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_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
52 #include <system_info.h>
53 #include <sound_manager.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 DEFAULT_PLAYBACK_RATE 1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93 (player->ini.http_use_file_buffer) && \
94 (player->http_file_buffering_path) && \
95 (strlen(player->http_file_buffering_path) > 0))
97 #define PLAYER_DISPLAY_MODE_DST_ROI 5
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
104 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
105 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
106 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
107 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
109 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
110 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | GLOBAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
133 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
135 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
138 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
142 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
146 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
150 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
151 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
152 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
153 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
158 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
159 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
160 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_release_misc(mm_player_t* player);
163 static void __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
166 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
167 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
168 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
169 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
170 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
171 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
172 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
173 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
176 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
177 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
178 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
179 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
180 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
181 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
182 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
183 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
184 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
185 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
186 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
187 static gpointer __mmplayer_next_play_thread(gpointer data);
188 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
190 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
191 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
192 static void __mmplayer_release_dump_list(GList *dump_list);
194 static int __gst_realize(mm_player_t* player);
195 static int __gst_unrealize(mm_player_t* player);
196 static int __gst_start(mm_player_t* player);
197 static int __gst_stop(mm_player_t* player);
198 static int __gst_pause(mm_player_t* player, gboolean async);
199 static int __gst_resume(mm_player_t* player, gboolean async);
200 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
201 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
202 gint64 cur, GstSeekType stop_type, gint64 stop);
203 static int __gst_pending_seek(mm_player_t* player);
205 static int __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
206 static int __gst_get_position(mm_player_t* player, int format, gint64 *position);
207 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
208 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
209 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
211 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
213 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
214 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
217 static gboolean __is_ms_buff_src(mm_player_t* player);
218 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
220 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
221 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
222 static int __mmplayer_start_streaming_ext(mm_player_t *player);
223 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
224 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
226 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
227 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
228 static void __mmplayer_check_pipeline(mm_player_t* player);
229 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
230 static void __mmplayer_deactivate_old_path(mm_player_t *player);
232 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
233 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
235 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
236 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
237 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
238 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
239 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
240 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
241 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
242 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
243 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
244 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
245 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
246 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
247 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
248 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
249 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
250 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
252 /*===========================================================================================
254 | FUNCTION DEFINITIONS |
256 ========================================================================================== */
260 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
264 count = gst_tag_list_get_tag_size(list, tag);
266 LOGD("count = %d", count);
268 for (i = 0; i < count; i++) {
271 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
272 if (!gst_tag_list_get_string_index(list, tag, i, &str))
273 g_assert_not_reached();
275 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
278 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
280 g_print(" : %s\n", str);
287 /* This function should be called after the pipeline goes PAUSED or higher
290 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
292 static gboolean has_duration = FALSE;
293 static gboolean has_video_attrs = FALSE;
294 static gboolean has_audio_attrs = FALSE;
295 static gboolean has_bitrate = FALSE;
296 gboolean missing_only = FALSE;
297 gboolean all = FALSE;
299 GstStructure* p = NULL;
300 MMHandleType attrs = 0;
306 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
308 /* check player state here */
309 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
310 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
311 /* give warning now only */
312 LOGW("be careful. content attributes may not available in this state ");
315 /* get content attribute first */
316 attrs = MMPLAYER_GET_ATTRS(player);
318 LOGE("cannot get content attribute");
322 /* get update flag */
324 if (flag & ATTR_MISSING_ONLY) {
326 LOGD("updating missed attr only");
329 if (flag & ATTR_ALL) {
331 has_duration = FALSE;
332 has_video_attrs = FALSE;
333 has_audio_attrs = FALSE;
336 LOGD("updating all attrs");
339 if (missing_only && all) {
340 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
341 missing_only = FALSE;
344 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
345 LOGD("try to update duration");
346 has_duration = FALSE;
348 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
349 player->duration = dur_nsec;
350 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
354 if (player->duration < 0) {
355 LOGW("duration is Non-Initialized !!!");
356 player->duration = 0;
359 /* update streaming service type */
360 player->streaming_type = __mmplayer_get_stream_service_type(player);
362 /* check duration is OK */
363 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
364 /* FIXIT : find another way to get duration here. */
365 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
369 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
370 /* update audio params
371 NOTE : We need original audio params and it can be only obtained from src pad of audio
372 decoder. Below code only valid when we are not using 'resampler' just before
375 LOGD("try to update audio attrs");
376 has_audio_attrs = FALSE;
378 if (player->pipeline->audiobin &&
379 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
380 GstCaps *caps_a = NULL;
382 gint samplerate = 0, channels = 0;
384 pad = gst_element_get_static_pad(
385 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
388 caps_a = gst_pad_get_current_caps(pad);
391 p = gst_caps_get_structure(caps_a, 0);
393 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
395 gst_structure_get_int(p, "rate", &samplerate);
396 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
398 gst_structure_get_int(p, "channels", &channels);
399 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
401 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
403 gst_caps_unref(caps_a);
406 has_audio_attrs = TRUE;
408 LOGW("not ready to get audio caps");
410 gst_object_unref(pad);
412 LOGW("failed to get pad from audiosink");
416 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
417 LOGD("try to update video attrs");
418 has_video_attrs = FALSE;
420 if (player->pipeline->videobin &&
421 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
422 GstCaps *caps_v = NULL;
427 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
429 caps_v = gst_pad_get_current_caps(pad);
431 /* Use v_stream_caps, if fail to get video_sink sink pad*/
432 if (!caps_v && player->v_stream_caps) {
433 caps_v = player->v_stream_caps;
434 gst_caps_ref(caps_v);
438 p = gst_caps_get_structure(caps_v, 0);
439 gst_structure_get_int(p, "width", &width);
440 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
442 gst_structure_get_int(p, "height", &height);
443 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
445 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
447 SECURE_LOGD("width : %d height : %d", width, height);
449 gst_caps_unref(caps_v);
453 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
454 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
457 has_video_attrs = TRUE;
459 LOGD("no negitiated caps from videosink");
460 gst_object_unref(pad);
463 LOGD("no videosink sink pad");
469 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
472 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
473 if (player->duration) {
474 guint64 data_size = 0;
476 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
477 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
479 if (stat(path, &sb) == 0)
480 data_size = (guint64)sb.st_size;
481 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
482 data_size = player->http_content_size;
484 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
488 guint64 msec_dur = 0;
490 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
492 bitrate = data_size * 8 * 1000 / msec_dur;
493 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
494 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
498 LOGD("player duration is less than 0");
502 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
503 if (player->total_bitrate) {
504 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
512 if (mmf_attrs_commit(attrs)) {
513 LOGE("failed to update attributes\n");
522 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
524 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
528 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
530 player->pipeline->mainbin &&
531 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
532 STREAMING_SERVICE_NONE);
534 /* streaming service type if streaming */
535 if (!MMPLAYER_IS_STREAMING(player))
536 return STREAMING_SERVICE_NONE;
538 if (MMPLAYER_IS_HTTP_STREAMING(player))
539 streaming_type = (player->duration == 0) ?
540 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
542 switch (streaming_type) {
543 case STREAMING_SERVICE_LIVE:
544 LOGD("it's live streaming");
546 case STREAMING_SERVICE_VOD:
547 LOGD("it's vod streaming");
550 LOGE("should not get here");
556 return streaming_type;
560 /* this function sets the player state and also report
561 * it to applicaton by calling callback function
564 __mmplayer_set_state(mm_player_t* player, int state)
566 MMMessageParamType msg = {0, };
567 gboolean post_bos = FALSE;
569 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
571 if (MMPLAYER_CURRENT_STATE(player) == state) {
572 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
573 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
574 return MM_ERROR_NONE;
577 /* update player states */
578 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
579 MMPLAYER_CURRENT_STATE(player) = state;
581 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
582 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
585 MMPLAYER_PRINT_STATE(player);
587 switch (MMPLAYER_CURRENT_STATE(player)) {
588 case MM_PLAYER_STATE_NULL:
589 case MM_PLAYER_STATE_READY:
592 case MM_PLAYER_STATE_PAUSED:
594 if (!player->sent_bos) {
595 /* rtsp case, get content attrs by GstMessage */
596 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
597 /* it's first time to update all content attrs. */
598 _mmplayer_update_content_attrs(player, ATTR_ALL);
602 /* add audio callback probe if condition is satisfied */
603 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
604 __mmplayer_configure_audio_callback(player);
606 /* FIXIT : handle return value */
610 case MM_PLAYER_STATE_PLAYING:
612 /* try to get content metadata */
613 if (!player->sent_bos) {
614 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
615 * c-api since c-api doesn't use _start() anymore. It may not work propery with
616 * legacy mmfw-player api */
617 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
620 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
621 if (!player->sent_bos)
622 __mmplayer_handle_missed_plugin(player);
625 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
626 /* initialize because auto resume is done well. */
627 player->resumed_by_rewind = FALSE;
628 player->playback_rate = 1.0;
631 if (!player->sent_bos) {
632 /* check audio codec field is set or not
633 * we can get it from typefinder or codec's caps.
635 gchar *audio_codec = NULL;
636 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
638 /* The codec format can't be sent for audio only case like amr, mid etc.
639 * Because, parser don't make related TAG.
640 * So, if it's not set yet, fill it with found data.
643 if (g_strrstr(player->type, "audio/midi"))
644 audio_codec = g_strdup("MIDI");
645 else if (g_strrstr(player->type, "audio/x-amr"))
646 audio_codec = g_strdup("AMR");
647 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
648 audio_codec = g_strdup("AAC");
650 audio_codec = g_strdup("unknown");
651 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
653 MMPLAYER_FREEIF(audio_codec);
654 if (mmf_attrs_commit(player->attrs))
655 LOGE("failed to update attributes\n");
657 LOGD("set audio codec type with caps\n");
665 case MM_PLAYER_STATE_NONE:
667 LOGW("invalid target state, there is nothing to do.\n");
672 /* post message to application */
673 if (MMPLAYER_TARGET_STATE(player) == state) {
674 /* fill the message with state of player */
675 msg.union_type = MM_MSG_UNION_STATE;
676 msg.state.previous = MMPLAYER_PREV_STATE(player);
677 msg.state.current = MMPLAYER_CURRENT_STATE(player);
679 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
681 /* state changed by resource callback */
682 if (player->interrupted_by_resource) {
683 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
684 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
685 } else { /* state changed by usecase */
686 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
689 LOGD("intermediate state, do nothing.\n");
690 MMPLAYER_PRINT_STATE(player);
691 return MM_ERROR_NONE;
695 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
696 player->sent_bos = TRUE;
699 return MM_ERROR_NONE;
702 static gpointer __mmplayer_next_play_thread(gpointer data)
704 mm_player_t* player = (mm_player_t*) data;
705 MMPlayerGstElement *mainbin = NULL;
707 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
709 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
710 while (!player->next_play_thread_exit) {
711 LOGD("next play thread started. waiting for signal.\n");
712 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
714 LOGD("reconfigure pipeline for gapless play.\n");
716 if (player->next_play_thread_exit) {
717 if (player->gapless.reconfigure) {
718 player->gapless.reconfigure = false;
719 MMPLAYER_PLAYBACK_UNLOCK(player);
721 LOGD("exiting gapless play thread\n");
725 mainbin = player->pipeline->mainbin;
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
731 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
733 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
735 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
741 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
743 MMHandleType attrs = 0;
744 guint64 data_size = 0;
749 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
751 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec); /* to update player->last_position */
753 attrs = MMPLAYER_GET_ATTRS(player);
755 LOGE("fail to get attributes.\n");
759 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
760 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
762 if (stat(path, &sb) == 0)
763 data_size = (guint64)sb.st_size;
764 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
765 data_size = player->http_content_size;
767 __mm_player_streaming_buffering(player->streamer,
770 player->last_position,
773 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
779 __mmplayer_handle_buffering_message(mm_player_t* player)
781 int ret = MM_ERROR_NONE;
782 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
783 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
784 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
785 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
787 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
788 LOGW("do nothing for buffering msg\n");
789 ret = MM_ERROR_PLAYER_INVALID_STATE;
793 prev_state = MMPLAYER_PREV_STATE(player);
794 current_state = MMPLAYER_CURRENT_STATE(player);
795 target_state = MMPLAYER_TARGET_STATE(player);
796 pending_state = MMPLAYER_PENDING_STATE(player);
798 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
799 MMPLAYER_STATE_GET_NAME(prev_state),
800 MMPLAYER_STATE_GET_NAME(current_state),
801 MMPLAYER_STATE_GET_NAME(pending_state),
802 MMPLAYER_STATE_GET_NAME(target_state),
803 player->streamer->is_buffering);
805 if (!player->streamer->is_buffering) {
806 /* NOTE : if buffering has done, player has to go to target state. */
807 switch (target_state) {
808 case MM_PLAYER_STATE_PAUSED:
810 switch (pending_state) {
811 case MM_PLAYER_STATE_PLAYING:
812 __gst_pause(player, TRUE);
815 case MM_PLAYER_STATE_PAUSED:
816 LOGD("player is already going to paused state, there is nothing to do.\n");
819 case MM_PLAYER_STATE_NONE:
820 case MM_PLAYER_STATE_NULL:
821 case MM_PLAYER_STATE_READY:
823 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
829 case MM_PLAYER_STATE_PLAYING:
831 switch (pending_state) {
832 case MM_PLAYER_STATE_NONE:
834 if (current_state != MM_PLAYER_STATE_PLAYING)
835 __gst_resume(player, TRUE);
839 case MM_PLAYER_STATE_PAUSED:
840 /* NOTE: It should be worked as asynchronously.
841 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
843 if (current_state == MM_PLAYER_STATE_PLAYING) {
844 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
845 * The current state should be changed to paused purposely to prevent state conflict.
847 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
849 __gst_resume(player, TRUE);
852 case MM_PLAYER_STATE_PLAYING:
853 LOGD("player is already going to playing state, there is nothing to do.\n");
856 case MM_PLAYER_STATE_NULL:
857 case MM_PLAYER_STATE_READY:
859 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
865 case MM_PLAYER_STATE_NULL:
866 case MM_PLAYER_STATE_READY:
867 case MM_PLAYER_STATE_NONE:
869 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
873 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
874 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
876 switch (pending_state) {
877 case MM_PLAYER_STATE_NONE:
879 if (current_state != MM_PLAYER_STATE_PAUSED) {
880 /* rtsp streaming pause makes rtsp server stop sending data. */
881 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
882 LOGD("set pause state during buffering\n");
883 __gst_pause(player, TRUE);
889 case MM_PLAYER_STATE_PLAYING:
890 /* rtsp streaming pause makes rtsp server stop sending data. */
891 if (!MMPLAYER_IS_RTSP_STREAMING(player))
892 __gst_pause(player, TRUE);
895 case MM_PLAYER_STATE_PAUSED:
898 case MM_PLAYER_STATE_NULL:
899 case MM_PLAYER_STATE_READY:
901 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
911 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
913 MMPlayerGstElement *textbin;
916 MMPLAYER_RETURN_IF_FAIL(player &&
918 player->pipeline->textbin);
920 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
922 textbin = player->pipeline->textbin;
925 LOGD("Drop subtitle text after getting EOS\n");
927 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
928 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
930 player->is_subtitle_force_drop = TRUE;
932 if (player->is_subtitle_force_drop == TRUE) {
933 LOGD("Enable subtitle data path without drop\n");
935 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
936 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
938 LOGD("non-connected with external display");
940 player->is_subtitle_force_drop = FALSE;
946 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
948 VariantData *var_info = NULL;
949 g_return_val_if_fail(self != NULL, NULL);
951 var_info = g_new0(VariantData, 1);
952 if (!var_info) return NULL;
953 var_info->bandwidth = self->bandwidth;
954 var_info->width = self->width;
955 var_info->height = self->height;
959 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
961 mm_player_t* player = (mm_player_t*)hplayer;
962 GstMessage *msg = NULL;
963 GQueue *queue = NULL;
966 MMPLAYER_RETURN_IF_FAIL(player);
968 /* disconnecting bus watch */
969 if (player->bus_watcher)
970 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
971 player->bus_watcher = 0;
973 /* destroy the gst bus msg thread */
974 if (player->bus_msg_thread) {
975 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
976 player->bus_msg_thread_exit = TRUE;
977 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
978 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
980 LOGD("gst bus msg thread exit.");
981 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
982 player->bus_msg_thread = NULL;
984 g_mutex_clear(&player->bus_msg_thread_mutex);
985 g_cond_clear(&player->bus_msg_thread_cond);
988 g_mutex_lock(&player->bus_msg_q_lock);
989 queue = player->bus_msg_q;
990 while (!g_queue_is_empty(queue)) {
991 msg = (GstMessage *)g_queue_pop_head(queue);
992 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
993 gst_message_unref(msg);
995 g_mutex_unlock(&player->bus_msg_q_lock);
1000 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1002 mm_player_t *player = (mm_player_t *) data;
1004 g_return_val_if_fail(player, FALSE);
1005 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1007 gst_message_ref(msg);
1009 g_mutex_lock(&player->bus_msg_q_lock);
1010 g_queue_push_tail(player->bus_msg_q, msg);
1011 g_mutex_unlock(&player->bus_msg_q_lock);
1013 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1014 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1015 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1019 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1021 mm_player_t *player = (mm_player_t*)(data);
1022 GstMessage *msg = NULL;
1026 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1028 player->pipeline->mainbin &&
1029 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1032 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1034 LOGE("cannot get BUS from the pipeline");
1038 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1040 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1041 while (!player->bus_msg_thread_exit) {
1042 g_mutex_lock(&player->bus_msg_q_lock);
1043 msg = g_queue_pop_head(player->bus_msg_q);
1044 g_mutex_unlock(&player->bus_msg_q_lock);
1046 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1049 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1050 /* handle the gst msg */
1051 __mmplayer_gst_callback(msg, player);
1052 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1053 gst_message_unref(msg);
1056 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1057 gst_object_unref(GST_OBJECT(bus));
1064 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1066 mm_player_t* player = (mm_player_t*)(data);
1067 static gboolean async_done = FALSE;
1069 MMPLAYER_RETURN_IF_FAIL(player);
1070 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1072 switch (GST_MESSAGE_TYPE(msg)) {
1073 case GST_MESSAGE_UNKNOWN:
1074 LOGD("unknown message received\n");
1077 case GST_MESSAGE_EOS:
1079 MMHandleType attrs = 0;
1082 LOGD("GST_MESSAGE_EOS received\n");
1084 /* NOTE : EOS event is comming multiple time. watch out it */
1085 /* check state. we only process EOS when pipeline state goes to PLAYING */
1086 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1087 LOGD("EOS received on non-playing state. ignoring it\n");
1091 if (player->pipeline) {
1092 if (player->pipeline->textbin)
1093 __mmplayer_drop_subtitle(player, TRUE);
1095 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1098 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1100 LOGD("release audio callback\n");
1102 /* release audio callback */
1103 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1104 player->audio_cb_probe_id = 0;
1105 /* audio callback should be free because it can be called even though probe remove.*/
1106 player->audio_stream_cb = NULL;
1107 player->audio_stream_cb_user_param = NULL;
1111 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1112 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1114 /* rewind if repeat count is greater then zero */
1115 /* get play count */
1116 attrs = MMPLAYER_GET_ATTRS(player);
1119 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1121 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1123 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1124 if (player->playback_rate < 0.0) {
1125 player->resumed_by_rewind = TRUE;
1126 _mmplayer_set_mute((MMHandleType)player, 0);
1127 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1130 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1133 player->sent_bos = FALSE;
1135 /* not posting eos when repeating */
1140 if (player->pipeline)
1141 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1143 /* post eos message to application */
1144 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1146 /* reset last position */
1147 player->last_position = 0;
1151 case GST_MESSAGE_ERROR:
1153 GError *error = NULL;
1154 gchar* debug = NULL;
1156 /* generating debug info before returning error */
1157 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1159 /* get error code */
1160 gst_message_parse_error(msg, &error, &debug);
1162 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1163 /* Note : the streaming error from the streaming source is handled
1164 * using __mmplayer_handle_streaming_error.
1166 __mmplayer_handle_streaming_error(player, msg);
1168 /* dump state of all element */
1169 __mmplayer_dump_pipeline_state(player);
1171 /* traslate gst error code to msl error code. then post it
1172 * to application if needed
1174 __mmplayer_handle_gst_error(player, msg, error);
1177 LOGE("error debug : %s", debug);
1180 if (MMPLAYER_IS_HTTP_PD(player))
1181 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1183 MMPLAYER_FREEIF(debug);
1184 g_error_free(error);
1188 case GST_MESSAGE_WARNING:
1191 GError* error = NULL;
1193 gst_message_parse_warning(msg, &error, &debug);
1195 LOGD("warning : %s\n", error->message);
1196 LOGD("debug : %s\n", debug);
1198 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1200 MMPLAYER_FREEIF(debug);
1201 g_error_free(error);
1205 case GST_MESSAGE_TAG:
1207 LOGD("GST_MESSAGE_TAG\n");
1208 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1209 LOGW("failed to extract tags from gstmessage\n");
1213 case GST_MESSAGE_BUFFERING:
1215 MMMessageParamType msg_param = {0, };
1216 int bRet = MM_ERROR_NONE;
1218 if (!(player->pipeline && player->pipeline->mainbin)) {
1219 LOGE("player pipeline handle is null");
1223 if (!MMPLAYER_IS_STREAMING(player))
1226 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1227 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1228 /* skip the playback control by buffering msg while user request is handled. */
1231 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1233 gst_message_parse_buffering(msg, &per);
1234 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1236 msg_param.connection.buffering = per;
1237 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1241 MMPLAYER_CMD_LOCK(player);
1244 /* ignore the prev buffering message */
1245 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1246 && (player->streamer->is_buffering_done == TRUE)) {
1247 gint buffer_percent = 0;
1249 gst_message_parse_buffering(msg, &buffer_percent);
1251 if (buffer_percent == MAX_BUFFER_PERCENT) {
1252 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1253 player->streamer->is_buffering_done = FALSE;
1255 MMPLAYER_CMD_UNLOCK(player);
1259 __mmplayer_update_buffer_setting(player, msg);
1261 bRet = __mmplayer_handle_buffering_message(player);
1263 if (bRet == MM_ERROR_NONE) {
1264 msg_param.connection.buffering = player->streamer->buffering_percent;
1265 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1267 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1268 player->pending_resume &&
1269 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1271 player->is_external_subtitle_added_now = FALSE;
1272 player->pending_resume = FALSE;
1273 _mmplayer_resume((MMHandleType)player);
1276 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1277 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1279 if (player->doing_seek) {
1280 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1281 player->doing_seek = FALSE;
1282 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1283 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1288 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1289 if (!player->streamer) {
1290 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1291 MMPLAYER_CMD_UNLOCK(player);
1295 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1297 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1298 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1300 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1301 msg_param.connection.buffering = player->streamer->buffering_percent;
1302 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1304 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1307 msg_param.connection.buffering = player->streamer->buffering_percent;
1308 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1311 MMPLAYER_CMD_UNLOCK(player);
1315 case GST_MESSAGE_STATE_CHANGED:
1317 MMPlayerGstElement *mainbin;
1318 const GValue *voldstate, *vnewstate, *vpending;
1319 GstState oldstate = GST_STATE_NULL;
1320 GstState newstate = GST_STATE_NULL;
1321 GstState pending = GST_STATE_NULL;
1323 if (!(player->pipeline && player->pipeline->mainbin)) {
1324 LOGE("player pipeline handle is null");
1328 mainbin = player->pipeline->mainbin;
1330 /* we only handle messages from pipeline */
1331 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1334 /* get state info from msg */
1335 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1336 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1337 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1339 if (!voldstate || !vnewstate) {
1340 LOGE("received msg has wrong format.");
1344 oldstate = (GstState)voldstate->data[0].v_int;
1345 newstate = (GstState)vnewstate->data[0].v_int;
1347 pending = (GstState)vpending->data[0].v_int;
1349 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1350 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1351 gst_element_state_get_name((GstState)oldstate),
1352 gst_element_state_get_name((GstState)newstate),
1353 gst_element_state_get_name((GstState)pending));
1355 if (newstate == GST_STATE_PLAYING) {
1356 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1358 int retVal = MM_ERROR_NONE;
1359 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1361 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1363 if (MM_ERROR_NONE != retVal)
1364 LOGE("failed to seek pending postion. just keep staying current position.\n");
1366 player->pending_seek.is_pending = FALSE;
1370 if (oldstate == newstate) {
1371 LOGD("pipeline reports state transition to old state");
1376 case GST_STATE_VOID_PENDING:
1379 case GST_STATE_NULL:
1382 case GST_STATE_READY:
1385 case GST_STATE_PAUSED:
1387 gboolean prepare_async = FALSE;
1389 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1390 __mmplayer_configure_audio_callback(player);
1392 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1393 // managed prepare async case
1394 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1395 LOGD("checking prepare mode for async transition - %d", prepare_async);
1398 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1399 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1401 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1402 __mm_player_streaming_set_content_bitrate(player->streamer,
1403 player->total_maximum_bitrate, player->total_bitrate);
1405 if (player->pending_seek.is_pending) {
1406 LOGW("trying to do pending seek");
1407 MMPLAYER_CMD_LOCK(player);
1408 __gst_pending_seek(player);
1409 MMPLAYER_CMD_UNLOCK(player);
1415 case GST_STATE_PLAYING:
1417 if (MMPLAYER_IS_STREAMING(player)) {
1418 // managed prepare async case when buffering is completed
1419 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1420 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1421 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1422 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1424 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1426 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1427 if (player->streamer->buffering_percent < 100) {
1429 MMMessageParamType msg_param = {0, };
1430 LOGW("Posting Buffering Completed Message to Application !!!");
1432 msg_param.connection.buffering = 100;
1433 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1438 if (player->gapless.stream_changed) {
1439 _mmplayer_update_content_attrs(player, ATTR_ALL);
1440 player->gapless.stream_changed = FALSE;
1443 if (player->doing_seek && async_done) {
1444 player->doing_seek = FALSE;
1446 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1457 case GST_MESSAGE_CLOCK_LOST:
1459 GstClock *clock = NULL;
1460 gboolean need_new_clock = FALSE;
1462 gst_message_parse_clock_lost(msg, &clock);
1463 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1465 if (!player->videodec_linked)
1466 need_new_clock = TRUE;
1467 else if (!player->ini.use_system_clock)
1468 need_new_clock = TRUE;
1470 if (need_new_clock) {
1471 LOGD("Provide clock is TRUE, do pause->resume\n");
1472 __gst_pause(player, FALSE);
1473 __gst_resume(player, FALSE);
1478 case GST_MESSAGE_NEW_CLOCK:
1480 GstClock *clock = NULL;
1481 gst_message_parse_new_clock(msg, &clock);
1482 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1486 case GST_MESSAGE_ELEMENT:
1488 const gchar *structure_name;
1489 gint count = 0, idx = 0;
1490 MMHandleType attrs = 0;
1492 attrs = MMPLAYER_GET_ATTRS(player);
1494 LOGE("cannot get content attribute");
1498 if (gst_message_get_structure(msg) == NULL)
1501 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1502 if (!structure_name)
1505 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1507 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1508 const GValue *var_info = NULL;
1510 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1511 if (var_info != NULL) {
1512 if (player->adaptive_info.var_list)
1513 g_list_free_full(player->adaptive_info.var_list, g_free);
1515 /* share addr or copy the list */
1516 player->adaptive_info.var_list =
1517 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1519 count = g_list_length(player->adaptive_info.var_list);
1521 VariantData *temp = NULL;
1523 /* print out for debug */
1524 LOGD("num of variant_info %d", count);
1525 for (idx = 0; idx < count; idx++) {
1526 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1528 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1534 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1535 gint num_buffers = 0;
1536 gint extra_num_buffers = 0;
1538 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1539 player->video_num_buffers = num_buffers;
1540 LOGD("video_num_buffers : %d", player->video_num_buffers);
1543 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1544 player->video_extra_num_buffers = extra_num_buffers;
1545 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1550 if (!strcmp(structure_name, "Language_list")) {
1551 const GValue *lang_list = NULL;
1552 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1553 if (lang_list != NULL) {
1554 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1556 LOGD("Total audio tracks(from parser) = %d \n", count);
1560 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1561 const GValue *lang_list = NULL;
1562 MMPlayerLangStruct *temp = NULL;
1564 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1565 if (lang_list != NULL) {
1566 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1568 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1569 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1570 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1571 if (mmf_attrs_commit(attrs))
1572 LOGE("failed to commit.\n");
1573 LOGD("Total subtitle tracks = %d \n", count);
1576 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1578 LOGD("value of lang_key is %s and lang_code is %s",
1579 temp->language_key, temp->language_code);
1582 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1583 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1588 /* custom message */
1589 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1590 MMMessageParamType msg_param = {0,};
1591 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1592 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1595 /* custom message for RTSP attribute :
1596 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1597 sdp which has contents info is received when rtsp connection is opened.
1598 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1599 if (!strcmp(structure_name, "rtspsrc_properties")) {
1601 gchar *audio_codec = NULL;
1602 gchar *video_codec = NULL;
1603 gchar *video_frame_size = NULL;
1605 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1606 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1607 player->streaming_type = __mmplayer_get_stream_service_type(player);
1609 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1610 LOGD("rtsp_audio_codec : %s", audio_codec);
1612 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1614 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1615 LOGD("rtsp_video_codec : %s", video_codec);
1617 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1619 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1620 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1621 if (video_frame_size) {
1623 char *seperator = strchr(video_frame_size, '-');
1626 char video_width[10] = {0,};
1627 int frame_size_len = strlen(video_frame_size);
1628 int separtor_len = strlen(seperator);
1630 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1631 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1634 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1638 if (mmf_attrs_commit(attrs))
1639 LOGE("failed to commit.\n");
1644 case GST_MESSAGE_DURATION_CHANGED:
1646 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1647 if (!__mmplayer_gst_handle_duration(player, msg))
1648 LOGW("failed to update duration");
1653 case GST_MESSAGE_ASYNC_START:
1654 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1657 case GST_MESSAGE_ASYNC_DONE:
1659 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1661 /* we only handle messages from pipeline */
1662 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1665 if (player->doing_seek) {
1666 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1667 player->doing_seek = FALSE;
1668 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1669 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1670 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1671 (player->streamer) &&
1672 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1673 (player->streamer->is_buffering == FALSE)) {
1674 GstQuery *query = NULL;
1675 gboolean busy = FALSE;
1678 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1679 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1680 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1681 gst_query_parse_buffering_percent(query, &busy, &percent);
1682 gst_query_unref(query);
1684 LOGD("buffered percent(%s): %d\n",
1685 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1688 if (percent >= 100) {
1689 player->streamer->is_buffering = FALSE;
1690 __mmplayer_handle_buffering_message(player);
1700 #if 0 /* delete unnecessary logs */
1701 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1702 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1703 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1704 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1705 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1706 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1707 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1708 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1709 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1710 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1711 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1712 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1713 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1714 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1715 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1722 /* should not call 'gst_message_unref(msg)' */
1727 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1733 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1734 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1736 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1737 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1738 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1740 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1741 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1742 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1745 /* handling audio clip which has vbr. means duration is keep changing */
1746 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1753 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1754 mm_player_spherical_metadata_t *metadata) {
1755 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1756 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1757 gst_tag_list_get_string(tags, "stitching_software",
1758 &metadata->stitching_software);
1759 gst_tag_list_get_string(tags, "projection_type",
1760 &metadata->projection_type_string);
1761 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1762 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1763 gst_tag_list_get_int(tags, "init_view_heading",
1764 &metadata->init_view_heading);
1765 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1766 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1767 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1768 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1769 &metadata->full_pano_width_pixels);
1770 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1771 &metadata->full_pano_height_pixels);
1772 gst_tag_list_get_int(tags, "cropped_area_image_width",
1773 &metadata->cropped_area_image_width);
1774 gst_tag_list_get_int(tags, "cropped_area_image_height",
1775 &metadata->cropped_area_image_height);
1776 gst_tag_list_get_int(tags, "cropped_area_left",
1777 &metadata->cropped_area_left);
1778 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1779 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1780 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1781 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1785 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1788 /* macro for better code readability */
1789 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1790 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1791 if (string != NULL) { \
1792 SECURE_LOGD("update tag string : %s\n", string); \
1793 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1794 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1795 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1796 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1797 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1798 g_free(new_string); \
1799 new_string = NULL; \
1801 mm_attrs_set_string_by_name(attribute, playertag, string); \
1808 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1810 GstSample *sample = NULL;\
1811 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1812 GstMapInfo info = GST_MAP_INFO_INIT;\
1813 buffer = gst_sample_get_buffer(sample);\
1814 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1815 LOGD("failed to get image data from tag");\
1816 gst_sample_unref(sample);\
1819 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1820 MMPLAYER_FREEIF(player->album_art);\
1821 player->album_art = (gchar *)g_malloc(info.size);\
1822 if (player->album_art) {\
1823 memcpy(player->album_art, info.data, info.size);\
1824 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1825 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1826 msg_param.data = (void *)player->album_art;\
1827 msg_param.size = info.size;\
1828 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1829 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1832 gst_buffer_unmap(buffer, &info);\
1833 gst_sample_unref(sample);\
1837 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1839 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1842 gchar *tag_list_str = NULL; \
1843 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1844 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1845 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1846 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1847 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1849 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1850 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1851 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1852 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1853 player->bitrate[track_type] = v_uint; \
1854 player->total_bitrate = 0; \
1855 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1856 player->total_bitrate += player->bitrate[i]; \
1857 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1858 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1859 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1860 player->maximum_bitrate[track_type] = v_uint; \
1861 player->total_maximum_bitrate = 0; \
1862 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1863 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1864 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1865 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1867 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1870 g_free(tag_list_str); \
1875 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1876 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1877 if (date != NULL) {\
1878 string = g_strdup_printf("%d", g_date_get_year(date));\
1879 mm_attrs_set_string_by_name(attribute, playertag, string);\
1880 SECURE_LOGD("metainfo year : %s\n", string);\
1881 MMPLAYER_FREEIF(string);\
1886 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1887 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1888 if (datetime != NULL) {\
1889 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1890 mm_attrs_set_string_by_name(attribute, playertag, string);\
1891 SECURE_LOGD("metainfo year : %s\n", string);\
1892 MMPLAYER_FREEIF(string);\
1893 gst_date_time_unref(datetime);\
1897 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1898 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1900 /* FIXIT : don't know how to store date */\
1906 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1907 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1909 /* FIXIT : don't know how to store date */\
1915 /* function start */
1916 GstTagList* tag_list = NULL;
1918 MMHandleType attrs = 0;
1920 char *string = NULL;
1923 GstDateTime *datetime = NULL;
1925 GstBuffer *buffer = NULL;
1927 MMMessageParamType msg_param = {0, };
1929 /* currently not used. but those are needed for above macro */
1930 //guint64 v_uint64 = 0;
1931 //gdouble v_double = 0;
1933 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1935 attrs = MMPLAYER_GET_ATTRS(player);
1937 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1939 /* get tag list from gst message */
1940 gst_message_parse_tag(msg, &tag_list);
1942 /* store tags to player attributes */
1943 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1944 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1945 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1946 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1947 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1948 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1949 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1950 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1951 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1952 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1953 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1954 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1955 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1956 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1958 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1959 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1960 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1961 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1962 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1963 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1964 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1965 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1966 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1967 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1969 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1970 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1971 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1972 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1973 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1974 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1975 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1976 MMPLAYER_UPDATE_TAG_LOCK(player);
1977 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1978 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1979 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1980 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1981 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1982 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1983 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1984 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1985 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1991 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1993 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1994 if (player->video360_metadata.is_spherical == -1) {
1995 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1996 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1997 player->video360_metadata.is_spherical);
1998 if (player->video360_metadata.is_spherical == 1) {
1999 LOGD("This is spherical content for 360 playback.");
2000 player->is_content_spherical = TRUE;
2002 LOGD("This is not spherical content");
2003 player->is_content_spherical = FALSE;
2006 if (player->video360_metadata.projection_type_string) {
2007 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2008 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2010 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2011 player->is_content_spherical = player->is_video360_enabled = FALSE;
2015 if (player->video360_metadata.stereo_mode_string) {
2016 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2017 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2018 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2019 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2020 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2021 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2023 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2024 player->is_content_spherical = player->is_video360_enabled = FALSE;
2030 if (mmf_attrs_commit(attrs))
2031 LOGE("failed to commit.\n");
2033 gst_tag_list_free(tag_list);
2039 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2041 mm_player_t* player = (mm_player_t*) data;
2045 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2046 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2047 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2048 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2050 * [1] audio and video will be dumped with filesink.
2051 * [2] autoplugging is done by just using pad caps.
2052 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2053 * and the video will be dumped via filesink.
2055 if (player->num_dynamic_pad == 0) {
2056 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2058 if (!__mmplayer_gst_remove_fakesink(player,
2059 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2060 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2061 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2062 * source element are not same. To overcome this situation, this function will called
2063 * several places and several times. Therefore, this is not an error case.
2068 /* create dot before error-return. for debugging */
2069 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2071 player->no_more_pad = TRUE;
2077 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2079 GstElement* parent = NULL;
2081 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2083 /* if we have no fakesink. this meas we are using decodebin which doesn'
2084 t need to add extra fakesink */
2085 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2088 MMPLAYER_FSINK_LOCK(player);
2093 /* get parent of fakesink */
2094 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2096 LOGD("fakesink already removed\n");
2100 gst_element_set_locked_state(fakesink->gst, TRUE);
2102 /* setting the state to NULL never returns async
2103 * so no need to wait for completion of state transiton
2105 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2106 LOGE("fakesink state change failure!\n");
2107 /* FIXIT : should I return here? or try to proceed to next? */
2110 /* remove fakesink from it's parent */
2111 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2112 LOGE("failed to remove fakesink\n");
2114 gst_object_unref(parent);
2119 gst_object_unref(parent);
2121 LOGD("state-holder removed\n");
2123 gst_element_set_locked_state(fakesink->gst, FALSE);
2125 MMPLAYER_FSINK_UNLOCK(player);
2130 gst_element_set_locked_state(fakesink->gst, FALSE);
2132 MMPLAYER_FSINK_UNLOCK(player);
2138 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2140 GstPad *sinkpad = NULL;
2141 GstCaps* caps = NULL;
2142 GstElement* new_element = NULL;
2143 GstStructure* str = NULL;
2144 const gchar* name = NULL;
2146 mm_player_t* player = (mm_player_t*) data;
2150 MMPLAYER_RETURN_IF_FAIL(element && pad);
2151 MMPLAYER_RETURN_IF_FAIL(player &&
2153 player->pipeline->mainbin);
2156 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2157 * num_dynamic_pad will decreased after creating a sinkbin.
2159 player->num_dynamic_pad++;
2160 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2162 caps = gst_pad_query_caps(pad, NULL);
2164 MMPLAYER_CHECK_NULL(caps);
2166 /* clear previous result*/
2167 player->have_dynamic_pad = FALSE;
2169 str = gst_caps_get_structure(caps, 0);
2172 LOGE("cannot get structure from caps.\n");
2176 name = gst_structure_get_name(str);
2178 LOGE("cannot get mimetype from structure.\n");
2182 if (strstr(name, "video")) {
2184 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2186 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2187 if (player->v_stream_caps) {
2188 gst_caps_unref(player->v_stream_caps);
2189 player->v_stream_caps = NULL;
2192 new_element = gst_element_factory_make("fakesink", NULL);
2193 player->num_dynamic_pad--;
2198 /* clear previous result*/
2199 player->have_dynamic_pad = FALSE;
2201 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2202 LOGE("failed to autoplug for caps");
2206 /* check if there's dynamic pad*/
2207 if (player->have_dynamic_pad) {
2208 LOGE("using pad caps assums there's no dynamic pad !\n");
2212 gst_caps_unref(caps);
2217 /* excute new_element if created*/
2219 LOGD("adding new element to pipeline\n");
2221 /* set state to READY before add to bin */
2222 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2224 /* add new element to the pipeline */
2225 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2226 LOGE("failed to add autoplug element to bin\n");
2230 /* get pad from element */
2231 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2233 LOGE("failed to get sinkpad from autoplug element\n");
2238 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2239 LOGE("failed to link autoplug element\n");
2243 gst_object_unref(sinkpad);
2246 /* run. setting PLAYING here since streamming source is live source */
2247 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2251 gst_caps_unref(caps);
2257 STATE_CHANGE_FAILED:
2259 /* FIXIT : take care if new_element has already added to pipeline */
2261 gst_object_unref(GST_OBJECT(new_element));
2264 gst_object_unref(GST_OBJECT(sinkpad));
2267 gst_caps_unref(caps);
2269 /* FIXIT : how to inform this error to MSL ????? */
2270 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2271 * then post an error to application
2275 static GstPadProbeReturn
2276 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2278 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2279 return GST_PAD_PROBE_OK;
2282 static GstPadProbeReturn
2283 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2285 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2286 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2287 mm_player_t* player = (mm_player_t*)data;
2288 GstCaps* caps = NULL;
2289 GstStructure* str = NULL;
2290 const gchar* name = NULL;
2291 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2294 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2295 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2296 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2297 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2298 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2300 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2301 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2305 caps = gst_pad_query_caps(pad, NULL);
2307 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2311 str = gst_caps_get_structure(caps, 0);
2313 LOGE("failed to get structure from caps");
2317 name = gst_structure_get_name(str);
2319 LOGE("failed to get name from str");
2323 if (strstr(name, "audio")) {
2324 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2325 } else if (strstr(name, "video")) {
2326 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2328 /* text track is not supportable */
2329 LOGE("invalid name %s", name);
2333 switch (GST_EVENT_TYPE(event)) {
2336 /* in case of gapless, drop eos event not to send it to sink */
2337 if (player->gapless.reconfigure && !player->msg_posted) {
2338 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2339 ret = GST_PAD_PROBE_DROP;
2343 case GST_EVENT_STREAM_START:
2345 gint64 stop_running_time = 0;
2346 gint64 position_running_time = 0;
2347 gint64 position = 0;
2350 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2351 if ((player->gapless.update_segment[idx] == TRUE) ||
2352 !(player->selector[idx].event_probe_id)) {
2353 /* LOGW("[%d] skip", idx); */
2357 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2359 gst_segment_to_running_time(&player->gapless.segment[idx],
2360 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2361 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2363 gst_segment_to_running_time(&player->gapless.segment[idx],
2364 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2366 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2368 gst_segment_to_running_time(&player->gapless.segment[idx],
2369 GST_FORMAT_TIME, player->duration);
2372 position_running_time =
2373 gst_segment_to_running_time(&player->gapless.segment[idx],
2374 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2376 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2377 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2379 GST_TIME_ARGS(stop_running_time),
2380 GST_TIME_ARGS(position_running_time),
2381 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2382 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2384 position_running_time = MAX(position_running_time, stop_running_time);
2385 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2386 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2387 position_running_time = MAX(0, position_running_time);
2388 position = MAX(position, position_running_time);
2391 if (position != 0) {
2392 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2393 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2394 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2396 player->gapless.start_time[stream_type] += position;
2400 case GST_EVENT_FLUSH_STOP:
2402 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2403 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2404 player->gapless.start_time[stream_type] = 0;
2407 case GST_EVENT_SEGMENT:
2412 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2413 gst_event_copy_segment(event, &segment);
2415 if (segment.format == GST_FORMAT_TIME) {
2416 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2417 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2418 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2419 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2420 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2421 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2423 /* keep the all the segment ev to cover the seeking */
2424 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2425 player->gapless.update_segment[stream_type] = TRUE;
2427 if (!player->gapless.running)
2430 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2432 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2434 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2435 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2436 gst_event_unref(event);
2437 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2443 gdouble proportion = 0.0;
2444 GstClockTimeDiff diff = 0;
2445 GstClockTime timestamp = 0;
2446 gint64 running_time_diff = -1;
2447 GstQOSType type = 0;
2448 GstEvent *tmpev = NULL;
2450 running_time_diff = player->gapless.segment[stream_type].base;
2452 if (running_time_diff <= 0) /* don't need to adjust */
2455 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2456 gst_event_unref(event);
2458 if (timestamp < running_time_diff) {
2459 LOGW("QOS event from previous group");
2460 ret = GST_PAD_PROBE_DROP;
2464 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2465 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2466 stream_type, GST_TIME_ARGS(timestamp),
2467 GST_TIME_ARGS(running_time_diff),
2468 GST_TIME_ARGS(timestamp - running_time_diff));
2470 timestamp -= running_time_diff;
2472 /* That case is invalid for QoS events */
2473 if (diff < 0 && -diff > timestamp) {
2474 LOGW("QOS event from previous group");
2475 ret = GST_PAD_PROBE_DROP;
2479 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2480 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2490 gst_caps_unref(caps);
2495 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2497 mm_player_t* player = NULL;
2498 GstElement* pipeline = NULL;
2499 GstElement* selector = NULL;
2500 GstElement* fakesink = NULL;
2501 GstCaps* caps = NULL;
2502 GstStructure* str = NULL;
2503 const gchar* name = NULL;
2504 GstPad* sinkpad = NULL;
2505 GstPad* srcpad = NULL;
2506 gboolean first_track = FALSE;
2508 enum MainElementID elemId = MMPLAYER_M_NUM;
2509 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2512 player = (mm_player_t*)data;
2514 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2517 //LOGD("pad-added signal handling\n");
2519 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2521 /* get mimetype from caps */
2522 caps = gst_pad_query_caps(pad, NULL);
2524 LOGE("cannot get caps from pad.\n");
2528 str = gst_caps_get_structure(caps, 0);
2530 LOGE("cannot get structure from caps.\n");
2534 name = gst_structure_get_name(str);
2536 LOGE("cannot get mimetype from structure.\n");
2540 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2541 //LOGD("detected mimetype : %s\n", name);
2543 if (strstr(name, "video")) {
2546 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2547 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2549 /* don't make video because of not required, and not support multiple track */
2550 if (stype == MM_DISPLAY_SURFACE_NULL) {
2551 LOGD("no video sink by null surface");
2553 gchar *caps_str = gst_caps_to_string(caps);
2554 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2555 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2556 player->set_mode.video_zc = TRUE;
2558 MMPLAYER_FREEIF(caps_str);
2560 if (player->v_stream_caps) {
2561 gst_caps_unref(player->v_stream_caps);
2562 player->v_stream_caps = NULL;
2565 LOGD("create fakesink instead of videobin");
2568 fakesink = gst_element_factory_make("fakesink", NULL);
2569 if (fakesink == NULL) {
2570 LOGE("ERROR : fakesink create error\n");
2574 if (player->ini.set_dump_element_flag)
2575 __mmplayer_add_dump_buffer_probe(player, fakesink);
2577 player->video_fakesink = fakesink;
2579 /* store it as it's sink element */
2580 __mmplayer_add_sink(player, player->video_fakesink);
2582 gst_bin_add(GST_BIN(pipeline), fakesink);
2585 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2587 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2588 LOGW("failed to link fakesink\n");
2589 gst_object_unref(GST_OBJECT(fakesink));
2593 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2594 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2595 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2598 if (player->set_mode.media_packet_video_stream) {
2599 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2601 MMPLAYER_SIGNAL_CONNECT(player,
2603 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2605 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2608 MMPLAYER_SIGNAL_CONNECT(player,
2610 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2612 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2616 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2617 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2621 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2622 __mmplayer_gst_decode_callback(elem, pad, player);
2626 LOGD("video selector \n");
2627 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2628 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2630 if (strstr(name, "audio")) {
2631 gint samplerate = 0;
2634 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2635 __mmplayer_gst_decode_callback(elem, pad, player);
2639 LOGD("audio selector \n");
2640 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2641 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2643 gst_structure_get_int(str, "rate", &samplerate);
2644 gst_structure_get_int(str, "channels", &channels);
2646 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2648 fakesink = gst_element_factory_make("fakesink", NULL);
2649 if (fakesink == NULL) {
2650 LOGE("ERROR : fakesink create error\n");
2654 gst_bin_add(GST_BIN(pipeline), fakesink);
2657 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2659 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2660 LOGW("failed to link fakesink\n");
2661 gst_object_unref(GST_OBJECT(fakesink));
2665 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2666 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2667 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2671 } else if (strstr(name, "text")) {
2672 LOGD("text selector \n");
2673 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2674 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2676 LOGE("wrong elem id \n");
2681 selector = player->pipeline->mainbin[elemId].gst;
2682 if (selector == NULL) {
2683 selector = gst_element_factory_make("input-selector", NULL);
2684 LOGD("Creating input-selector\n");
2685 if (selector == NULL) {
2686 LOGE("ERROR : input-selector create error\n");
2689 g_object_set(selector, "sync-streams", TRUE, NULL);
2691 player->pipeline->mainbin[elemId].id = elemId;
2692 player->pipeline->mainbin[elemId].gst = selector;
2695 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2697 srcpad = gst_element_get_static_pad(selector, "src");
2699 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2700 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2701 __mmplayer_gst_selector_blocked, NULL, NULL);
2702 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2703 __mmplayer_gst_selector_event_probe, player, NULL);
2705 gst_element_set_state(selector, GST_STATE_PAUSED);
2706 gst_bin_add(GST_BIN(pipeline), selector);
2708 LOGD("input-selector is already created.\n");
2711 LOGD("Calling request pad with selector %p \n", selector);
2712 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2714 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2716 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2717 LOGW("failed to link selector\n");
2718 gst_object_unref(GST_OBJECT(selector));
2723 LOGD("this is first track --> active track \n");
2724 g_object_set(selector, "active-pad", sinkpad, NULL);
2727 _mmplayer_track_update_info(player, stream_type, sinkpad);
2734 gst_caps_unref(caps);
2737 gst_object_unref(GST_OBJECT(sinkpad));
2742 gst_object_unref(GST_OBJECT(srcpad));
2749 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2751 GstPad* srcpad = NULL;
2752 MMHandleType attrs = 0;
2753 gint active_index = 0;
2755 // [link] input-selector :: textbin
2756 srcpad = gst_element_get_static_pad(text_selector, "src");
2758 LOGE("failed to get srcpad from selector\n");
2762 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2764 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2765 if ((active_index != DEFAULT_TRACK) &&
2766 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2767 LOGW("failed to change text track\n");
2768 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2771 player->no_more_pad = TRUE;
2772 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2774 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2775 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2776 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2777 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2780 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2782 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2783 player->has_closed_caption = TRUE;
2785 attrs = MMPLAYER_GET_ATTRS(player);
2787 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2788 if (mmf_attrs_commit(attrs))
2789 LOGE("failed to commit.\n");
2791 LOGE("cannot get content attribute");
2794 gst_object_unref(GST_OBJECT(srcpad));
2800 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2802 mm_player_t* player = (mm_player_t*)data;
2803 GstElement* selector = NULL;
2804 GstElement* queue = NULL;
2806 GstPad* srcpad = NULL;
2807 GstPad* sinkpad = NULL;
2808 GstCaps* caps = NULL;
2809 gchar* caps_str = NULL;
2812 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2814 caps = gst_pad_get_current_caps(pad);
2815 caps_str = gst_caps_to_string(caps);
2816 LOGD("deinterleave new caps : %s\n", caps_str);
2817 MMPLAYER_FREEIF(caps_str);
2818 gst_caps_unref(caps);
2820 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2821 LOGE("ERROR : queue create error\n");
2825 g_object_set(G_OBJECT(queue),
2826 "max-size-buffers", 10,
2827 "max-size-bytes", 0,
2828 "max-size-time", (guint64)0,
2831 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2834 LOGE("there is no audio channel selector.\n");
2838 srcpad = gst_element_get_static_pad(queue, "src");
2839 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2841 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2843 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2844 LOGW("failed to link deinterleave - selector\n");
2848 gst_element_set_state(queue, GST_STATE_PAUSED);
2849 player->audio_mode.total_track_num++;
2854 gst_object_unref(GST_OBJECT(srcpad));
2859 gst_object_unref(GST_OBJECT(sinkpad));
2868 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2870 mm_player_t* player = NULL;
2871 GstElement* selector = NULL;
2872 GstPad* sinkpad = NULL;
2873 gint active_index = 0;
2874 gchar* change_pad_name = NULL;
2875 GstCaps* caps = NULL; // no need to unref
2876 gint default_audio_ch = 0;
2879 player = (mm_player_t*) data;
2881 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2884 LOGE("there is no audio channel selector.\n");
2888 active_index = player->audio_mode.active_pad_index;
2890 if (active_index != default_audio_ch) {
2891 gint audio_ch = default_audio_ch;
2893 /*To get the new pad from the selector*/
2894 change_pad_name = g_strdup_printf("sink%d", active_index);
2895 if (change_pad_name != NULL) {
2896 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2897 if (sinkpad != NULL) {
2898 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2899 g_object_set(selector, "active-pad", sinkpad, NULL);
2901 audio_ch = active_index;
2903 caps = gst_pad_get_current_caps(sinkpad);
2904 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2906 __mmplayer_set_audio_attrs(player, caps);
2907 gst_caps_unref(caps);
2909 MMPLAYER_FREEIF(change_pad_name);
2912 player->audio_mode.active_pad_index = audio_ch;
2913 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2919 gst_object_unref(sinkpad);
2926 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2928 mm_player_t* player = NULL;
2929 MMPlayerGstElement *mainbin = NULL;
2931 GstElement* tee = NULL;
2932 GstElement* stereo_queue = NULL;
2933 GstElement* mono_queue = NULL;
2934 GstElement* conv = NULL;
2935 GstElement* filter = NULL;
2936 GstElement* deinterleave = NULL;
2937 GstElement* selector = NULL;
2939 GstPad* srcpad = NULL;
2940 GstPad* selector_srcpad = NULL;
2941 GstPad* sinkpad = NULL;
2942 GstCaps* caps = NULL;
2943 gulong block_id = 0;
2948 player = (mm_player_t*) data;
2950 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2951 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2953 mainbin = player->pipeline->mainbin;
2956 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2957 LOGE("ERROR : tee create error\n");
2961 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2962 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2964 gst_element_set_state(tee, GST_STATE_PAUSED);
2967 srcpad = gst_element_get_request_pad(tee, "src_%u");
2968 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2969 LOGE("ERROR : stereo queue create error\n");
2973 g_object_set(G_OBJECT(stereo_queue),
2974 "max-size-buffers", 10,
2975 "max-size-bytes", 0,
2976 "max-size-time", (guint64)0,
2979 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2980 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2983 gst_object_unref(GST_OBJECT(srcpad));
2987 srcpad = gst_element_get_request_pad(tee, "src_%u");
2989 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2990 LOGE("ERROR : mono queue create error\n");
2994 g_object_set(G_OBJECT(mono_queue),
2995 "max-size-buffers", 10,
2996 "max-size-bytes", 0,
2997 "max-size-time", (guint64)0,
3000 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3001 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3003 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3004 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3007 srcpad = gst_element_get_static_pad(mono_queue, "src");
3008 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3009 LOGE("ERROR : audioconvert create error\n");
3013 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3014 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3018 gst_object_unref(GST_OBJECT(srcpad));
3021 srcpad = gst_element_get_static_pad(conv, "src");
3023 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3024 LOGE("ERROR : capsfilter create error\n");
3028 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3029 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3031 caps = gst_caps_from_string("audio/x-raw-int, "
3032 "width = (int) 16, "
3033 "depth = (int) 16, "
3034 "channels = (int) 2");
3036 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3037 gst_caps_unref(caps);
3039 gst_element_set_state(conv, GST_STATE_PAUSED);
3040 gst_element_set_state(filter, GST_STATE_PAUSED);
3044 gst_object_unref(GST_OBJECT(srcpad));
3047 srcpad = gst_element_get_static_pad(filter, "src");
3049 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3050 LOGE("ERROR : deinterleave create error\n");
3054 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3056 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3057 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3059 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3060 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3062 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3063 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3066 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3067 if (selector == NULL) {
3068 LOGE("ERROR : audio-selector create error\n");
3072 g_object_set(selector, "sync-streams", TRUE, NULL);
3073 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3075 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3076 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3078 selector_srcpad = gst_element_get_static_pad(selector, "src");
3080 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3082 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3083 __mmplayer_gst_selector_blocked, NULL, NULL);
3086 gst_object_unref(GST_OBJECT(srcpad));
3090 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3091 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3093 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3094 LOGW("failed to link queue_stereo - selector\n");
3098 player->audio_mode.total_track_num++;
3100 g_object_set(selector, "active-pad", sinkpad, NULL);
3101 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3102 gst_element_set_state(selector, GST_STATE_PAUSED);
3104 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3108 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3109 if (block_id != 0) {
3110 gst_pad_remove_probe(selector_srcpad, block_id);
3115 gst_object_unref(GST_OBJECT(sinkpad));
3120 gst_object_unref(GST_OBJECT(srcpad));
3124 if (selector_srcpad) {
3125 gst_object_unref(GST_OBJECT(selector_srcpad));
3126 selector_srcpad = NULL;
3134 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3136 mm_player_t* player = NULL;
3137 GstPad* srcpad = NULL;
3138 GstElement* video_selector = NULL;
3139 GstElement* audio_selector = NULL;
3140 GstElement* text_selector = NULL;
3141 MMHandleType attrs = 0;
3142 gint active_index = 0;
3143 gint64 dur_bytes = 0L;
3145 player = (mm_player_t*) data;
3147 LOGD("no-more-pad signal handling\n");
3149 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3150 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3151 LOGW("no need to go more");
3153 if (player->gapless.reconfigure) {
3154 player->gapless.reconfigure = FALSE;
3155 MMPLAYER_PLAYBACK_UNLOCK(player);
3161 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3162 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3163 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3164 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3165 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3167 if (NULL == player->streamer) {
3168 LOGW("invalid state for buffering");
3172 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3173 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3175 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3176 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3178 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3180 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3181 LOGE("fail to get duration.\n");
3183 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3184 // use file information was already set on Q2 when it was created.
3185 __mm_player_streaming_set_queue2(player->streamer,
3186 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3187 TRUE, // use_buffering
3189 init_buffering_time,
3191 player->ini.http_buffering_limit, // high percent
3192 MUXED_BUFFER_TYPE_MEM_QUEUE,
3194 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3197 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3198 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3199 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3200 if (video_selector) {
3201 // [link] input-selector :: videobin
3202 srcpad = gst_element_get_static_pad(video_selector, "src");
3204 LOGE("failed to get srcpad from video selector\n");
3208 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3209 if (!text_selector && !audio_selector)
3210 player->no_more_pad = TRUE;
3212 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3214 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3215 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3216 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3217 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3221 if (audio_selector) {
3222 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3223 if ((active_index != DEFAULT_TRACK) &&
3224 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3225 LOGW("failed to change audio track\n");
3226 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3229 // [link] input-selector :: audiobin
3230 srcpad = gst_element_get_static_pad(audio_selector, "src");
3232 LOGE("failed to get srcpad from selector\n");
3236 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3238 player->no_more_pad = TRUE;
3240 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3241 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3242 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3243 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3244 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3247 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3249 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3251 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3252 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3253 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3254 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3258 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3260 attrs = MMPLAYER_GET_ATTRS(player);
3262 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3263 if (mmf_attrs_commit(attrs))
3264 LOGE("failed to commit.\n");
3266 LOGE("cannot get content attribute");
3268 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3269 LOGD("There is no audio track : remove audiobin");
3271 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3272 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3274 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3275 MMPLAYER_FREEIF(player->pipeline->audiobin);
3278 if (player->num_dynamic_pad == 0)
3279 __mmplayer_pipeline_complete(NULL, player);
3282 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3284 __mmplayer_handle_text_decode_path(player, text_selector);
3291 gst_object_unref(GST_OBJECT(srcpad));
3295 if (player->gapless.reconfigure) {
3296 player->gapless.reconfigure = FALSE;
3297 MMPLAYER_PLAYBACK_UNLOCK(player);
3302 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3304 mm_player_t* player = NULL;
3305 MMHandleType attrs = 0;
3306 GstElement* pipeline = NULL;
3307 GstCaps* caps = NULL;
3308 gchar* caps_str = NULL;
3309 GstStructure* str = NULL;
3310 const gchar* name = NULL;
3311 GstPad* sinkpad = NULL;
3312 GstElement* sinkbin = NULL;
3313 gboolean reusing = FALSE;
3314 GstElement *text_selector = NULL;
3317 player = (mm_player_t*) data;
3319 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3320 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3322 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3324 attrs = MMPLAYER_GET_ATTRS(player);
3326 LOGE("cannot get content attribute\n");
3330 /* get mimetype from caps */
3331 caps = gst_pad_query_caps(pad, NULL);
3333 LOGE("cannot get caps from pad.\n");
3336 caps_str = gst_caps_to_string(caps);
3338 str = gst_caps_get_structure(caps, 0);
3340 LOGE("cannot get structure from caps.\n");
3344 name = gst_structure_get_name(str);
3346 LOGE("cannot get mimetype from structure.\n");
3350 //LOGD("detected mimetype : %s\n", name);
3352 if (strstr(name, "audio")) {
3353 if (player->pipeline->audiobin == NULL) {
3354 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3355 LOGE("failed to create audiobin. continuing without audio\n");
3359 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3360 LOGD("creating audiosink bin success\n");
3363 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3364 LOGD("reusing audiobin\n");
3365 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3368 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3369 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3371 player->audiosink_linked = 1;
3373 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3375 LOGE("failed to get pad from sinkbin\n");
3378 } else if (strstr(name, "video")) {
3379 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3380 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3381 player->set_mode.video_zc = TRUE;
3383 if (player->pipeline->videobin == NULL) {
3384 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3385 /* get video surface type */
3386 int surface_type = 0;
3387 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3388 LOGD("display_surface_type(%d)\n", surface_type);
3390 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3391 LOGD("not make videobin because it dose not want\n");
3395 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3396 /* mark video overlay for acquire */
3397 if (player->video_overlay_resource == NULL) {
3398 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3399 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3400 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3401 &player->video_overlay_resource)
3402 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3403 LOGE("could not mark video_overlay resource for acquire\n");
3409 player->interrupted_by_resource = FALSE;
3410 /* acquire resources for video overlay */
3411 if (mm_resource_manager_commit(player->resource_manager) !=
3412 MM_RESOURCE_MANAGER_ERROR_NONE) {
3413 LOGE("could not acquire resources for video playing\n");
3417 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3418 LOGE("failed to create videobin. continuing without video\n");
3422 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3423 LOGD("creating videosink bin success\n");
3426 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3427 LOGD("re-using videobin\n");
3428 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3431 player->videosink_linked = 1;
3433 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3435 LOGE("failed to get pad from sinkbin\n");
3438 } else if (strstr(name, "text")) {
3439 if (player->pipeline->textbin == NULL) {
3440 MMPlayerGstElement* mainbin = NULL;
3442 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3443 LOGE("failed to create text sink bin. continuing without text\n");
3447 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3448 LOGD("creating textsink bin success\n");
3450 /* FIXIT : track number shouldn't be hardcoded */
3451 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3453 player->textsink_linked = 1;
3454 LOGI("player->textsink_linked set to 1\n");
3456 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3458 LOGE("failed to get pad from sinkbin\n");
3462 mainbin = player->pipeline->mainbin;
3464 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3465 /* input selector */
3466 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3467 if (!text_selector) {
3468 LOGE("failed to create subtitle input selector element\n");
3471 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3473 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3474 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3477 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3478 LOGE("failed to set state(READY) to sinkbin\n");
3482 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3483 LOGW("failed to add subtitle input selector\n");
3487 LOGD("created element input-selector");
3490 LOGD("already having subtitle input selector");
3491 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3494 if (!player->textsink_linked) {
3495 LOGD("re-using textbin\n");
3498 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3500 player->textsink_linked = 1;
3501 LOGI("player->textsink_linked set to 1\n");
3503 LOGD("ignoring internal subtutle since external subtitle is available");
3506 LOGW("unknown type of elementary stream!ignoring it...\n");
3513 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3514 LOGE("failed to set state(READY) to sinkbin\n");
3518 /* Added for multi audio support to avoid adding audio bin again*/
3520 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3521 LOGE("failed to add sinkbin to pipeline\n");
3527 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3528 LOGE("failed to get pad from sinkbin\n");
3534 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3535 LOGE("failed to set state(PAUSED) to sinkbin\n");
3539 if (text_selector) {
3540 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3541 LOGE("failed to set state(PAUSED) to sinkbin\n");
3547 gst_object_unref(sinkpad);
3551 LOGD("[handle: %p] linking sink bin success", player);
3553 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3554 * streaming task. if the task blocked, then buffer will not flow to the next element
3555 *(autoplugging element). so this is special hack for streaming. please try to remove it
3557 /* dec stream count. we can remove fakesink if it's zero */
3558 if (player->num_dynamic_pad)
3559 player->num_dynamic_pad--;
3561 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3563 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3564 __mmplayer_pipeline_complete(NULL, player);
3568 MMPLAYER_FREEIF(caps_str);
3571 gst_caps_unref(caps);
3574 gst_object_unref(GST_OBJECT(sinkpad));
3576 /* flusing out new attributes */
3577 if (mmf_attrs_commit(attrs))
3578 LOGE("failed to comit attributes\n");
3584 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3586 int pro_value = 0; // in the case of expection, default will be returned.
3587 int dest_angle = rotation_angle;
3588 int rotation_type = -1;
3590 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3591 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3592 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3594 if (rotation_angle >= 360)
3595 dest_angle = rotation_angle - 360;
3597 /* chech if supported or not */
3598 if (dest_angle % 90) {
3599 LOGD("not supported rotation angle = %d", rotation_angle);
3605 * custom_convert - none (B)
3606 * videoflip - none (C)
3608 if (player->set_mode.video_zc) {
3609 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3610 rotation_type = ROTATION_USING_CUSTOM;
3612 rotation_type = ROTATION_USING_SINK;
3614 int surface_type = 0;
3615 rotation_type = ROTATION_USING_FLIP;
3617 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3618 LOGD("check display surface type attribute: %d", surface_type);
3620 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3621 rotation_type = ROTATION_USING_SINK;
3623 rotation_type = ROTATION_USING_FLIP; //C
3625 LOGD("using %d type for rotation", rotation_type);
3628 /* get property value for setting */
3629 switch (rotation_type) {
3630 case ROTATION_USING_SINK: // tizenwlsink
3632 switch (dest_angle) {
3636 pro_value = 3; // clockwise 90
3642 pro_value = 1; // counter-clockwise 90
3647 case ROTATION_USING_CUSTOM:
3649 gchar *ename = NULL;
3650 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3652 if (g_strrstr(ename, "fimcconvert")) {
3653 switch (dest_angle) {
3657 pro_value = 90; // clockwise 90
3663 pro_value = 270; // counter-clockwise 90
3669 case ROTATION_USING_FLIP: // videoflip
3671 switch (dest_angle) {
3675 pro_value = 1; // clockwise 90
3681 pro_value = 3; // counter-clockwise 90
3688 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3696 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3698 /* check video sinkbin is created */
3699 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3701 player->pipeline->videobin &&
3702 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3703 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3704 MM_ERROR_PLAYER_NOT_INITIALIZED);
3706 return MM_ERROR_NONE;
3710 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3712 int rotation_value = 0;
3713 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3717 /* check video sinkbin is created */
3718 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3721 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3723 /* get rotation value to set */
3724 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3725 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3726 LOGD("set video param : rotate %d", rotation_value);
3730 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3732 MMHandleType attrs = 0;
3736 /* check video sinkbin is created */
3737 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3740 attrs = MMPLAYER_GET_ATTRS(player);
3741 MMPLAYER_RETURN_IF_FAIL(attrs);
3743 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3744 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3745 LOGD("set video param : visible %d", visible);
3749 __mmplayer_video_param_set_display_method(mm_player_t* player)
3751 MMHandleType attrs = 0;
3752 int display_method = 0;
3755 /* check video sinkbin is created */
3756 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3759 attrs = MMPLAYER_GET_ATTRS(player);
3760 MMPLAYER_RETURN_IF_FAIL(attrs);
3762 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3763 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3764 LOGD("set video param : method %d", display_method);
3768 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3770 MMHandleType attrs = 0;
3771 void *handle = NULL;
3773 int wl_window_x = 0;
3774 int wl_window_y = 0;
3775 int wl_window_width = 0;
3776 int wl_window_height = 0;
3779 /* check video sinkbin is created */
3780 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3783 attrs = MMPLAYER_GET_ATTRS(player);
3784 MMPLAYER_RETURN_IF_FAIL(attrs);
3786 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3789 /*It should be set after setting window*/
3790 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3791 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3792 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3793 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3795 /* After setting window handle, set render rectangle */
3796 gst_video_overlay_set_render_rectangle(
3797 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3798 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3799 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3800 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3805 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3807 MMHandleType attrs = 0;
3808 void *handle = NULL;
3810 /* check video sinkbin is created */
3811 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3814 attrs = MMPLAYER_GET_ATTRS(player);
3815 MMPLAYER_RETURN_IF_FAIL(attrs);
3817 /* common case if using overlay surface */
3818 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3821 /* default is using wl_surface_id */
3822 unsigned int wl_surface_id = 0;
3823 wl_surface_id = *(int*)handle;
3824 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3825 gst_video_overlay_set_wl_window_wl_surface_id(
3826 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3829 /* FIXIT : is it error case? */
3830 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3835 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3837 bool update_all_param = FALSE;
3840 /* check video sinkbin is created */
3841 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3842 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3844 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3845 LOGE("can not find tizenwlsink");
3846 return MM_ERROR_PLAYER_INTERNAL;
3849 LOGD("param_name : %s", param_name);
3850 if (!g_strcmp0(param_name, "update_all_param"))
3851 update_all_param = TRUE;
3853 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3854 __mmplayer_video_param_set_display_overlay(player);
3855 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3856 __mmplayer_video_param_set_display_method(player);
3857 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3858 __mmplayer_video_param_set_render_rectangle(player);
3859 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3860 __mmplayer_video_param_set_display_visible(player);
3861 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3862 __mmplayer_video_param_set_display_rotation(player);
3864 return MM_ERROR_NONE;
3868 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3870 MMHandleType attrs = 0;
3871 int surface_type = 0;
3872 int ret = MM_ERROR_NONE;
3876 /* check video sinkbin is created */
3877 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3878 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3880 attrs = MMPLAYER_GET_ATTRS(player);
3882 LOGE("cannot get content attribute");
3883 return MM_ERROR_PLAYER_INTERNAL;
3885 LOGD("param_name : %s", param_name);
3887 /* update display surface */
3888 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3889 LOGD("check display surface type attribute: %d", surface_type);
3891 /* configuring display */
3892 switch (surface_type) {
3893 case MM_DISPLAY_SURFACE_OVERLAY:
3895 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3896 if (ret != MM_ERROR_NONE)
3904 return MM_ERROR_NONE;
3908 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3910 gboolean disable_overlay = FALSE;
3911 mm_player_t* player = (mm_player_t*) hplayer;
3912 int ret = MM_ERROR_NONE;
3915 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3916 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3917 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3918 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3920 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3921 LOGW("Display control is not supported");
3922 return MM_ERROR_PLAYER_INTERNAL;
3925 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3927 if (audio_only == (bool)disable_overlay) {
3928 LOGE("It's the same with current setting: (%d)", audio_only);
3929 return MM_ERROR_NONE;
3933 LOGE("disable overlay");
3934 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3936 /* release overlay resource */
3937 if (player->video_overlay_resource != NULL) {
3938 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3939 player->video_overlay_resource);
3940 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3941 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3944 player->video_overlay_resource = NULL;
3947 ret = mm_resource_manager_commit(player->resource_manager);
3948 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3949 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3953 /* mark video overlay for acquire */
3954 if (player->video_overlay_resource == NULL) {
3955 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3956 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3957 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3958 &player->video_overlay_resource);
3959 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3960 LOGE("could not prepare for video_overlay resource\n");
3965 player->interrupted_by_resource = FALSE;
3966 /* acquire resources for video overlay */
3967 ret = mm_resource_manager_commit(player->resource_manager);
3968 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3969 LOGE("could not acquire resources for video playing\n");
3973 LOGD("enable overlay");
3974 __mmplayer_video_param_set_display_overlay(player);
3975 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3980 return MM_ERROR_NONE;
3984 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3986 mm_player_t* player = (mm_player_t*) hplayer;
3987 gboolean disable_overlay = FALSE;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3992 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3993 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3994 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3995 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3997 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3998 LOGW("Display control is not supported");
3999 return MM_ERROR_PLAYER_INTERNAL;
4002 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4004 *paudio_only = (bool)(disable_overlay);
4006 LOGD("audio_only : %d", *paudio_only);
4010 return MM_ERROR_NONE;
4014 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4016 GList* bucket = element_bucket;
4017 MMPlayerGstElement* element = NULL;
4018 MMPlayerGstElement* prv_element = NULL;
4019 gint successful_link_count = 0;
4023 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4025 prv_element = (MMPlayerGstElement*)bucket->data;
4026 bucket = bucket->next;
4028 for (; bucket; bucket = bucket->next) {
4029 element = (MMPlayerGstElement*)bucket->data;
4031 if (element && element->gst) {
4032 /* If next element is audio appsrc then make a separate audio pipeline */
4033 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4034 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4035 prv_element = element;
4039 if (prv_element && prv_element->gst) {
4040 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4041 LOGD("linking [%s] to [%s] success\n",
4042 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4043 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4044 successful_link_count++;
4046 LOGD("linking [%s] to [%s] failed\n",
4047 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4048 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4054 prv_element = element;
4059 return successful_link_count;
4063 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4065 GList* bucket = element_bucket;
4066 MMPlayerGstElement* element = NULL;
4067 int successful_add_count = 0;
4071 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4072 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4074 for (; bucket; bucket = bucket->next) {
4075 element = (MMPlayerGstElement*)bucket->data;
4077 if (element && element->gst) {
4078 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4079 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4080 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4081 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4084 successful_add_count++;
4090 return successful_add_count;
4093 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4095 mm_player_t* player = (mm_player_t*) data;
4096 GstCaps *caps = NULL;
4097 GstStructure *str = NULL;
4102 MMPLAYER_RETURN_IF_FAIL(pad)
4103 MMPLAYER_RETURN_IF_FAIL(unused)
4104 MMPLAYER_RETURN_IF_FAIL(data)
4106 caps = gst_pad_get_current_caps(pad);
4110 str = gst_caps_get_structure(caps, 0);
4114 name = gst_structure_get_name(str);
4118 LOGD("name = %s\n", name);
4120 if (strstr(name, "audio")) {
4121 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4123 if (player->audio_stream_changed_cb) {
4124 LOGE("call the audio stream changed cb\n");
4125 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4127 } else if (strstr(name, "video")) {
4128 if ((name = gst_structure_get_string(str, "format")))
4129 player->set_mode.video_zc = name[0] == 'S';
4131 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4133 if (player->video_stream_changed_cb) {
4134 LOGE("call the video stream changed cb\n");
4135 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4142 gst_caps_unref(caps);
4152 * This function is to create audio pipeline for playing.
4154 * @param player [in] handle of player
4156 * @return This function returns zero on success.
4158 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4160 /* macro for code readability. just for sinkbin-creation functions */
4161 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4163 x_bin[x_id].id = x_id;\
4164 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4165 if (!x_bin[x_id].gst) {\
4166 LOGE("failed to create %s \n", x_factory);\
4169 if (x_player->ini.set_dump_element_flag)\
4170 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4173 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4177 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4182 MMPLAYER_RETURN_IF_FAIL(player);
4184 if (player->audio_stream_buff_list) {
4185 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4186 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4189 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4190 __mmplayer_audio_stream_send_data(player, tmp);
4193 g_free(tmp->pcm_data);
4197 g_list_free(player->audio_stream_buff_list);
4198 player->audio_stream_buff_list = NULL;
4205 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4207 MMPlayerAudioStreamDataType audio_stream = { 0, };
4210 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4212 audio_stream.bitrate = a_buffer->bitrate;
4213 audio_stream.channel = a_buffer->channel;
4214 audio_stream.depth = a_buffer->depth;
4215 audio_stream.is_little_endian = a_buffer->is_little_endian;
4216 audio_stream.channel_mask = a_buffer->channel_mask;
4217 audio_stream.data_size = a_buffer->data_size;
4218 audio_stream.data = a_buffer->pcm_data;
4220 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4221 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4227 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4229 mm_player_t* player = (mm_player_t*) data;
4234 gint endianness = 0;
4235 guint64 channel_mask = 0;
4236 void *a_data = NULL;
4238 mm_player_audio_stream_buff_t *a_buffer = NULL;
4239 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4243 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4245 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4246 a_data = mapinfo.data;
4247 a_size = mapinfo.size;
4249 GstCaps *caps = gst_pad_get_current_caps(pad);
4250 GstStructure *structure = gst_caps_get_structure(caps, 0);
4252 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4253 gst_structure_get_int(structure, "rate", &rate);
4254 gst_structure_get_int(structure, "channels", &channel);
4255 gst_structure_get_int(structure, "depth", &depth);
4256 gst_structure_get_int(structure, "endianness", &endianness);
4257 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4258 gst_caps_unref(GST_CAPS(caps));
4260 /* In case of the sync is false, use buffer list. *
4261 * The num of buffer list depends on the num of audio channels */
4262 if (player->audio_stream_buff_list) {
4263 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4264 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4266 if (channel_mask == tmp->channel_mask) {
4267 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4268 if (tmp->data_size + a_size < tmp->buff_size) {
4269 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4270 tmp->data_size += a_size;
4272 /* send data to client */
4273 __mmplayer_audio_stream_send_data(player, tmp);
4275 if (a_size > tmp->buff_size) {
4276 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4277 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4278 if (tmp->pcm_data == NULL) {
4279 LOGE("failed to realloc data.");
4282 tmp->buff_size = a_size;
4284 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4285 memcpy(tmp->pcm_data, a_data, a_size);
4286 tmp->data_size = a_size;
4291 LOGE("data is empty in list.");
4297 /* create new audio stream data */
4298 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4299 if (a_buffer == NULL) {
4300 LOGE("failed to alloc data.");
4303 a_buffer->bitrate = rate;
4304 a_buffer->channel = channel;
4305 a_buffer->depth = depth;
4306 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4307 a_buffer->channel_mask = channel_mask;
4308 a_buffer->data_size = a_size;
4310 if (!player->audio_stream_sink_sync) {
4311 /* If sync is FALSE, use buffer list to reduce the IPC. */
4312 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4313 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4314 if (a_buffer->pcm_data == NULL) {
4315 LOGE("failed to alloc data.");
4319 memcpy(a_buffer->pcm_data, a_data, a_size);
4320 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4321 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4323 /* If sync is TRUE, send data directly. */
4324 a_buffer->pcm_data = a_data;
4325 __mmplayer_audio_stream_send_data(player, a_buffer);
4330 gst_buffer_unmap(buffer, &mapinfo);
4335 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4337 mm_player_t* player = (mm_player_t*)data;
4338 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4339 GstPad* sinkpad = NULL;
4340 GstElement *queue = NULL, *sink = NULL;
4343 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4345 queue = gst_element_factory_make("queue", NULL);
4346 if (queue == NULL) {
4347 LOGD("fail make queue\n");
4351 sink = gst_element_factory_make("fakesink", NULL);
4353 LOGD("fail make fakesink\n");
4357 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4359 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4360 LOGW("failed to link queue & sink\n");
4364 sinkpad = gst_element_get_static_pad(queue, "sink");
4366 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4367 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4371 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4373 gst_object_unref(sinkpad);
4374 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4375 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4377 gst_element_set_state(sink, GST_STATE_PAUSED);
4378 gst_element_set_state(queue, GST_STATE_PAUSED);
4380 MMPLAYER_SIGNAL_CONNECT(player,
4382 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4384 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4391 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4393 gst_object_unref(GST_OBJECT(queue));
4397 gst_object_unref(GST_OBJECT(sink));
4401 gst_object_unref(GST_OBJECT(sinkpad));
4408 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4410 #define MAX_PROPS_LEN 128
4411 gint latency_mode = 0;
4412 gchar *stream_type = NULL;
4413 gchar *latency = NULL;
4415 gchar stream_props[MAX_PROPS_LEN] = {0,};
4416 GstStructure *props = NULL;
4419 * It should be set after player creation through attribute.
4420 * But, it can not be changed during playing.
4423 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4424 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4427 LOGE("stream_type is null.\n");
4429 if (player->sound.focus_id)
4430 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4431 stream_type, stream_id, player->sound.focus_id);
4433 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4434 stream_type, stream_id);
4435 props = gst_structure_from_string(stream_props, NULL);
4436 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4437 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4438 stream_type, stream_id, player->sound.focus_id, stream_props);
4439 gst_structure_free(props);
4442 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4444 switch (latency_mode) {
4445 case AUDIO_LATENCY_MODE_LOW:
4446 latency = g_strndup("low", 3);
4448 case AUDIO_LATENCY_MODE_MID:
4449 latency = g_strndup("mid", 3);
4451 case AUDIO_LATENCY_MODE_HIGH:
4452 latency = g_strndup("high", 4);
4456 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4460 LOGD("audiosink property - latency=%s \n", latency);
4468 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4470 MMPlayerGstElement* first_element = NULL;
4471 MMPlayerGstElement* audiobin = NULL;
4472 MMHandleType attrs = 0;
4474 GstPad *ghostpad = NULL;
4475 GList* element_bucket = NULL;
4476 gboolean link_audio_sink_now = TRUE;
4482 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4485 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4487 LOGE("failed to allocate memory for audiobin\n");
4488 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4491 attrs = MMPLAYER_GET_ATTRS(player);
4494 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4495 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4496 if (!audiobin[MMPLAYER_A_BIN].gst) {
4497 LOGE("failed to create audiobin\n");
4502 player->pipeline->audiobin = audiobin;
4504 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4506 /* Adding audiotp plugin for reverse trickplay feature */
4507 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4510 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4512 /* replaygain volume */
4513 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4514 if (player->sound.rg_enable)
4515 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4517 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4520 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4522 if (player->set_mode.pcm_extraction) {
4523 // pcm extraction only and no sound output
4524 if (player->audio_stream_render_cb_ex) {
4525 char *caps_str = NULL;
4526 GstCaps* caps = NULL;
4527 gchar *format = NULL;
4530 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4532 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4534 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4536 caps = gst_caps_new_simple("audio/x-raw",
4537 "format", G_TYPE_STRING, format,
4538 "rate", G_TYPE_INT, player->pcm_samplerate,
4539 "channels", G_TYPE_INT, player->pcm_channel,
4541 caps_str = gst_caps_to_string(caps);
4542 LOGD("new caps : %s\n", caps_str);
4544 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4547 gst_caps_unref(caps);
4548 MMPLAYER_FREEIF(caps_str);
4550 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4552 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4553 /* raw pad handling signal */
4554 MMPLAYER_SIGNAL_CONNECT(player,
4555 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4556 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4557 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4559 int dst_samplerate = 0;
4560 int dst_channels = 0;
4562 char *caps_str = NULL;
4563 GstCaps* caps = NULL;
4565 /* get conf. values */
4566 mm_attrs_multiple_get(player->attrs,
4568 "pcm_extraction_samplerate", &dst_samplerate,
4569 "pcm_extraction_channels", &dst_channels,
4570 "pcm_extraction_depth", &dst_depth,
4574 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4575 caps = gst_caps_new_simple("audio/x-raw",
4576 "rate", G_TYPE_INT, dst_samplerate,
4577 "channels", G_TYPE_INT, dst_channels,
4578 "depth", G_TYPE_INT, dst_depth,
4580 caps_str = gst_caps_to_string(caps);
4581 LOGD("new caps : %s\n", caps_str);
4583 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4586 gst_caps_unref(caps);
4587 MMPLAYER_FREEIF(caps_str);
4590 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4593 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4597 //GstCaps* caps = NULL;
4600 /* for logical volume control */
4601 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4602 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4604 if (player->sound.mute) {
4605 LOGD("mute enabled\n");
4606 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4611 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4612 caps = gst_caps_from_string("audio/x-raw-int, "
4613 "endianness = (int) LITTLE_ENDIAN, "
4614 "signed = (boolean) true, "
4615 "width = (int) 16, "
4616 "depth = (int) 16");
4617 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4618 gst_caps_unref(caps);
4621 /* check if multi-channels */
4622 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4623 GstPad *srcpad = NULL;
4624 GstCaps *caps = NULL;
4626 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4627 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4628 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4629 GstStructure *str = gst_caps_get_structure(caps, 0);
4631 gst_structure_get_int(str, "channels", &channels);
4632 gst_caps_unref(caps);
4634 gst_object_unref(srcpad);
4638 /* audio effect element. if audio effect is enabled */
4639 if ((strcmp(player->ini.audioeffect_element, ""))
4641 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4644 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4646 if ((!player->bypass_audio_effect)
4647 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4648 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4649 if (!_mmplayer_audio_effect_custom_apply(player))
4650 LOGI("apply audio effect(custom) setting success\n");
4654 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4655 && (player->set_mode.rich_audio))
4656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4659 /* create audio sink */
4660 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4661 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4662 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4664 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4665 if (player->is_360_feature_enabled &&
4666 player->is_content_spherical &&
4668 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4669 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4670 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4672 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4674 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4676 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4677 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4678 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4679 gst_caps_unref(acaps);
4681 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4682 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4683 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4686 player->is_openal_plugin_used = TRUE;
4688 if (player->video360_yaw_radians <= M_PI &&
4689 player->video360_yaw_radians >= -M_PI &&
4690 player->video360_pitch_radians <= M_PI_2 &&
4691 player->video360_pitch_radians >= -M_PI_2) {
4692 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4693 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4694 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4695 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4696 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4697 "source-orientation-y", player->video360_metadata.init_view_heading,
4698 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4701 if (player->is_360_feature_enabled && player->is_content_spherical)
4702 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4703 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4711 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4712 (player->videodec_linked && player->ini.use_system_clock)) {
4713 LOGD("system clock will be used.\n");
4714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4717 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4718 __mmplayer_gst_set_audiosink_property(player, attrs);
4721 if (audiobin[MMPLAYER_A_SINK].gst) {
4722 GstPad *sink_pad = NULL;
4723 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4724 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4725 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4726 gst_object_unref(GST_OBJECT(sink_pad));
4729 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4731 /* adding created elements to bin */
4732 LOGD("adding created elements to bin\n");
4733 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4734 LOGE("failed to add elements\n");
4738 /* linking elements in the bucket by added order. */
4739 LOGD("Linking elements in the bucket by added order.\n");
4740 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4741 LOGE("failed to link elements\n");
4745 /* get first element's sinkpad for creating ghostpad */
4746 first_element = (MMPlayerGstElement *)element_bucket->data;
4747 if (!first_element) {
4748 LOGE("failed to get first elem\n");
4752 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4754 LOGE("failed to get pad from first element of audiobin\n");
4758 ghostpad = gst_ghost_pad_new("sink", pad);
4760 LOGE("failed to create ghostpad\n");
4764 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4765 LOGE("failed to add ghostpad to audiobin\n");
4769 gst_object_unref(pad);
4771 g_list_free(element_bucket);
4774 return MM_ERROR_NONE;
4778 LOGD("ERROR : releasing audiobin\n");
4781 gst_object_unref(GST_OBJECT(pad));
4784 gst_object_unref(GST_OBJECT(ghostpad));
4787 g_list_free(element_bucket);
4789 /* release element which are not added to bin */
4790 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4791 /* NOTE : skip bin */
4792 if (audiobin[i].gst) {
4793 GstObject* parent = NULL;
4794 parent = gst_element_get_parent(audiobin[i].gst);
4797 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4798 audiobin[i].gst = NULL;
4800 gst_object_unref(GST_OBJECT(parent));
4804 /* release audiobin with it's childs */
4805 if (audiobin[MMPLAYER_A_BIN].gst)
4806 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4808 MMPLAYER_FREEIF(audiobin);
4810 player->pipeline->audiobin = NULL;
4812 return MM_ERROR_PLAYER_INTERNAL;
4815 static GstPadProbeReturn
4816 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4818 mm_player_t* player = (mm_player_t*) u_data;
4819 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4820 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4822 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4824 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4825 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4827 return GST_PAD_PROBE_OK;
4830 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4832 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4835 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4837 int ret = MM_ERROR_NONE;
4839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4840 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4842 MMPLAYER_VIDEO_BO_LOCK(player);
4844 if (player->video_bo_list) {
4845 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4846 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4847 if (tmp && tmp->bo == bo) {
4849 LOGD("release bo %p", bo);
4850 tbm_bo_unref(tmp->bo);
4851 MMPLAYER_VIDEO_BO_UNLOCK(player);
4852 MMPLAYER_VIDEO_BO_SIGNAL(player);
4857 /* hw codec is running or the list was reset for DRC. */
4858 LOGW("there is no bo list.");
4860 MMPLAYER_VIDEO_BO_UNLOCK(player);
4862 LOGW("failed to find bo %p", bo);
4867 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4872 MMPLAYER_RETURN_IF_FAIL(player);
4874 MMPLAYER_VIDEO_BO_LOCK(player);
4875 if (player->video_bo_list) {
4876 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4877 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4878 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4881 tbm_bo_unref(tmp->bo);
4885 g_list_free(player->video_bo_list);
4886 player->video_bo_list = NULL;
4888 player->video_bo_size = 0;
4889 MMPLAYER_VIDEO_BO_UNLOCK(player);
4896 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4899 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4900 gboolean ret = TRUE;
4902 /* check DRC, if it is, destroy the prev bo list to create again */
4903 if (player->video_bo_size != size) {
4904 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4905 __mmplayer_video_stream_destroy_bo_list(player);
4906 player->video_bo_size = size;
4909 MMPLAYER_VIDEO_BO_LOCK(player);
4911 if ((!player->video_bo_list) ||
4912 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4914 /* create bo list */
4916 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4918 if (player->video_bo_list) {
4919 /* if bo list did not created all, try it again. */
4920 idx = g_list_length(player->video_bo_list);
4921 LOGD("bo list exist(len: %d)", idx);
4924 for (; idx < player->ini.num_of_video_bo; idx++) {
4925 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4927 LOGE("Fail to alloc bo_info.");
4930 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4932 LOGE("Fail to tbm_bo_alloc.");
4936 bo_info->using = FALSE;
4937 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4940 /* update video num buffers */
4941 player->video_num_buffers = idx;
4942 if (idx == player->ini.num_of_video_bo)
4943 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4946 MMPLAYER_VIDEO_BO_UNLOCK(player);
4950 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4954 /* get bo from list*/
4955 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4956 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4957 if (tmp && (tmp->using == FALSE)) {
4958 LOGD("found bo %p to use", tmp->bo);
4960 MMPLAYER_VIDEO_BO_UNLOCK(player);
4961 return tbm_bo_ref(tmp->bo);
4965 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4966 MMPLAYER_VIDEO_BO_UNLOCK(player);
4970 if (player->ini.video_bo_timeout <= 0) {
4971 MMPLAYER_VIDEO_BO_WAIT(player);
4973 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4974 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4981 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4983 mm_player_t* player = (mm_player_t*)data;
4985 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4987 /* send prerolled pkt */
4988 player->video_stream_prerolled = FALSE;
4990 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4992 /* not to send prerolled pkt again */
4993 player->video_stream_prerolled = TRUE;
4997 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4999 mm_player_t* player = (mm_player_t*)data;
5000 GstCaps *caps = NULL;
5001 MMPlayerVideoStreamDataType *stream = NULL;
5002 MMVideoBuffer *video_buffer = NULL;
5003 GstMemory *dataBlock = NULL;
5004 GstMemory *metaBlock = NULL;
5005 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5006 GstStructure *structure = NULL;
5007 const gchar *string_format = NULL;
5008 unsigned int fourcc = 0;
5011 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5013 if (player->video_stream_prerolled) {
5014 player->video_stream_prerolled = FALSE;
5015 LOGD("skip the prerolled pkt not to send it again");
5019 caps = gst_pad_get_current_caps(pad);
5021 LOGE("Caps is NULL.");
5025 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5027 /* clear stream data structure */
5028 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5030 LOGE("failed to alloc mem for video data");
5034 structure = gst_caps_get_structure(caps, 0);
5035 gst_structure_get_int(structure, "width", &(stream->width));
5036 gst_structure_get_int(structure, "height", &(stream->height));
5037 string_format = gst_structure_get_string(structure, "format");
5039 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5040 stream->format = util_get_pixtype(fourcc);
5041 gst_caps_unref(caps);
5044 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5047 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5048 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5051 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5052 LOGE("Wrong condition!!");
5056 /* set size and timestamp */
5057 dataBlock = gst_buffer_peek_memory(buffer, 0);
5058 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5059 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/GST_MSECOND); /* nano sec -> mili sec */
5061 /* check zero-copy */
5062 if (player->set_mode.video_zc &&
5063 player->set_mode.media_packet_video_stream &&
5064 gst_buffer_n_memory(buffer) > 1) {
5065 metaBlock = gst_buffer_peek_memory(buffer, 1);
5066 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5067 video_buffer = (MMVideoBuffer *)mapinfo.data;
5070 if (video_buffer) { /* hw codec */
5072 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5075 /* copy pointer of tbm bo, stride, elevation */
5076 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5077 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5081 LOGE("Not support video buffer format");
5084 memcpy(stream->stride, video_buffer->stride_width,
5085 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5086 memcpy(stream->elevation, video_buffer->stride_height,
5087 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5089 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5090 stream->internal_buffer = gst_buffer_ref(buffer);
5091 } else { /* sw codec */
5095 int ret = TBM_SURFACE_ERROR_NONE;
5096 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5097 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5099 unsigned char *src = NULL;
5100 unsigned char *dest = NULL;
5101 tbm_bo_handle thandle;
5102 tbm_surface_h surface;
5103 tbm_surface_info_s info;
5106 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5108 LOGE("fail to gst_memory_map");
5113 if (stream->format == MM_PIXEL_FORMAT_I420) {
5114 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5116 ret = tbm_surface_get_info(surface, &info);
5118 if (ret != TBM_SURFACE_ERROR_NONE) {
5119 tbm_surface_destroy(surface);
5122 tbm_surface_destroy(surface);
5124 src_stride[0] = GST_ROUND_UP_4(stream->width);
5125 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5126 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5127 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5128 stream->stride[0] = info.planes[0].stride;
5129 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5130 stream->stride[1] = info.planes[1].stride;
5131 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5132 stream->stride[2] = info.planes[2].stride;
5133 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5134 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5135 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5136 stream->stride[0] = stream->width * 4;
5137 stream->elevation[0] = stream->height;
5138 size = stream->stride[0] * stream->height;
5140 LOGE("Not support format %d", stream->format);
5144 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5145 if (!stream->bo[0]) {
5146 LOGE("Fail to tbm_bo_alloc!!");
5150 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5151 if (thandle.ptr && mapinfo.data) {
5152 if (stream->format == MM_PIXEL_FORMAT_I420) {
5153 for (i = 0; i < 3; i++) {
5154 src = mapinfo.data + src_offset[i];
5155 dest = thandle.ptr + info.planes[i].offset;
5158 for (j = 0; j < stream->height>>k; j++) {
5159 memcpy(dest, src, stream->width>>k);
5160 src += src_stride[i];
5161 dest += stream->stride[i];
5164 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5165 memcpy(thandle.ptr, mapinfo.data, size);
5167 LOGE("Not support format %d", stream->format);
5171 LOGE("data pointer is wrong. dest : %p, src : %p",
5172 thandle.ptr, mapinfo.data);
5175 tbm_bo_unmap(stream->bo[0]);
5178 if (player->video_stream_cb) { /* This has been already checked at the entry */
5179 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5180 LOGE("failed to send video stream data.");
5186 gst_memory_unmap(metaBlock, &mapinfo);
5188 gst_memory_unmap(dataBlock, &mapinfo);
5193 LOGE("release video stream resource.");
5196 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5198 tbm_bo_unref(stream->bo[i]);
5200 gst_memory_unmap(metaBlock, &mapinfo);
5202 /* unref gst buffer */
5203 if (stream->internal_buffer)
5204 gst_buffer_unref(stream->internal_buffer);
5205 } else if (dataBlock) {
5207 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5208 gst_memory_unmap(dataBlock, &mapinfo);
5216 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5218 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5219 GList* element_bucket = NULL;
5221 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5225 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5226 LOGD("do not need to add video filters.");
5227 return MM_ERROR_NONE;
5230 /* in case of sw codec except 360 playback,
5231 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5232 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5233 LOGD("using video converter: %s", video_csc);
5235 /* set video rotator */
5236 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5238 *bucket = element_bucket;
5240 return MM_ERROR_NONE;
5242 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5243 g_list_free(element_bucket);
5247 return MM_ERROR_PLAYER_INTERNAL;
5251 * This function is to create video pipeline.
5253 * @param player [in] handle of player
5254 * caps [in] src caps of decoder
5255 * surface_type [in] surface type for video rendering
5257 * @return This function returns zero on success.
5259 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5263 * - video overlay surface(arm/x86) : tizenwlsink
5266 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5270 GList*element_bucket = NULL;
5271 MMPlayerGstElement* first_element = NULL;
5272 MMPlayerGstElement* videobin = NULL;
5273 gchar *videosink_element = NULL;
5277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5282 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5284 player->pipeline->videobin = videobin;
5286 attrs = MMPLAYER_GET_ATTRS(player);
5288 LOGE("cannot get content attribute");
5289 return MM_ERROR_PLAYER_INTERNAL;
5293 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5294 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5295 if (!videobin[MMPLAYER_V_BIN].gst) {
5296 LOGE("failed to create videobin");
5300 int enable_video_decoded_cb = 0;
5301 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5303 if (player->is_360_feature_enabled && player->is_content_spherical) {
5304 LOGD("video360 elem will be added.");
5306 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5307 "video-360", TRUE, player);
5309 /* Set spatial media metadata and/or user settings to the element.
5311 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5312 "projection-type", player->video360_metadata.projection_type, NULL);
5314 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5315 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5317 if (player->video360_metadata.full_pano_width_pixels &&
5318 player->video360_metadata.full_pano_height_pixels &&
5319 player->video360_metadata.cropped_area_image_width &&
5320 player->video360_metadata.cropped_area_image_height) {
5321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5322 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5323 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5324 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5325 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5326 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5327 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5331 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5332 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5333 "horizontal-fov", player->video360_horizontal_fov,
5334 "vertical-fov", player->video360_vertical_fov, NULL);
5337 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5338 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5339 "zoom", 1.0f / player->video360_zoom, NULL);
5342 if (player->video360_yaw_radians <= M_PI &&
5343 player->video360_yaw_radians >= -M_PI &&
5344 player->video360_pitch_radians <= M_PI_2 &&
5345 player->video360_pitch_radians >= -M_PI_2) {
5346 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5347 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5348 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5349 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5350 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5351 "pose-yaw", player->video360_metadata.init_view_heading,
5352 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5355 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5356 "passthrough", !player->is_video360_enabled, NULL);
5359 /* set video sink */
5360 switch (surface_type) {
5361 case MM_DISPLAY_SURFACE_OVERLAY:
5362 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5364 if (strlen(player->ini.videosink_element_overlay) > 0)
5365 videosink_element = player->ini.videosink_element_overlay;
5369 case MM_DISPLAY_SURFACE_NULL:
5370 if (strlen(player->ini.videosink_element_fake) > 0)
5371 videosink_element = player->ini.videosink_element_fake;
5375 case MM_DISPLAY_SURFACE_REMOTE:
5376 if (strlen(player->ini.videosink_element_fake) > 0)
5377 videosink_element = player->ini.videosink_element_fake;
5382 LOGE("unidentified surface type");
5385 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5387 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5389 /* additional setting for sink plug-in */
5390 switch (surface_type) {
5391 case MM_DISPLAY_SURFACE_OVERLAY:
5393 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5395 LOGD("selected videosink name: %s", videosink_element);
5397 /* support shard memory with S/W codec on HawkP */
5398 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5399 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5400 "use-tbm", use_tbm, NULL);
5406 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5409 LOGD("disable last-sample");
5410 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5414 if (player->set_mode.media_packet_video_stream) {
5416 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5418 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5420 MMPLAYER_SIGNAL_CONNECT(player,
5421 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5422 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5424 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5427 MMPLAYER_SIGNAL_CONNECT(player,
5428 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5429 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5431 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5436 case MM_DISPLAY_SURFACE_REMOTE:
5438 if (player->set_mode.media_packet_video_stream) {
5439 LOGE("add data probe at videosink");
5440 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5441 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5443 MMPLAYER_SIGNAL_CONNECT(player,
5444 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5445 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5447 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5450 MMPLAYER_SIGNAL_CONNECT(player,
5451 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5452 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5454 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5459 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5462 LOGD("disable last-sample");
5463 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5473 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5476 if (videobin[MMPLAYER_V_SINK].gst) {
5477 GstPad *sink_pad = NULL;
5478 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5480 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5481 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5482 gst_object_unref(GST_OBJECT(sink_pad));
5484 LOGW("failed to get sink pad from videosink\n");
5487 /* store it as it's sink element */
5488 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5490 /* adding created elements to bin */
5491 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5492 LOGE("failed to add elements\n");
5496 /* Linking elements in the bucket by added order */
5497 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5498 LOGE("failed to link elements\n");
5502 /* get first element's sinkpad for creating ghostpad */
5504 first_element = (MMPlayerGstElement *)element_bucket->data;
5505 if (!first_element) {
5506 LOGE("failed to get first element from bucket\n");
5510 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5512 LOGE("failed to get pad from first element\n");
5516 /* create ghostpad */
5517 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5518 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5519 LOGE("failed to add ghostpad to videobin\n");
5522 gst_object_unref(pad);
5524 /* done. free allocated variables */
5526 g_list_free(element_bucket);
5530 return MM_ERROR_NONE;
5533 LOGE("ERROR : releasing videobin\n");
5535 g_list_free(element_bucket);
5538 gst_object_unref(GST_OBJECT(pad));
5540 /* release videobin with it's childs */
5541 if (videobin[MMPLAYER_V_BIN].gst)
5542 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5545 MMPLAYER_FREEIF(videobin);
5547 player->pipeline->videobin = NULL;
5549 return MM_ERROR_PLAYER_INTERNAL;
5552 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5554 GList *element_bucket = NULL;
5555 MMPlayerGstElement *textbin = player->pipeline->textbin;
5557 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5558 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5559 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5560 "signal-handoffs", FALSE,
5563 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5564 MMPLAYER_SIGNAL_CONNECT(player,
5565 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5566 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5568 G_CALLBACK(__mmplayer_update_subtitle),
5571 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5572 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5573 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5575 if (!player->play_subtitle) {
5576 LOGD("add textbin sink as sink element of whole pipeline.\n");
5577 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5580 /* adding created elements to bin */
5581 LOGD("adding created elements to bin\n");
5582 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5583 LOGE("failed to add elements\n");
5587 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5588 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5589 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5591 /* linking elements in the bucket by added order. */
5592 LOGD("Linking elements in the bucket by added order.\n");
5593 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5594 LOGE("failed to link elements\n");
5598 /* done. free allocated variables */
5599 g_list_free(element_bucket);
5601 if (textbin[MMPLAYER_T_QUEUE].gst) {
5603 GstPad *ghostpad = NULL;
5605 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5607 LOGE("failed to get sink pad of text queue");
5611 ghostpad = gst_ghost_pad_new("text_sink", pad);
5612 gst_object_unref(pad);
5615 LOGE("failed to create ghostpad of textbin\n");
5619 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5620 LOGE("failed to add ghostpad to textbin\n");
5621 gst_object_unref(ghostpad);
5626 return MM_ERROR_NONE;
5629 g_list_free(element_bucket);
5631 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5632 LOGE("remove textbin sink from sink list");
5633 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5636 /* release element at __mmplayer_gst_create_text_sink_bin */
5637 return MM_ERROR_PLAYER_INTERNAL;
5640 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5642 MMPlayerGstElement *textbin = NULL;
5643 GList *element_bucket = NULL;
5644 int surface_type = 0;
5649 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5652 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5654 LOGE("failed to allocate memory for textbin\n");
5655 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5659 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5660 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5661 if (!textbin[MMPLAYER_T_BIN].gst) {
5662 LOGE("failed to create textbin\n");
5667 player->pipeline->textbin = textbin;
5670 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5671 LOGD("surface type for subtitle : %d", surface_type);
5672 switch (surface_type) {
5673 case MM_DISPLAY_SURFACE_OVERLAY:
5674 case MM_DISPLAY_SURFACE_NULL:
5675 case MM_DISPLAY_SURFACE_REMOTE:
5676 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5677 LOGE("failed to make plain text elements\n");
5688 return MM_ERROR_NONE;
5692 LOGD("ERROR : releasing textbin\n");
5694 g_list_free(element_bucket);
5696 /* release signal */
5697 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5699 /* release element which are not added to bin */
5700 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5701 /* NOTE : skip bin */
5702 if (textbin[i].gst) {
5703 GstObject* parent = NULL;
5704 parent = gst_element_get_parent(textbin[i].gst);
5707 gst_object_unref(GST_OBJECT(textbin[i].gst));
5708 textbin[i].gst = NULL;
5710 gst_object_unref(GST_OBJECT(parent));
5715 /* release textbin with it's childs */
5716 if (textbin[MMPLAYER_T_BIN].gst)
5717 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5719 MMPLAYER_FREEIF(player->pipeline->textbin);
5720 player->pipeline->textbin = NULL;
5723 return MM_ERROR_PLAYER_INTERNAL;
5728 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5730 MMPlayerGstElement* mainbin = NULL;
5731 MMPlayerGstElement* textbin = NULL;
5732 MMHandleType attrs = 0;
5733 GstElement *subsrc = NULL;
5734 GstElement *subparse = NULL;
5735 gchar *subtitle_uri = NULL;
5736 const gchar *charset = NULL;
5742 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5744 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5746 mainbin = player->pipeline->mainbin;
5748 attrs = MMPLAYER_GET_ATTRS(player);
5750 LOGE("cannot get content attribute\n");
5751 return MM_ERROR_PLAYER_INTERNAL;
5754 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5755 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5756 LOGE("subtitle uri is not proper filepath.\n");
5757 return MM_ERROR_PLAYER_INVALID_URI;
5760 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5761 LOGE("failed to get storage info of subtitle path");
5762 return MM_ERROR_PLAYER_INVALID_URI;
5765 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5767 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5768 player->subtitle_language_list = NULL;
5769 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5771 /* create the subtitle source */
5772 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5774 LOGE("failed to create filesrc element\n");
5777 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5779 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5780 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5782 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5783 LOGW("failed to add queue\n");
5784 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5785 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5786 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5791 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5793 LOGE("failed to create subparse element\n");
5797 charset = util_get_charset(subtitle_uri);
5799 LOGD("detected charset is %s\n", charset);
5800 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5803 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5804 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5806 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5807 LOGW("failed to add subparse\n");
5808 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5809 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5810 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5814 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5815 LOGW("failed to link subsrc and subparse\n");
5819 player->play_subtitle = TRUE;
5820 player->adjust_subtitle_pos = 0;
5822 LOGD("play subtitle using subtitle file\n");
5824 if (player->pipeline->textbin == NULL) {
5825 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5826 LOGE("failed to create text sink bin. continuing without text\n");
5830 textbin = player->pipeline->textbin;
5832 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5833 LOGW("failed to add textbin\n");
5835 /* release signal */
5836 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5838 /* release textbin with it's childs */
5839 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5840 MMPLAYER_FREEIF(player->pipeline->textbin);
5841 player->pipeline->textbin = textbin = NULL;
5845 LOGD("link text input selector and textbin ghost pad");
5847 player->textsink_linked = 1;
5848 player->external_text_idx = 0;
5849 LOGI("player->textsink_linked set to 1\n");
5851 textbin = player->pipeline->textbin;
5852 LOGD("text bin has been created. reuse it.");
5853 player->external_text_idx = 1;
5856 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5857 LOGW("failed to link subparse and textbin\n");
5861 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5863 LOGE("failed to get sink pad from textsink to probe data");
5867 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5868 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5870 gst_object_unref(pad);
5873 /* create dot. for debugging */
5874 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5877 return MM_ERROR_NONE;
5880 /* release text pipeline resource */
5881 player->textsink_linked = 0;
5883 /* release signal */
5884 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5886 if (player->pipeline->textbin) {
5887 LOGE("remove textbin");
5889 /* release textbin with it's childs */
5890 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5891 MMPLAYER_FREEIF(player->pipeline->textbin);
5892 player->pipeline->textbin = NULL;
5896 /* release subtitle elem */
5897 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5898 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5900 return MM_ERROR_PLAYER_INTERNAL;
5904 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5906 mm_player_t* player = (mm_player_t*) data;
5907 MMMessageParamType msg = {0, };
5908 GstClockTime duration = 0;
5909 gpointer text = NULL;
5910 guint text_size = 0;
5911 gboolean ret = TRUE;
5912 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5916 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5917 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5919 if (player->is_subtitle_force_drop) {
5920 LOGW("subtitle is dropped forcedly.");
5924 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5925 text = mapinfo.data;
5926 text_size = mapinfo.size;
5927 duration = GST_BUFFER_DURATION(buffer);
5929 if (player->set_mode.subtitle_off) {
5930 LOGD("subtitle is OFF.\n");
5934 if (!text || (text_size == 0)) {
5935 LOGD("There is no subtitle to be displayed.\n");
5939 msg.data = (void *) text;
5940 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5942 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5944 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5945 gst_buffer_unmap(buffer, &mapinfo);
5952 static GstPadProbeReturn
5953 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5955 mm_player_t *player = (mm_player_t *) u_data;
5956 GstClockTime cur_timestamp = 0;
5957 gint64 adjusted_timestamp = 0;
5958 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5960 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5962 if (player->set_mode.subtitle_off) {
5963 LOGD("subtitle is OFF.\n");
5967 if (player->adjust_subtitle_pos == 0) {
5968 LOGD("nothing to do");
5972 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5973 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5975 if (adjusted_timestamp < 0) {
5976 LOGD("adjusted_timestamp under zero");
5981 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5982 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5983 GST_TIME_ARGS(cur_timestamp),
5984 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5986 return GST_PAD_PROBE_OK;
5988 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5992 /* check player and subtitlebin are created */
5993 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5994 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5996 if (position == 0) {
5997 LOGD("nothing to do\n");
5999 return MM_ERROR_NONE;
6003 case MM_PLAYER_POS_FORMAT_TIME:
6005 /* check current postion */
6006 player->adjust_subtitle_pos = position;
6008 LOGD("save adjust_subtitle_pos in player") ;
6014 LOGW("invalid format.\n");
6016 return MM_ERROR_INVALID_ARGUMENT;
6022 return MM_ERROR_NONE;
6026 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6028 GstElement *appsrc = element;
6029 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6030 GstBuffer *buffer = NULL;
6031 GstFlowReturn ret = GST_FLOW_OK;
6034 MMPLAYER_RETURN_IF_FAIL(element);
6035 MMPLAYER_RETURN_IF_FAIL(buf);
6037 buffer = gst_buffer_new();
6039 if (buf->offset >= buf->len) {
6040 LOGD("call eos appsrc\n");
6041 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6045 if (buf->len - buf->offset < size)
6046 len = buf->len - buf->offset;
6048 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6049 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6050 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6052 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6053 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6059 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6061 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6063 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6065 buf->offset = (int)size;
6070 static GstBusSyncReply
6071 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6073 mm_player_t *player = (mm_player_t *)data;
6074 GstBusSyncReply reply = GST_BUS_DROP;
6076 if (!(player->pipeline && player->pipeline->mainbin)) {
6077 LOGE("player pipeline handle is null");
6078 return GST_BUS_PASS;
6081 if (!__mmplayer_check_useful_message(player, message)) {
6082 gst_message_unref(message);
6083 return GST_BUS_DROP;
6086 switch (GST_MESSAGE_TYPE(message)) {
6087 case GST_MESSAGE_STATE_CHANGED:
6088 /* post directly for fast launch */
6089 if (player->sync_handler) {
6090 __mmplayer_gst_callback(message, player);
6091 reply = GST_BUS_DROP;
6093 reply = GST_BUS_PASS;
6095 case GST_MESSAGE_TAG:
6096 __mmplayer_gst_extract_tag_from_msg(player, message);
6100 GstTagList *tags = NULL;
6102 gst_message_parse_tag(message, &tags);
6104 LOGE("TAGS received from element \"%s\".\n",
6105 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6107 gst_tag_list_foreach(tags, print_tag, NULL);
6108 gst_tag_list_free(tags);
6116 case GST_MESSAGE_DURATION_CHANGED:
6117 __mmplayer_gst_handle_duration(player, message);
6119 case GST_MESSAGE_ASYNC_DONE:
6120 /* NOTE:Don't call gst_callback directly
6121 * because previous frame can be showed even though this message is received for seek.
6124 reply = GST_BUS_PASS;
6128 if (reply == GST_BUS_DROP)
6129 gst_message_unref(message);
6135 __mmplayer_gst_create_decoder(mm_player_t *player,
6136 MMPlayerTrackType track,
6138 enum MainElementID elemId,
6141 gboolean ret = TRUE;
6142 GstPad *sinkpad = NULL;
6146 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6148 player->pipeline->mainbin, FALSE);
6149 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6150 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6151 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6153 GstElement *decodebin = NULL;
6154 GstCaps *dec_caps = NULL;
6156 /* create decodebin */
6157 decodebin = gst_element_factory_make("decodebin", name);
6160 LOGE("error : fail to create decodebin for %d decoder\n", track);
6165 /* raw pad handling signal */
6166 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6167 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6169 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6170 before looking for any elements that can handle that stream.*/
6171 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6172 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6174 /* This signal is emitted when a element is added to the bin.*/
6175 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6176 G_CALLBACK(__mmplayer_gst_element_added), player);
6178 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6179 LOGE("failed to add new decodebin\n");
6184 dec_caps = gst_pad_query_caps(srcpad, NULL);
6186 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6187 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6188 gst_caps_unref(dec_caps);
6191 player->pipeline->mainbin[elemId].id = elemId;
6192 player->pipeline->mainbin[elemId].gst = decodebin;
6194 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6196 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6197 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6198 gst_object_unref(GST_OBJECT(decodebin));
6201 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6202 LOGE("failed to sync second level decodebin state with parent\n");
6204 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6208 gst_object_unref(GST_OBJECT(sinkpad));
6217 * This function is to create audio or video pipeline for playing.
6219 * @param player [in] handle of player
6221 * @return This function returns zero on success.
6226 __mmplayer_gst_create_pipeline(mm_player_t* player)
6229 MMPlayerGstElement *mainbin = NULL;
6230 MMHandleType attrs = 0;
6231 GstElement* element = NULL;
6232 GstElement* elem_src_audio = NULL;
6233 GstElement* elem_src_subtitle = NULL;
6234 GstElement* es_video_queue = NULL;
6235 GstElement* es_audio_queue = NULL;
6236 GstElement* es_subtitle_queue = NULL;
6237 GList* element_bucket = NULL;
6238 gboolean need_state_holder = TRUE;
6240 #ifdef SW_CODEC_ONLY
6241 int surface_type = 0;
6245 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6247 /* get profile attribute */
6248 attrs = MMPLAYER_GET_ATTRS(player);
6250 LOGE("cannot get content attribute\n");
6254 /* create pipeline handles */
6255 if (player->pipeline) {
6256 LOGW("pipeline should be released before create new one\n");
6260 player->video360_metadata.is_spherical = -1;
6261 player->is_openal_plugin_used = FALSE;
6263 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6264 if (player->pipeline == NULL)
6267 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6269 /* create mainbin */
6270 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6271 if (mainbin == NULL)
6274 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6276 /* create pipeline */
6277 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6278 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6279 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6280 LOGE("failed to create pipeline\n");
6283 player->demux_pad_index = 0;
6284 player->subtitle_language_list = NULL;
6286 player->is_subtitle_force_drop = FALSE;
6287 player->last_multiwin_status = FALSE;
6289 _mmplayer_track_initialize(player);
6290 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6292 /* create source element */
6293 switch (player->profile.uri_type) {
6294 /* rtsp streamming */
6295 case MM_PLAYER_URI_TYPE_URL_RTSP:
6299 element = gst_element_factory_make("rtspsrc", "rtsp source");
6302 LOGE("failed to create streaming source element\n");
6310 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6312 SECURE_LOGD("user_agent : %s\n", user_agent);
6314 /* setting property to streaming source */
6315 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6317 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6319 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6320 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6321 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6322 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6327 case MM_PLAYER_URI_TYPE_URL_HTTP:
6329 gchar *user_agent, *cookies, **cookie_list;
6330 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6331 user_agent = cookies = NULL;
6333 gint mode = MM_PLAYER_PD_MODE_NONE;
6335 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6337 player->pd_mode = mode;
6339 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6341 if (!MMPLAYER_IS_HTTP_PD(player)) {
6342 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6344 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6347 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6350 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6351 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6353 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6354 LOGD("get timeout from ini\n");
6355 http_timeout = player->ini.http_timeout;
6359 SECURE_LOGD("location : %s\n", player->profile.uri);
6360 SECURE_LOGD("cookies : %s\n", cookies);
6361 SECURE_LOGD("user_agent : %s\n", user_agent);
6362 LOGD("timeout : %d\n", http_timeout);
6364 /* setting property to streaming source */
6365 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6366 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6367 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6369 /* parsing cookies */
6370 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6371 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6372 g_strfreev(cookie_list);
6375 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6377 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6378 LOGW("it's dash. and it's still experimental feature.");
6380 // progressive download
6381 gchar* location = NULL;
6383 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6386 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6388 MMPLAYER_FREEIF(player->pd_file_save_path);
6390 LOGD("PD Location : %s\n", path);
6393 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6394 LOGE("failed to get storage info");
6397 player->pd_file_save_path = g_strdup(path);
6399 LOGE("can't find pd location so, it should be set \n");
6404 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6406 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6410 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6411 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6413 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6414 g_object_get(element, "location", &location, NULL);
6415 LOGD("PD_LOCATION [%s].\n", location);
6423 case MM_PLAYER_URI_TYPE_FILE:
6425 LOGD("using filesrc for 'file://' handler.\n");
6426 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6427 LOGE("failed to get storage info");
6431 element = gst_element_factory_make("filesrc", "source");
6433 LOGE("failed to create filesrc\n");
6437 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6441 case MM_PLAYER_URI_TYPE_SS:
6443 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6444 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6446 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6450 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6451 LOGD("get timeout from ini\n");
6452 http_timeout = player->ini.http_timeout;
6455 /* setting property to streaming source */
6456 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6457 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6460 case MM_PLAYER_URI_TYPE_MS_BUFF:
6462 LOGD("MS buff src is selected\n");
6464 if (player->v_stream_caps) {
6465 element = gst_element_factory_make("appsrc", "video_appsrc");
6467 LOGF("failed to create video app source element[appsrc].\n");
6471 if (player->a_stream_caps) {
6472 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6473 if (!elem_src_audio) {
6474 LOGF("failed to create audio app source element[appsrc].\n");
6478 } else if (player->a_stream_caps) {
6479 /* no video, only audio pipeline*/
6480 element = gst_element_factory_make("appsrc", "audio_appsrc");
6482 LOGF("failed to create audio app source element[appsrc].\n");
6487 if (player->s_stream_caps) {
6488 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6489 if (!elem_src_subtitle) {
6490 LOGF("failed to create subtitle app source element[appsrc].\n");
6495 LOGD("setting app sources properties.\n");
6496 LOGD("location : %s\n", player->profile.uri);
6498 if (player->v_stream_caps && element) {
6499 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6500 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6501 "caps", player->v_stream_caps, NULL);
6503 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6504 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6505 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6506 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6508 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6509 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6510 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6511 G_CALLBACK(__gst_seek_video_data), player);
6513 if (player->a_stream_caps && elem_src_audio) {
6514 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6515 "caps", player->a_stream_caps, NULL);
6517 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6518 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6519 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6520 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6522 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6523 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6524 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6525 G_CALLBACK(__gst_seek_audio_data), player);
6527 } else if (player->a_stream_caps && element) {
6528 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6529 "caps", player->a_stream_caps, NULL);
6531 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6532 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6533 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6534 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6536 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6537 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6538 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6539 G_CALLBACK(__gst_seek_audio_data), player);
6542 if (player->s_stream_caps && elem_src_subtitle) {
6543 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6544 "caps", player->s_stream_caps, NULL);
6546 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6547 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6548 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6549 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6551 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6553 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6554 G_CALLBACK(__gst_seek_subtitle_data), player);
6557 if (player->v_stream_caps && element) {
6558 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6559 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6560 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6561 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6563 if (player->a_stream_caps && elem_src_audio) {
6564 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6565 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6566 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6567 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6569 } else if (player->a_stream_caps && element) {
6570 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6571 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6572 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6573 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6576 if (player->s_stream_caps && elem_src_subtitle)
6577 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6578 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6580 need_state_holder = FALSE;
6582 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6583 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6584 LOGE("failed to commit\n");
6588 case MM_PLAYER_URI_TYPE_MEM:
6590 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6592 LOGD("mem src is selected\n");
6594 element = gst_element_factory_make("appsrc", "mem-source");
6596 LOGE("failed to create appsrc element\n");
6600 g_object_set(element, "stream-type", stream_type, NULL);
6601 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6602 g_object_set(element, "blocksize", (guint64)20480, NULL);
6604 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6605 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6606 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6607 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6610 case MM_PLAYER_URI_TYPE_URL:
6613 case MM_PLAYER_URI_TYPE_TEMP:
6616 case MM_PLAYER_URI_TYPE_NONE:
6621 /* check source element is OK */
6623 LOGE("no source element was created.\n");
6627 /* take source element */
6628 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6629 mainbin[MMPLAYER_M_SRC].gst = element;
6630 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6632 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6633 player->streamer = __mm_player_streaming_create();
6634 __mm_player_streaming_initialize(player->streamer);
6637 if (MMPLAYER_IS_HTTP_PD(player)) {
6638 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6640 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6641 element = gst_element_factory_make("queue2", "queue2");
6643 LOGE("failed to create http streaming buffer element\n");
6648 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6649 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6650 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6652 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6654 player->streamer->is_pd_mode = TRUE;
6656 __mm_player_streaming_set_queue2(player->streamer,
6659 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6662 player->ini.http_buffering_limit,
6663 MUXED_BUFFER_TYPE_MEM_QUEUE,
6667 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6668 if (player->v_stream_caps) {
6669 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6670 if (!es_video_queue) {
6671 LOGE("create es_video_queue for es player failed\n");
6674 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6675 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6676 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6677 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6679 /* Adding audio appsrc to bucket */
6680 if (player->a_stream_caps && elem_src_audio) {
6681 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6682 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6683 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6685 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6686 if (!es_audio_queue) {
6687 LOGE("create es_audio_queue for es player failed\n");
6690 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6692 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6693 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6694 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6696 } else if (player->a_stream_caps) {
6697 /* Only audio stream, no video */
6698 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6699 if (!es_audio_queue) {
6700 LOGE("create es_audio_queue for es player failed\n");
6703 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6704 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6705 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6708 if (player->s_stream_caps && elem_src_subtitle) {
6709 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6710 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6711 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6713 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6714 if (!es_subtitle_queue) {
6715 LOGE("create es_subtitle_queue for es player failed\n");
6718 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6719 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6720 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6724 /* create autoplugging element if src element is not a rtsp src */
6725 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6726 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6728 enum MainElementID elemId = MMPLAYER_M_NUM;
6730 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6731 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6732 elemId = MMPLAYER_M_AUTOPLUG;
6733 element = __mmplayer_create_decodebin(player);
6735 /* default size of mq in decodebin is 2M
6736 * but it can cause blocking issue during seeking depends on content. */
6737 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6739 need_state_holder = FALSE;
6741 elemId = MMPLAYER_M_TYPEFIND;
6742 element = gst_element_factory_make("typefind", "typefinder");
6743 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6744 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6748 /* check autoplug element is OK */
6750 LOGE("can not create element(%d)\n", elemId);
6754 mainbin[elemId].id = elemId;
6755 mainbin[elemId].gst = element;
6757 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6760 /* add elements to pipeline */
6761 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6762 LOGE("Failed to add elements to pipeline\n");
6767 /* linking elements in the bucket by added order. */
6768 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6769 LOGE("Failed to link some elements\n");
6774 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6775 if (need_state_holder) {
6777 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6778 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6780 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6781 LOGE("fakesink element could not be created\n");
6784 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6786 /* take ownership of fakesink. we are reusing it */
6787 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6790 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6791 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6792 LOGE("failed to add fakesink to bin\n");
6797 /* now we have completed mainbin. take it */
6798 player->pipeline->mainbin = mainbin;
6800 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6801 GstPad *srcpad = NULL;
6803 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6804 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6806 __mmplayer_gst_create_decoder(player,
6807 MM_PLAYER_TRACK_TYPE_VIDEO,
6809 MMPLAYER_M_AUTOPLUG_V_DEC,
6812 gst_object_unref(GST_OBJECT(srcpad));
6817 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6818 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6820 __mmplayer_gst_create_decoder(player,
6821 MM_PLAYER_TRACK_TYPE_AUDIO,
6823 MMPLAYER_M_AUTOPLUG_A_DEC,
6826 gst_object_unref(GST_OBJECT(srcpad));
6831 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6832 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6835 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6836 if (__mmplayer_check_subtitle(player)) {
6837 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6838 LOGE("fail to create text pipeline");
6841 /* connect bus callback */
6842 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6844 LOGE("cannot get bus from pipeline.\n");
6848 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6850 player->context.thread_default = g_main_context_get_thread_default();
6852 if (player->context.thread_default == NULL) {
6853 player->context.thread_default = g_main_context_default();
6854 LOGD("thread-default context is the global default context");
6856 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6858 /* set sync handler to get tag synchronously */
6859 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6862 gst_object_unref(GST_OBJECT(bus));
6863 g_list_free(element_bucket);
6865 /* create gst bus_msb_cb thread */
6866 g_mutex_init(&player->bus_msg_thread_mutex);
6867 g_cond_init(&player->bus_msg_thread_cond);
6868 player->bus_msg_thread_exit = FALSE;
6869 player->bus_msg_thread =
6870 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6871 if (!player->bus_msg_thread) {
6872 LOGE("failed to create gst BUS msg thread");
6873 g_mutex_clear(&player->bus_msg_thread_mutex);
6874 g_cond_clear(&player->bus_msg_thread_cond);
6880 return MM_ERROR_NONE;
6883 __mmplayer_gst_destroy_pipeline(player);
6884 g_list_free(element_bucket);
6887 /* release element which are not added to bin */
6888 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6889 /* NOTE : skip pipeline */
6890 if (mainbin[i].gst) {
6891 GstObject* parent = NULL;
6892 parent = gst_element_get_parent(mainbin[i].gst);
6895 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6896 mainbin[i].gst = NULL;
6898 gst_object_unref(GST_OBJECT(parent));
6902 /* release pipeline with it's childs */
6903 if (mainbin[MMPLAYER_M_PIPE].gst)
6904 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6906 MMPLAYER_FREEIF(mainbin);
6909 MMPLAYER_FREEIF(player->pipeline);
6910 return MM_ERROR_PLAYER_INTERNAL;
6914 __mmplayer_reset_gapless_state(mm_player_t* player)
6917 MMPLAYER_RETURN_IF_FAIL(player
6919 && player->pipeline->audiobin
6920 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6922 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6929 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6932 int ret = MM_ERROR_NONE;
6936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6938 /* cleanup stuffs */
6939 MMPLAYER_FREEIF(player->type);
6940 player->have_dynamic_pad = FALSE;
6941 player->no_more_pad = FALSE;
6942 player->num_dynamic_pad = 0;
6943 player->demux_pad_index = 0;
6944 player->use_deinterleave = FALSE;
6945 player->max_audio_channels = 0;
6946 player->video_share_api_delta = 0;
6947 player->video_share_clock_delta = 0;
6948 player->video_hub_download_mode = 0;
6950 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6951 player->subtitle_language_list = NULL;
6952 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6954 __mmplayer_reset_gapless_state(player);
6956 if (player->streamer) {
6957 __mm_player_streaming_deinitialize(player->streamer);
6958 __mm_player_streaming_destroy(player->streamer);
6959 player->streamer = NULL;
6962 /* cleanup unlinked mime type */
6963 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6964 MMPLAYER_FREEIF(player->unlinked_video_mime);
6965 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6967 /* cleanup running stuffs */
6968 __mmplayer_cancel_eos_timer(player);
6970 /* cleanup gst stuffs */
6971 if (player->pipeline) {
6972 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6973 GstTagList* tag_list = player->pipeline->tag_list;
6975 /* first we need to disconnect all signal hander */
6976 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6979 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6980 MMPlayerGstElement* videobin = player->pipeline->videobin;
6981 MMPlayerGstElement* textbin = player->pipeline->textbin;
6982 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6983 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6984 gst_object_unref(bus);
6986 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6987 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6988 if (ret != MM_ERROR_NONE) {
6989 LOGE("fail to change state to NULL\n");
6990 return MM_ERROR_PLAYER_INTERNAL;
6993 LOGW("succeeded in chaning state to NULL\n");
6995 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6998 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6999 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7001 /* free avsysaudiosink
7002 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7003 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7005 MMPLAYER_FREEIF(audiobin);
7006 MMPLAYER_FREEIF(videobin);
7007 MMPLAYER_FREEIF(textbin);
7008 MMPLAYER_FREEIF(mainbin);
7012 gst_tag_list_free(tag_list);
7014 MMPLAYER_FREEIF(player->pipeline);
7016 MMPLAYER_FREEIF(player->album_art);
7018 if (player->v_stream_caps) {
7019 gst_caps_unref(player->v_stream_caps);
7020 player->v_stream_caps = NULL;
7022 if (player->a_stream_caps) {
7023 gst_caps_unref(player->a_stream_caps);
7024 player->a_stream_caps = NULL;
7027 if (player->s_stream_caps) {
7028 gst_caps_unref(player->s_stream_caps);
7029 player->s_stream_caps = NULL;
7031 _mmplayer_track_destroy(player);
7033 if (player->sink_elements)
7034 g_list_free(player->sink_elements);
7035 player->sink_elements = NULL;
7037 if (player->bufmgr) {
7038 tbm_bufmgr_deinit(player->bufmgr);
7039 player->bufmgr = NULL;
7042 LOGW("finished destroy pipeline\n");
7049 static int __gst_realize(mm_player_t* player)
7052 int ret = MM_ERROR_NONE;
7056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7058 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7060 ret = __mmplayer_gst_create_pipeline(player);
7062 LOGE("failed to create pipeline\n");
7066 /* set pipeline state to READY */
7067 /* NOTE : state change to READY must be performed sync. */
7068 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7069 ret = __mmplayer_gst_set_state(player,
7070 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7072 if (ret != MM_ERROR_NONE) {
7073 /* return error if failed to set state */
7074 LOGE("failed to set READY state");
7078 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7080 /* create dot before error-return. for debugging */
7081 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7088 static int __gst_unrealize(mm_player_t* player)
7090 int ret = MM_ERROR_NONE;
7094 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7096 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7097 MMPLAYER_PRINT_STATE(player);
7099 /* release miscellaneous information */
7100 __mmplayer_release_misc(player);
7102 /* destroy pipeline */
7103 ret = __mmplayer_gst_destroy_pipeline(player);
7104 if (ret != MM_ERROR_NONE) {
7105 LOGE("failed to destory pipeline\n");
7109 /* release miscellaneous information.
7110 these info needs to be released after pipeline is destroyed. */
7111 __mmplayer_release_misc_post(player);
7113 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7120 static int __gst_pending_seek(mm_player_t* player)
7122 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7123 int ret = MM_ERROR_NONE;
7127 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7129 if (!player->pending_seek.is_pending) {
7130 LOGD("pending seek is not reserved. nothing to do.\n");
7134 /* check player state if player could pending seek or not. */
7135 current_state = MMPLAYER_CURRENT_STATE(player);
7137 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7138 LOGW("try to pending seek in %s state, try next time. \n",
7139 MMPLAYER_STATE_GET_NAME(current_state));
7143 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7145 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7147 if (MM_ERROR_NONE != ret)
7148 LOGE("failed to seek pending postion. just keep staying current position.\n");
7150 player->pending_seek.is_pending = FALSE;
7157 static int __gst_start(mm_player_t* player)
7159 gboolean sound_extraction = 0;
7160 int ret = MM_ERROR_NONE;
7161 gboolean async = FALSE;
7165 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7167 /* get sound_extraction property */
7168 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7170 /* NOTE : if SetPosition was called before Start. do it now */
7171 /* streaming doesn't support it. so it should be always sync */
7172 /* !!create one more api to check if there is pending seek rather than checking variables */
7173 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7174 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7175 ret = __gst_pause(player, FALSE);
7176 if (ret != MM_ERROR_NONE) {
7177 LOGE("failed to set state to PAUSED for pending seek\n");
7181 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7183 if (sound_extraction) {
7184 LOGD("setting pcm extraction\n");
7186 ret = __mmplayer_set_pcm_extraction(player);
7187 if (MM_ERROR_NONE != ret) {
7188 LOGW("failed to set pcm extraction\n");
7192 if (MM_ERROR_NONE != __gst_pending_seek(player))
7193 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7197 LOGD("current state before doing transition");
7198 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7199 MMPLAYER_PRINT_STATE(player);
7201 /* set pipeline state to PLAYING */
7202 if (player->es_player_push_mode)
7204 /* set pipeline state to PLAYING */
7205 ret = __mmplayer_gst_set_state(player,
7206 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7208 if (ret == MM_ERROR_NONE) {
7209 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7211 LOGE("failed to set state to PLAYING");
7215 /* generating debug info before returning error */
7216 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7223 static int __gst_stop(mm_player_t* player)
7225 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7226 MMHandleType attrs = 0;
7227 gboolean rewind = FALSE;
7229 int ret = MM_ERROR_NONE;
7230 gboolean async = FALSE;
7234 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7235 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7237 LOGD("current state before doing transition");
7238 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7239 MMPLAYER_PRINT_STATE(player);
7241 attrs = MMPLAYER_GET_ATTRS(player);
7243 LOGE("cannot get content attribute\n");
7244 return MM_ERROR_PLAYER_INTERNAL;
7247 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7248 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7250 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7251 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7254 if (player->es_player_push_mode)
7257 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7259 /* return if set_state has failed */
7260 if (ret != MM_ERROR_NONE) {
7261 LOGE("failed to set state.\n");
7267 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7268 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7269 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7270 LOGW("failed to rewind\n");
7271 ret = MM_ERROR_PLAYER_SEEK;
7276 player->sent_bos = FALSE;
7278 if (player->es_player_push_mode) //for cloudgame
7281 /* wait for seek to complete */
7282 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7283 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7284 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7286 LOGE("fail to stop player.\n");
7287 ret = MM_ERROR_PLAYER_INTERNAL;
7288 __mmplayer_dump_pipeline_state(player);
7291 /* generate dot file if enabled */
7292 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7299 int __gst_pause(mm_player_t* player, gboolean async)
7301 int ret = MM_ERROR_NONE;
7305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7306 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7308 LOGD("current state before doing transition");
7309 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7310 MMPLAYER_PRINT_STATE(player);
7312 /* set pipeline status to PAUSED */
7313 ret = __mmplayer_gst_set_state(player,
7314 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7316 if (FALSE == async) {
7317 if (ret != MM_ERROR_NONE) {
7318 GstMessage *msg = NULL;
7319 GTimer *timer = NULL;
7320 gdouble MAX_TIMEOUT_SEC = 3;
7322 LOGE("failed to set state to PAUSED");
7324 if (player->msg_posted) {
7325 LOGE("error msg is already posted.");
7329 timer = g_timer_new();
7330 g_timer_start(timer);
7332 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7335 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7337 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7338 GError *error = NULL;
7340 /* parse error code */
7341 gst_message_parse_error(msg, &error, NULL);
7343 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7344 /* Note : the streaming error from the streaming source is handled
7345 * using __mmplayer_handle_streaming_error.
7347 __mmplayer_handle_streaming_error(player, msg);
7350 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7352 if (error->domain == GST_STREAM_ERROR)
7353 ret = __gst_handle_stream_error(player, error, msg);
7354 else if (error->domain == GST_RESOURCE_ERROR)
7355 ret = __gst_handle_resource_error(player, error->code, NULL);
7356 else if (error->domain == GST_LIBRARY_ERROR)
7357 ret = __gst_handle_library_error(player, error->code);
7358 else if (error->domain == GST_CORE_ERROR)
7359 ret = __gst_handle_core_error(player, error->code);
7361 g_error_free(error);
7363 player->msg_posted = TRUE;
7365 gst_message_unref(msg);
7367 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7369 gst_object_unref(bus);
7370 g_timer_stop(timer);
7371 g_timer_destroy(timer);
7375 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7376 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7378 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7380 } else if (ret == MM_ERROR_NONE) {
7382 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7386 /* generate dot file before returning error */
7387 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7394 int __gst_resume(mm_player_t* player, gboolean async)
7396 int ret = MM_ERROR_NONE;
7401 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7402 MM_ERROR_PLAYER_NOT_INITIALIZED);
7404 LOGD("current state before doing transition");
7405 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7406 MMPLAYER_PRINT_STATE(player);
7408 /* generate dot file before returning error */
7409 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7412 LOGD("do async state transition to PLAYING.\n");
7414 /* set pipeline state to PLAYING */
7415 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7417 ret = __mmplayer_gst_set_state(player,
7418 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7419 if (ret != MM_ERROR_NONE) {
7420 LOGE("failed to set state to PLAYING\n");
7423 if (async == FALSE) {
7424 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7425 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7426 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7430 /* generate dot file before returning error */
7431 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7439 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7441 gint64 dur_nsec = 0;
7442 gint64 pos_nsec = 0;
7443 gboolean ret = TRUE;
7444 gboolean accurated = FALSE;
7445 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7449 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7451 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7452 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7455 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7456 /* check duration */
7457 /* NOTE : duration cannot be zero except live streaming.
7458 * Since some element could have some timing problemn with quering duration, try again.
7460 if (player->duration == 0) {
7461 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7462 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7463 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7464 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7465 player->pending_seek.is_pending = TRUE;
7466 player->pending_seek.format = format;
7467 player->pending_seek.pos = position;
7468 player->doing_seek = FALSE;
7469 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7470 return MM_ERROR_NONE;
7475 player->duration = dur_nsec;
7478 LOGD("playback rate: %f\n", player->playback_rate);
7480 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7482 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7484 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7488 case MM_PLAYER_POS_FORMAT_TIME:
7490 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7491 GstQuery *query = NULL;
7492 gboolean seekable = FALSE;
7494 /* check position is valid or not */
7495 if (position > player->duration)
7498 query = gst_query_new_seeking(GST_FORMAT_TIME);
7499 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7500 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7501 gst_query_unref(query);
7504 LOGW("non-seekable content");
7505 player->doing_seek = FALSE;
7506 return MM_ERROR_PLAYER_NO_OP;
7509 LOGW("failed to get seeking query");
7510 gst_query_unref(query); /* keep seeking operation */
7513 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7515 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7516 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7517 This causes problem is position calculation during normal pause resume scenarios also.
7518 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7519 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7520 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7521 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7522 LOGW("getting current position failed in seek\n");
7524 player->last_position = pos_nsec;
7525 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7528 if (player->doing_seek) {
7529 LOGD("not completed seek");
7530 return MM_ERROR_PLAYER_DOING_SEEK;
7534 if (!internal_called)
7535 player->doing_seek = TRUE;
7537 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7538 gint64 cur_time = 0;
7540 /* get current position */
7541 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7544 GstEvent *event = gst_event_new_seek(1.0,
7546 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7547 GST_SEEK_TYPE_SET, cur_time,
7548 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7550 __gst_send_event_to_sink(player, event);
7552 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7553 __gst_pause(player, FALSE);
7556 pos_nsec = position;
7558 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7559 that's why set position through property. */
7560 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7561 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7562 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7563 (!player->videodec_linked) && (!player->audiodec_linked)) {
7565 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7566 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7567 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7568 player->doing_seek = FALSE;
7569 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7571 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7572 GST_FORMAT_TIME, seek_flags,
7573 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7577 LOGE("failed to set position.");
7583 case MM_PLAYER_POS_FORMAT_PERCENT:
7585 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7587 if (player->doing_seek) {
7588 LOGD("not completed seek");
7589 return MM_ERROR_PLAYER_DOING_SEEK;
7592 if (!internal_called)
7593 player->doing_seek = TRUE;
7595 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7596 pos_nsec = (gint64)((position * player->duration) / 100);
7597 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7598 GST_FORMAT_TIME, seek_flags,
7599 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7601 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7611 /* NOTE : store last seeking point to overcome some bad operation
7612 * (returning zero when getting current position) of some elements
7614 player->last_position = pos_nsec;
7616 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7617 if (player->playback_rate > 1.0)
7618 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7621 return MM_ERROR_NONE;
7624 player->pending_seek.is_pending = TRUE;
7625 player->pending_seek.format = format;
7626 player->pending_seek.pos = position;
7628 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7629 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7630 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7631 player->pending_seek.pos);
7633 return MM_ERROR_NONE;
7636 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7637 return MM_ERROR_INVALID_ARGUMENT;
7640 player->doing_seek = FALSE;
7641 return MM_ERROR_PLAYER_SEEK;
7644 #define TRICKPLAY_OFFSET GST_MSECOND
7647 __gst_get_position(mm_player_t* player, int format, gint64* position)
7649 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7650 gint64 pos_nsec = 0;
7651 gboolean ret = TRUE;
7653 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7654 MM_ERROR_PLAYER_NOT_INITIALIZED);
7656 current_state = MMPLAYER_CURRENT_STATE(player);
7658 /* NOTE : query position except paused state to overcome some bad operation
7659 * please refer to below comments in details
7661 if (current_state != MM_PLAYER_STATE_PAUSED)
7662 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7664 /* NOTE : get last point to overcome some bad operation of some elements
7665 *(returning zero when getting current position in paused state
7666 * and when failed to get postion during seeking
7668 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7669 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7671 if (player->playback_rate < 0.0)
7672 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7674 pos_nsec = player->last_position;
7677 pos_nsec = player->last_position;
7679 player->last_position = pos_nsec;
7681 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7684 if (player->duration > 0 && pos_nsec > player->duration)
7685 pos_nsec = player->duration;
7687 player->last_position = pos_nsec;
7691 case MM_PLAYER_POS_FORMAT_TIME:
7692 *position = pos_nsec;
7695 case MM_PLAYER_POS_FORMAT_PERCENT:
7697 if (player->duration <= 0) {
7698 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7701 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7702 *position = (gint64)(pos_nsec * 100 / player->duration);
7707 return MM_ERROR_PLAYER_INTERNAL;
7710 return MM_ERROR_NONE;
7714 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7716 #define STREAMING_IS_FINISHED 0
7717 #define BUFFERING_MAX_PER 100
7718 #define DEFAULT_PER_VALUE -1
7719 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7721 MMPlayerGstElement *mainbin = NULL;
7722 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7723 gint64 buffered_total = 0;
7724 gint64 position = 0;
7725 gint buffered_sec = -1;
7726 GstBufferingMode mode = GST_BUFFERING_STREAM;
7727 gint64 content_size_time = player->duration;
7728 guint64 content_size_bytes = player->http_content_size;
7730 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7732 player->pipeline->mainbin,
7733 MM_ERROR_PLAYER_NOT_INITIALIZED);
7735 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7740 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7741 /* and rtsp is not ready yet. */
7742 LOGW("it's only used for http streaming case.\n");
7743 return MM_ERROR_PLAYER_NO_OP;
7746 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7747 LOGW("Time format is not supported yet.\n");
7748 return MM_ERROR_INVALID_ARGUMENT;
7751 if (content_size_time <= 0 || content_size_bytes <= 0) {
7752 LOGW("there is no content size.");
7753 return MM_ERROR_NONE;
7756 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7757 LOGW("fail to get current position.");
7758 return MM_ERROR_NONE;
7761 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7762 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7764 mainbin = player->pipeline->mainbin;
7765 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7767 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7768 GstQuery *query = NULL;
7769 gint byte_in_rate = 0, byte_out_rate = 0;
7770 gint64 estimated_total = 0;
7772 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7773 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7774 LOGW("fail to get buffering query from queue2");
7776 gst_query_unref(query);
7777 return MM_ERROR_NONE;
7780 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7781 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7783 if (mode == GST_BUFFERING_STREAM) {
7784 /* using only queue in case of push mode(ts / mp3) */
7785 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7786 GST_FORMAT_BYTES, &buffered_total)) {
7787 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7788 stop_per = 100 * buffered_total / content_size_bytes;
7791 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7793 guint num_of_ranges = 0;
7794 gint64 start_byte = 0, stop_byte = 0;
7796 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7797 if (estimated_total != STREAMING_IS_FINISHED) {
7798 /* buffered size info from queue2 */
7799 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7800 for (idx = 0; idx < num_of_ranges; idx++) {
7801 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7802 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7804 buffered_total += (stop_byte - start_byte);
7807 stop_per = BUFFERING_MAX_PER;
7809 gst_query_unref(query);
7812 if (stop_per == DEFAULT_PER_VALUE) {
7813 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7815 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7817 /* buffered size info from multiqueue */
7818 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7819 guint curr_size_bytes = 0;
7820 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7821 "curr-size-bytes", &curr_size_bytes, NULL);
7822 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7823 buffered_total += curr_size_bytes;
7826 if (avg_byterate > 0)
7827 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7828 else if (player->total_maximum_bitrate > 0)
7829 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7830 else if (player->total_bitrate > 0)
7831 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7833 if (buffered_sec >= 0)
7834 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7838 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7839 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7841 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7842 buffered_total, buffered_sec, *start_pos, *stop_pos);
7844 return MM_ERROR_NONE;
7848 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7853 LOGW("set_message_callback is called with invalid player handle\n");
7854 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7857 player->msg_cb = callback;
7858 player->msg_cb_param = user_param;
7860 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7864 return MM_ERROR_NONE;
7867 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7869 int ret = MM_ERROR_PLAYER_INVALID_URI;
7874 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7875 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7876 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7878 memset(data, 0, sizeof(MMPlayerParseProfile));
7880 if ((path = strstr(uri, "es_buff://"))) {
7882 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7883 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7884 ret = MM_ERROR_NONE;
7886 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7888 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7889 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7890 ret = MM_ERROR_NONE;
7892 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7895 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7896 tmp = g_ascii_strdown(uri, strlen(uri));
7898 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7899 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7901 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7903 ret = MM_ERROR_NONE;
7906 } else if ((path = strstr(uri, "rtspu://"))) {
7908 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7909 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7910 ret = MM_ERROR_NONE;
7912 } else if ((path = strstr(uri, "rtspr://"))) {
7913 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7914 char *separater = strstr(path, "*");
7918 char *urgent = separater + strlen("*");
7920 if ((urgent_len = strlen(urgent))) {
7921 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7922 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7923 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7924 ret = MM_ERROR_NONE;
7927 } else if ((path = strstr(uri, "mms://"))) {
7929 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7930 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7931 ret = MM_ERROR_NONE;
7933 } else if ((path = strstr(uri, "mem://"))) {
7936 char *buffer = NULL;
7937 char *seperator = strchr(path, ',');
7938 char ext[100] = {0,}, size[100] = {0,};
7941 if ((buffer = strstr(path, "ext="))) {
7942 buffer += strlen("ext=");
7944 if (strlen(buffer)) {
7945 strncpy(ext, buffer, 99);
7947 if ((seperator = strchr(ext, ','))
7948 || (seperator = strchr(ext, ' '))
7949 || (seperator = strchr(ext, '\0'))) {
7950 seperator[0] = '\0';
7955 if ((buffer = strstr(path, "size="))) {
7956 buffer += strlen("size=");
7958 if (strlen(buffer) > 0) {
7959 strncpy(size, buffer, 99);
7961 if ((seperator = strchr(size, ','))
7962 || (seperator = strchr(size, ' '))
7963 || (seperator = strchr(size, '\0'))) {
7964 seperator[0] = '\0';
7967 mem_size = atoi(size);
7972 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7973 if (mem_size && param) {
7974 if (data->input_mem.buf)
7975 free(data->input_mem.buf);
7976 data->input_mem.buf = malloc(mem_size);
7978 if (data->input_mem.buf) {
7979 memcpy(data->input_mem.buf, param, mem_size);
7980 data->input_mem.len = mem_size;
7981 ret = MM_ERROR_NONE;
7983 LOGE("failed to alloc mem %d", mem_size);
7984 ret = MM_ERROR_PLAYER_INTERNAL;
7987 data->input_mem.offset = 0;
7988 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7992 gchar *location = NULL;
7995 if ((path = strstr(uri, "file://"))) {
7997 location = g_filename_from_uri(uri, NULL, &err);
7999 if (!location || (err != NULL)) {
8000 LOGE("Invalid URI '%s' for filesrc: %s", path,
8001 (err != NULL) ? err->message : "unknown error");
8003 if (err) g_error_free(err);
8004 if (location) g_free(location);
8006 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8010 LOGD("path from uri: %s", location);
8013 path = (location != NULL) ? (location) : ((char*)uri);
8014 int file_stat = MM_ERROR_NONE;
8016 file_stat = util_exist_file_path(path);
8018 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8019 if (file_stat == MM_ERROR_NONE) {
8020 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8022 if (util_is_sdp_file(path)) {
8023 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8024 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8026 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8028 ret = MM_ERROR_NONE;
8029 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8030 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8032 LOGE("invalid uri, could not play..\n");
8033 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8036 if (location) g_free(location);
8040 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8041 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8042 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8043 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8045 /* dump parse result */
8046 SECURE_LOGW("incomming uri : %s\n", uri);
8047 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8048 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8056 __mmplayer_can_do_interrupt(mm_player_t *player)
8058 if (!player || !player->pipeline || !player->attrs) {
8059 LOGW("not initialized");
8063 if (player->set_mode.pcm_extraction) {
8064 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8068 /* check if seeking */
8069 if (player->doing_seek) {
8070 MMMessageParamType msg_param;
8071 memset(&msg_param, 0, sizeof(MMMessageParamType));
8072 msg_param.code = MM_ERROR_PLAYER_SEEK;
8073 player->doing_seek = FALSE;
8074 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8078 /* check other thread */
8079 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8080 LOGW("locked already, cmd state : %d", player->cmd);
8082 /* check application command */
8083 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8084 LOGW("playing.. should wait cmd lock then, will be interrupted");
8086 /* lock will be released at mrp_resource_release_cb() */
8087 MMPLAYER_CMD_LOCK(player);
8090 LOGW("nothing to do");
8093 LOGW("can interrupt immediately");
8097 FAILED: /* with CMD UNLOCKED */
8100 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8105 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8108 mm_player_t *player = NULL;
8112 if (user_data == NULL) {
8113 LOGE("- user_data is null\n");
8116 player = (mm_player_t *)user_data;
8118 /* do something to release resource here.
8119 * player stop and interrupt forwarding */
8120 if (!__mmplayer_can_do_interrupt(player)) {
8121 LOGW("no need to interrupt, so leave");
8123 MMMessageParamType msg = {0, };
8126 player->interrupted_by_resource = TRUE;
8128 /* get last play position */
8129 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8130 LOGW("failed to get play position.");
8132 msg.union_type = MM_MSG_UNION_TIME;
8133 msg.time.elapsed = pos;
8134 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8136 LOGD("video resource conflict so, resource will be freed by unrealizing");
8137 if (_mmplayer_unrealize((MMHandleType)player))
8138 LOGW("failed to unrealize");
8140 /* lock is called in __mmplayer_can_do_interrupt() */
8141 MMPLAYER_CMD_UNLOCK(player);
8144 if (res == player->video_overlay_resource)
8145 player->video_overlay_resource = FALSE;
8147 player->video_decoder_resource = FALSE;
8155 _mmplayer_create_player(MMHandleType handle)
8157 int ret = MM_ERROR_PLAYER_INTERNAL;
8158 bool enabled = false;
8160 mm_player_t* player = MM_PLAYER_CAST(handle);
8164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8166 /* initialize player state */
8167 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8168 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8169 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8170 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8172 /* check current state */
8173 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8175 /* construct attributes */
8176 player->attrs = _mmplayer_construct_attribute(handle);
8178 if (!player->attrs) {
8179 LOGE("Failed to construct attributes\n");
8183 /* initialize gstreamer with configured parameter */
8184 if (!__mmplayer_init_gstreamer(player)) {
8185 LOGE("Initializing gstreamer failed\n");
8186 _mmplayer_deconstruct_attribute(handle);
8190 /* create lock. note that g_tread_init() has already called in gst_init() */
8191 g_mutex_init(&player->fsink_lock);
8193 /* create update tag lock */
8194 g_mutex_init(&player->update_tag_lock);
8196 /* create next play mutex */
8197 g_mutex_init(&player->next_play_thread_mutex);
8199 /* create next play cond */
8200 g_cond_init(&player->next_play_thread_cond);
8202 /* create next play thread */
8203 player->next_play_thread =
8204 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8205 if (!player->next_play_thread) {
8206 LOGE("failed to create next play thread");
8207 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8208 g_mutex_clear(&player->next_play_thread_mutex);
8209 g_cond_clear(&player->next_play_thread_cond);
8213 player->bus_msg_q = g_queue_new();
8214 if (!player->bus_msg_q) {
8215 LOGE("failed to create queue for bus_msg");
8216 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8220 ret = _mmplayer_initialize_video_capture(player);
8221 if (ret != MM_ERROR_NONE) {
8222 LOGE("failed to initialize video capture\n");
8226 /* initialize resource manager */
8227 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8228 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8229 &player->resource_manager)) {
8230 LOGE("failed to initialize resource manager\n");
8234 if (MMPLAYER_IS_HTTP_PD(player)) {
8235 player->pd_downloader = NULL;
8236 player->pd_file_save_path = NULL;
8239 /* create video bo lock and cond */
8240 g_mutex_init(&player->video_bo_mutex);
8241 g_cond_init(&player->video_bo_cond);
8243 /* create media stream callback mutex */
8244 g_mutex_init(&player->media_stream_cb_lock);
8246 /* create subtitle info lock and cond */
8247 g_mutex_init(&player->subtitle_info_mutex);
8248 g_cond_init(&player->subtitle_info_cond);
8250 player->streaming_type = STREAMING_SERVICE_NONE;
8252 /* give default value of audio effect setting */
8253 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8254 player->sound.rg_enable = false;
8255 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8257 player->play_subtitle = FALSE;
8258 player->use_deinterleave = FALSE;
8259 player->max_audio_channels = 0;
8260 player->video_share_api_delta = 0;
8261 player->video_share_clock_delta = 0;
8262 player->has_closed_caption = FALSE;
8263 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8264 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8265 player->pending_resume = FALSE;
8266 if (player->ini.dump_element_keyword[0][0] == '\0')
8267 player->ini.set_dump_element_flag = FALSE;
8269 player->ini.set_dump_element_flag = TRUE;
8271 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8272 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8273 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8275 /* Set video360 settings to their defaults for just-created player.
8278 player->is_360_feature_enabled = FALSE;
8279 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8280 LOGI("spherical feature info: %d", enabled);
8282 player->is_360_feature_enabled = TRUE;
8284 LOGE("failed to get spherical feature info");
8287 player->is_content_spherical = FALSE;
8288 player->is_video360_enabled = TRUE;
8289 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8290 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8291 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8292 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8293 player->video360_zoom = 1.0f;
8294 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8295 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8297 /* set player state to null */
8298 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8299 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8301 return MM_ERROR_NONE;
8305 g_mutex_clear(&player->fsink_lock);
8307 /* free update tag lock */
8308 g_mutex_clear(&player->update_tag_lock);
8310 g_queue_free(player->bus_msg_q);
8312 /* free next play thread */
8313 if (player->next_play_thread) {
8314 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8315 player->next_play_thread_exit = TRUE;
8316 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8317 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8319 g_thread_join(player->next_play_thread);
8320 player->next_play_thread = NULL;
8322 g_mutex_clear(&player->next_play_thread_mutex);
8323 g_cond_clear(&player->next_play_thread_cond);
8326 /* release attributes */
8327 _mmplayer_deconstruct_attribute(handle);
8335 __mmplayer_init_gstreamer(mm_player_t* player)
8337 static gboolean initialized = FALSE;
8338 static const int max_argc = 50;
8340 gchar** argv = NULL;
8341 gchar** argv2 = NULL;
8347 LOGD("gstreamer already initialized.\n");
8352 argc = malloc(sizeof(int));
8353 argv = malloc(sizeof(gchar*) * max_argc);
8354 argv2 = malloc(sizeof(gchar*) * max_argc);
8356 if (!argc || !argv || !argv2)
8359 memset(argv, 0, sizeof(gchar*) * max_argc);
8360 memset(argv2, 0, sizeof(gchar*) * max_argc);
8364 argv[0] = g_strdup("mmplayer");
8367 for (i = 0; i < 5; i++) {
8368 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8369 if (strlen(player->ini.gst_param[i]) > 0) {
8370 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8375 /* we would not do fork for scanning plugins */
8376 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8379 /* check disable registry scan */
8380 if (player->ini.skip_rescan) {
8381 argv[*argc] = g_strdup("--gst-disable-registry-update");
8385 /* check disable segtrap */
8386 if (player->ini.disable_segtrap) {
8387 argv[*argc] = g_strdup("--gst-disable-segtrap");
8391 LOGD("initializing gstreamer with following parameter\n");
8392 LOGD("argc : %d\n", *argc);
8395 for (i = 0; i < arg_count; i++) {
8397 LOGD("argv[%d] : %s\n", i, argv2[i]);
8400 /* initializing gstreamer */
8401 if (!gst_init_check(argc, &argv, &err)) {
8402 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8409 for (i = 0; i < arg_count; i++) {
8410 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8411 MMPLAYER_FREEIF(argv2[i]);
8414 MMPLAYER_FREEIF(argv);
8415 MMPLAYER_FREEIF(argv2);
8416 MMPLAYER_FREEIF(argc);
8426 for (i = 0; i < arg_count; i++) {
8427 LOGD("free[%d] : %s\n", i, argv2[i]);
8428 MMPLAYER_FREEIF(argv2[i]);
8431 MMPLAYER_FREEIF(argv);
8432 MMPLAYER_FREEIF(argv2);
8433 MMPLAYER_FREEIF(argc);
8439 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8441 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8443 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8444 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8445 MMPLAYER_FREEIF(player->pd_file_save_path);
8448 return MM_ERROR_NONE;
8452 __mmplayer_check_async_state_transition(mm_player_t* player)
8454 GstState element_state = GST_STATE_VOID_PENDING;
8455 GstState element_pending_state = GST_STATE_VOID_PENDING;
8456 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8457 GstElement * element = NULL;
8458 gboolean async = FALSE;
8460 /* check player handle */
8461 MMPLAYER_RETURN_IF_FAIL(player &&
8463 player->pipeline->mainbin &&
8464 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8467 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8469 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8470 LOGD("don't need to check the pipeline state");
8474 MMPLAYER_PRINT_STATE(player);
8476 /* wait for state transition */
8477 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8478 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8480 if (ret == GST_STATE_CHANGE_FAILURE) {
8481 LOGE(" [%s] state : %s pending : %s \n",
8482 GST_ELEMENT_NAME(element),
8483 gst_element_state_get_name(element_state),
8484 gst_element_state_get_name(element_pending_state));
8486 /* dump state of all element */
8487 __mmplayer_dump_pipeline_state(player);
8492 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8497 _mmplayer_destroy(MMHandleType handle)
8499 mm_player_t* player = MM_PLAYER_CAST(handle);
8503 /* check player handle */
8504 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8506 /* destroy can called at anytime */
8507 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8509 /* check async state transition */
8510 __mmplayer_check_async_state_transition(player);
8512 __mmplayer_destroy_streaming_ext(player);
8514 /* release next play thread */
8515 if (player->next_play_thread) {
8516 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8517 player->next_play_thread_exit = TRUE;
8518 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8519 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8521 LOGD("waitting for next play thread exit\n");
8522 g_thread_join(player->next_play_thread);
8523 g_mutex_clear(&player->next_play_thread_mutex);
8524 g_cond_clear(&player->next_play_thread_cond);
8525 LOGD("next play thread released\n");
8528 _mmplayer_release_video_capture(player);
8530 /* de-initialize resource manager */
8531 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8532 player->resource_manager))
8533 LOGE("failed to deinitialize resource manager\n");
8535 /* release pipeline */
8536 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8537 LOGE("failed to destory pipeline\n");
8538 return MM_ERROR_PLAYER_INTERNAL;
8541 g_queue_free(player->bus_msg_q);
8543 /* release subtitle info lock and cond */
8544 g_mutex_clear(&player->subtitle_info_mutex);
8545 g_cond_clear(&player->subtitle_info_cond);
8547 __mmplayer_release_dump_list(player->dump_list);
8549 /* release miscellaneous information */
8550 __mmplayer_release_misc(player);
8552 /* release miscellaneous information.
8553 these info needs to be released after pipeline is destroyed. */
8554 __mmplayer_release_misc_post(player);
8556 /* release attributes */
8557 _mmplayer_deconstruct_attribute(handle);
8560 g_mutex_clear(&player->fsink_lock);
8563 g_mutex_clear(&player->update_tag_lock);
8565 /* release video bo lock and cond */
8566 g_mutex_clear(&player->video_bo_mutex);
8567 g_cond_clear(&player->video_bo_cond);
8569 /* release media stream callback lock */
8570 g_mutex_clear(&player->media_stream_cb_lock);
8574 return MM_ERROR_NONE;
8578 __mmplayer_realize_streaming_ext(mm_player_t* player)
8580 int ret = MM_ERROR_NONE;
8583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8585 if (MMPLAYER_IS_HTTP_PD(player)) {
8586 gboolean bret = FALSE;
8588 player->pd_downloader = _mmplayer_create_pd_downloader();
8589 if (!player->pd_downloader) {
8590 LOGE("Unable to create PD Downloader...");
8591 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8594 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8596 if (FALSE == bret) {
8597 LOGE("Unable to create PD Downloader...");
8598 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8607 _mmplayer_realize(MMHandleType hplayer)
8609 mm_player_t* player = (mm_player_t*)hplayer;
8612 MMHandleType attrs = 0;
8613 int ret = MM_ERROR_NONE;
8617 /* check player handle */
8618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8620 /* check current state */
8621 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8623 attrs = MMPLAYER_GET_ATTRS(player);
8625 LOGE("fail to get attributes.\n");
8626 return MM_ERROR_PLAYER_INTERNAL;
8628 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8629 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8631 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8632 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8634 if (ret != MM_ERROR_NONE) {
8635 LOGE("failed to parse profile\n");
8640 if (uri && (strstr(uri, "es_buff://"))) {
8641 if (strstr(uri, "es_buff://push_mode"))
8642 player->es_player_push_mode = TRUE;
8644 player->es_player_push_mode = FALSE;
8647 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8648 LOGW("mms protocol is not supported format.\n");
8649 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8652 if (MMPLAYER_IS_STREAMING(player))
8653 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8655 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8657 player->smooth_streaming = FALSE;
8658 player->videodec_linked = 0;
8659 player->videosink_linked = 0;
8660 player->audiodec_linked = 0;
8661 player->audiosink_linked = 0;
8662 player->textsink_linked = 0;
8663 player->is_external_subtitle_present = FALSE;
8664 player->is_external_subtitle_added_now = FALSE;
8665 /* set the subtitle ON default */
8666 player->is_subtitle_off = FALSE;
8668 /* realize pipeline */
8669 ret = __gst_realize(player);
8670 if (ret != MM_ERROR_NONE)
8671 LOGE("fail to realize the player.\n");
8673 ret = __mmplayer_realize_streaming_ext(player);
8675 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8683 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8688 /* destroy can called at anytime */
8689 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8690 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8693 return MM_ERROR_NONE;
8697 _mmplayer_unrealize(MMHandleType hplayer)
8699 mm_player_t* player = (mm_player_t*)hplayer;
8700 int ret = MM_ERROR_NONE;
8704 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8706 MMPLAYER_CMD_UNLOCK(player);
8707 /* destroy the gst bus msg thread which is created during realize.
8708 this funct have to be called before getting cmd lock. */
8709 _mmplayer_bus_msg_thread_destroy(player);
8710 MMPLAYER_CMD_LOCK(player);
8712 /* check current state */
8713 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8715 /* check async state transition */
8716 __mmplayer_check_async_state_transition(player);
8718 __mmplayer_unrealize_streaming_ext(player);
8720 /* unrealize pipeline */
8721 ret = __gst_unrealize(player);
8723 /* set asm stop if success */
8724 if (MM_ERROR_NONE == ret) {
8725 if (!player->interrupted_by_resource) {
8726 if (player->video_decoder_resource != NULL) {
8727 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8728 player->video_decoder_resource);
8729 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8730 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8732 player->video_decoder_resource = NULL;
8735 if (player->video_overlay_resource != NULL) {
8736 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8737 player->video_overlay_resource);
8738 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8739 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8741 player->video_overlay_resource = NULL;
8744 ret = mm_resource_manager_commit(player->resource_manager);
8745 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8746 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8749 LOGE("failed and don't change asm state to stop");
8757 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8759 mm_player_t* player = (mm_player_t*)hplayer;
8761 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8763 return __gst_set_message_callback(player, callback, user_param);
8767 _mmplayer_get_state(MMHandleType hplayer, int* state)
8769 mm_player_t *player = (mm_player_t*)hplayer;
8771 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8773 *state = MMPLAYER_CURRENT_STATE(player);
8775 return MM_ERROR_NONE;
8780 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8782 mm_player_t* player = (mm_player_t*) hplayer;
8783 GstElement* vol_element = NULL;
8788 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8790 LOGD("volume [L]=%f:[R]=%f\n",
8791 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8793 /* invalid factor range or not */
8794 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8795 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8796 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8797 return MM_ERROR_INVALID_ARGUMENT;
8801 /* not support to set other value into each channel */
8802 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8803 return MM_ERROR_INVALID_ARGUMENT;
8805 /* Save volume to handle. Currently the first array element will be saved. */
8806 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8808 /* check pipeline handle */
8809 if (!player->pipeline || !player->pipeline->audiobin) {
8810 LOGD("audiobin is not created yet\n");
8811 LOGD("but, current stored volume will be set when it's created.\n");
8813 /* NOTE : stored volume will be used in create_audiobin
8814 * returning MM_ERROR_NONE here makes application to able to
8815 * set volume at anytime.
8817 return MM_ERROR_NONE;
8820 /* setting volume to volume element */
8821 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8824 LOGD("volume is set [%f]\n", player->sound.volume);
8825 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8830 return MM_ERROR_NONE;
8835 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8837 mm_player_t* player = (mm_player_t*) hplayer;
8842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8843 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8845 /* returning stored volume */
8846 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8847 volume->level[i] = player->sound.volume;
8851 return MM_ERROR_NONE;
8855 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8857 mm_player_t* player = (mm_player_t*) hplayer;
8858 GstElement* vol_element = NULL;
8862 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8864 /* mute value shoud 0 or 1 */
8865 if (mute != 0 && mute != 1) {
8866 LOGE("bad mute value\n");
8868 /* FIXIT : definitly, we need _BAD_PARAM error code */
8869 return MM_ERROR_INVALID_ARGUMENT;
8872 player->sound.mute = mute;
8874 /* just hold mute value if pipeline is not ready */
8875 if (!player->pipeline || !player->pipeline->audiobin) {
8876 LOGD("pipeline is not ready. holding mute value\n");
8877 return MM_ERROR_NONE;
8880 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8882 /* NOTE : volume will only created when the bt is enabled */
8884 LOGD("mute : %d\n", mute);
8885 g_object_set(vol_element, "mute", mute, NULL);
8887 LOGD("volume elemnet is not created. using volume in audiosink\n");
8891 return MM_ERROR_NONE;
8895 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8897 mm_player_t* player = (mm_player_t*) hplayer;
8901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8902 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8904 /* just hold mute value if pipeline is not ready */
8905 if (!player->pipeline || !player->pipeline->audiobin) {
8906 LOGD("pipeline is not ready. returning stored value\n");
8907 *pmute = player->sound.mute;
8908 return MM_ERROR_NONE;
8911 *pmute = player->sound.mute;
8915 return MM_ERROR_NONE;
8919 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8921 mm_player_t* player = (mm_player_t*) hplayer;
8925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8927 player->video_stream_changed_cb = callback;
8928 player->video_stream_changed_cb_user_param = user_param;
8929 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8933 return MM_ERROR_NONE;
8937 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8939 mm_player_t* player = (mm_player_t*) hplayer;
8943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8945 player->audio_stream_changed_cb = callback;
8946 player->audio_stream_changed_cb_user_param = user_param;
8947 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8951 return MM_ERROR_NONE;
8955 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8957 mm_player_t* player = (mm_player_t*) hplayer;
8961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8963 player->audio_stream_render_cb_ex = callback;
8964 player->audio_stream_cb_user_param = user_param;
8965 player->audio_stream_sink_sync = sync;
8966 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);
8970 return MM_ERROR_NONE;
8974 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8976 mm_player_t* player = (mm_player_t*) hplayer;
8980 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8982 if (callback && !player->bufmgr)
8983 player->bufmgr = tbm_bufmgr_init(-1);
8985 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8986 player->video_stream_cb = callback;
8987 player->video_stream_cb_user_param = user_param;
8989 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8993 return MM_ERROR_NONE;
8997 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8999 mm_player_t* player = (mm_player_t*) hplayer;
9003 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9005 player->audio_stream_cb = callback;
9006 player->audio_stream_cb_user_param = user_param;
9007 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9011 return MM_ERROR_NONE;
9015 __mmplayer_start_streaming_ext(mm_player_t *player)
9017 gint ret = MM_ERROR_NONE;
9020 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9022 if (MMPLAYER_IS_HTTP_PD(player)) {
9023 if (!player->pd_downloader) {
9024 ret = __mmplayer_realize_streaming_ext(player);
9026 if (ret != MM_ERROR_NONE) {
9027 LOGE("failed to realize streaming ext\n");
9032 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9033 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9035 LOGE("ERROR while starting PD...\n");
9036 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9038 ret = MM_ERROR_NONE;
9047 _mmplayer_start(MMHandleType hplayer)
9049 mm_player_t* player = (mm_player_t*) hplayer;
9050 gint ret = MM_ERROR_NONE;
9054 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9056 /* check current state */
9057 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9059 /* NOTE : we should check and create pipeline again if not created as we destroy
9060 * whole pipeline when stopping in streamming playback
9062 if (!player->pipeline) {
9063 ret = __gst_realize(player);
9064 if (MM_ERROR_NONE != ret) {
9065 LOGE("failed to realize before starting. only in streamming\n");
9071 ret = __mmplayer_start_streaming_ext(player);
9072 if (ret != MM_ERROR_NONE) {
9073 LOGE("failed to start streaming ext 0x%X", ret);
9077 /* start pipeline */
9078 ret = __gst_start(player);
9079 if (ret != MM_ERROR_NONE)
9080 LOGE("failed to start player.\n");
9087 /* NOTE: post "not supported codec message" to application
9088 * when one codec is not found during AUTOPLUGGING in MSL.
9089 * So, it's separated with error of __mmplayer_gst_callback().
9090 * And, if any codec is not found, don't send message here.
9091 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9094 __mmplayer_handle_missed_plugin(mm_player_t* player)
9096 MMMessageParamType msg_param;
9097 memset(&msg_param, 0, sizeof(MMMessageParamType));
9098 gboolean post_msg_direct = FALSE;
9102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9104 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9105 player->not_supported_codec, player->can_support_codec);
9107 if (player->not_found_demuxer) {
9108 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9109 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9111 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9112 MMPLAYER_FREEIF(msg_param.data);
9114 return MM_ERROR_NONE;
9117 if (player->not_supported_codec) {
9118 if (player->can_support_codec) {
9119 // There is one codec to play
9120 post_msg_direct = TRUE;
9122 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9123 post_msg_direct = TRUE;
9126 if (post_msg_direct) {
9127 MMMessageParamType msg_param;
9128 memset(&msg_param, 0, sizeof(MMMessageParamType));
9130 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9131 LOGW("not found AUDIO codec, posting error code to application.\n");
9133 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9134 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9135 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9136 LOGW("not found VIDEO codec, posting error code to application.\n");
9138 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9139 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9142 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9144 MMPLAYER_FREEIF(msg_param.data);
9146 return MM_ERROR_NONE;
9148 // no any supported codec case
9149 LOGW("not found any codec, posting error code to application.\n");
9151 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9152 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9153 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9155 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9156 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9159 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9161 MMPLAYER_FREEIF(msg_param.data);
9167 return MM_ERROR_NONE;
9170 static void __mmplayer_check_pipeline(mm_player_t* player)
9172 GstState element_state = GST_STATE_VOID_PENDING;
9173 GstState element_pending_state = GST_STATE_VOID_PENDING;
9175 int ret = MM_ERROR_NONE;
9177 if (player->gapless.reconfigure) {
9178 LOGW("pipeline is under construction.\n");
9180 MMPLAYER_PLAYBACK_LOCK(player);
9181 MMPLAYER_PLAYBACK_UNLOCK(player);
9183 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9185 /* wait for state transition */
9186 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9188 if (ret == GST_STATE_CHANGE_FAILURE)
9189 LOGE("failed to change pipeline state within %d sec\n", timeout);
9193 /* NOTE : it should be able to call 'stop' anytime*/
9195 _mmplayer_stop(MMHandleType hplayer)
9197 mm_player_t* player = (mm_player_t*)hplayer;
9198 int ret = MM_ERROR_NONE;
9202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9204 /* check current state */
9205 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9207 /* check pipline building state */
9208 __mmplayer_check_pipeline(player);
9209 __mmplayer_reset_gapless_state(player);
9211 /* NOTE : application should not wait for EOS after calling STOP */
9212 __mmplayer_cancel_eos_timer(player);
9214 __mmplayer_unrealize_streaming_ext(player);
9217 player->doing_seek = FALSE;
9220 ret = __gst_stop(player);
9222 if (ret != MM_ERROR_NONE)
9223 LOGE("failed to stop player.\n");
9231 _mmplayer_pause(MMHandleType hplayer)
9233 mm_player_t* player = (mm_player_t*)hplayer;
9234 gint64 pos_nsec = 0;
9235 gboolean async = FALSE;
9236 gint ret = MM_ERROR_NONE;
9240 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9242 /* check current state */
9243 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9245 /* check pipline building state */
9246 __mmplayer_check_pipeline(player);
9248 switch (MMPLAYER_CURRENT_STATE(player)) {
9249 case MM_PLAYER_STATE_READY:
9251 /* check prepare async or not.
9252 * In the case of streaming playback, it's recommned to avoid blocking wait.
9254 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9255 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9257 /* Changing back sync of rtspsrc to async */
9258 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9259 LOGD("async prepare working mode for rtsp");
9265 case MM_PLAYER_STATE_PLAYING:
9267 /* NOTE : store current point to overcome some bad operation
9268 *(returning zero when getting current position in paused state) of some
9271 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9272 LOGW("getting current position failed in paused\n");
9274 player->last_position = pos_nsec;
9276 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9277 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9278 This causes problem is position calculation during normal pause resume scenarios also.
9279 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9280 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9281 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9282 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9288 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9289 LOGD("doing async pause in case of ms buff src");
9293 /* pause pipeline */
9294 ret = __gst_pause(player, async);
9296 if (ret != MM_ERROR_NONE)
9297 LOGE("failed to pause player. ret : 0x%x\n", ret);
9299 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9300 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9301 LOGE("failed to update display_rotation");
9310 _mmplayer_resume(MMHandleType hplayer)
9312 mm_player_t* player = (mm_player_t*)hplayer;
9313 int ret = MM_ERROR_NONE;
9314 gboolean async = FALSE;
9318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9320 /* Changing back sync mode rtspsrc to async */
9321 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9322 LOGD("async resume for rtsp case");
9326 /* check current state */
9327 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9329 ret = __gst_resume(player, async);
9331 if (ret != MM_ERROR_NONE)
9332 LOGE("failed to resume player.\n");
9340 __mmplayer_set_pcm_extraction(mm_player_t* player)
9342 gint64 start_nsec = 0;
9343 gint64 end_nsec = 0;
9344 gint64 dur_nsec = 0;
9345 gint64 dur_msec = 0;
9346 int required_start = 0;
9347 int required_end = 0;
9352 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9354 mm_attrs_multiple_get(player->attrs,
9356 "pcm_extraction_start_msec", &required_start,
9357 "pcm_extraction_end_msec", &required_end,
9360 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9362 if (required_start == 0 && required_end == 0) {
9363 LOGD("extracting entire stream");
9364 return MM_ERROR_NONE;
9365 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9366 LOGD("invalid range for pcm extraction");
9367 return MM_ERROR_INVALID_ARGUMENT;
9371 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9373 LOGE("failed to get duration");
9374 return MM_ERROR_PLAYER_INTERNAL;
9376 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9378 if (dur_msec < required_end) {
9380 LOGD("invalid end pos for pcm extraction");
9381 return MM_ERROR_INVALID_ARGUMENT;
9384 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9385 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9387 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9390 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9391 GST_SEEK_TYPE_SET, start_nsec,
9392 GST_SEEK_TYPE_SET, end_nsec))) {
9393 LOGE("failed to seek for pcm extraction\n");
9395 return MM_ERROR_PLAYER_SEEK;
9398 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9402 return MM_ERROR_NONE;
9406 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9408 mm_player_t* player = (mm_player_t*)hplayer;
9409 gint64 pos_nsec = 0;
9410 int ret = MM_ERROR_NONE;
9412 signed long long start = 0, stop = 0;
9413 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9416 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9417 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9419 /* The sound of video is not supported under 0.0 and over 2.0. */
9420 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9421 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9424 _mmplayer_set_mute(hplayer, mute);
9426 if (player->playback_rate == rate)
9427 return MM_ERROR_NONE;
9429 /* If the position is reached at start potion during fast backward, EOS is posted.
9430 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9432 player->playback_rate = rate;
9434 current_state = MMPLAYER_CURRENT_STATE(player);
9436 if (current_state != MM_PLAYER_STATE_PAUSED)
9437 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9439 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9441 if ((current_state == MM_PLAYER_STATE_PAUSED)
9442 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9443 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9444 pos_nsec = player->last_position;
9449 stop = GST_CLOCK_TIME_NONE;
9451 start = GST_CLOCK_TIME_NONE;
9455 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9456 player->playback_rate,
9458 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9459 GST_SEEK_TYPE_SET, start,
9460 GST_SEEK_TYPE_SET, stop)) {
9461 LOGE("failed to set speed playback\n");
9462 return MM_ERROR_PLAYER_SEEK;
9465 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9469 return MM_ERROR_NONE;;
9473 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9475 mm_player_t* player = (mm_player_t*)hplayer;
9476 int ret = MM_ERROR_NONE;
9480 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9482 /* check pipline building state */
9483 __mmplayer_check_pipeline(player);
9485 ret = __gst_set_position(player, format, position, FALSE);
9493 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9495 mm_player_t* player = (mm_player_t*)hplayer;
9496 int ret = MM_ERROR_NONE;
9498 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9500 ret = __gst_get_position(player, format, position);
9506 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9508 mm_player_t* player = (mm_player_t*)hplayer;
9509 int ret = MM_ERROR_NONE;
9511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9512 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9514 *duration = player->duration;
9519 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9521 mm_player_t* player = (mm_player_t*)hplayer;
9522 int ret = MM_ERROR_NONE;
9524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9526 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9532 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9534 mm_player_t* player = (mm_player_t*)hplayer;
9535 int ret = MM_ERROR_NONE;
9539 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9541 ret = __gst_adjust_subtitle_position(player, format, position);
9549 __mmplayer_is_midi_type(gchar* str_caps)
9551 if ((g_strrstr(str_caps, "audio/midi")) ||
9552 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9553 (g_strrstr(str_caps, "application/x-smaf")) ||
9554 (g_strrstr(str_caps, "audio/x-imelody")) ||
9555 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9556 (g_strrstr(str_caps, "audio/xmf")) ||
9557 (g_strrstr(str_caps, "audio/mxmf"))) {
9566 __mmplayer_is_only_mp3_type(gchar *str_caps)
9568 if (g_strrstr(str_caps, "application/x-id3") ||
9569 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9575 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9577 GstStructure* caps_structure = NULL;
9578 gint samplerate = 0;
9582 MMPLAYER_RETURN_IF_FAIL(player && caps);
9584 caps_structure = gst_caps_get_structure(caps, 0);
9586 /* set stream information */
9587 gst_structure_get_int(caps_structure, "rate", &samplerate);
9588 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9590 gst_structure_get_int(caps_structure, "channels", &channels);
9591 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9593 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9597 __mmplayer_update_content_type_info(mm_player_t* player)
9600 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9602 if (__mmplayer_is_midi_type(player->type)) {
9603 player->bypass_audio_effect = TRUE;
9604 } else if (g_strrstr(player->type, "application/x-hls")) {
9605 /* If it can't know exact type when it parses uri because of redirection case,
9606 * it will be fixed by typefinder or when doing autoplugging.
9608 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9609 if (player->streamer) {
9610 player->streamer->is_adaptive_streaming = TRUE;
9611 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9612 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9614 } else if (g_strrstr(player->type, "application/dash+xml")) {
9615 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9622 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9623 GstCaps *caps, gpointer data)
9625 mm_player_t* player = (mm_player_t*)data;
9630 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9632 /* store type string */
9633 MMPLAYER_FREEIF(player->type);
9634 player->type = gst_caps_to_string(caps);
9636 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9637 player, player->type, probability, gst_caps_get_size(caps));
9640 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9641 (g_strrstr(player->type, "audio/x-raw-int"))) {
9642 LOGE("not support media format\n");
9644 if (player->msg_posted == FALSE) {
9645 MMMessageParamType msg_param;
9646 memset(&msg_param, 0, sizeof(MMMessageParamType));
9648 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9649 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9651 /* don't post more if one was sent already */
9652 player->msg_posted = TRUE;
9657 __mmplayer_update_content_type_info(player);
9659 pad = gst_element_get_static_pad(tf, "src");
9661 LOGE("fail to get typefind src pad.\n");
9665 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9666 gboolean async = FALSE;
9667 LOGE("failed to autoplug %s\n", player->type);
9669 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9671 if (async && player->msg_posted == FALSE)
9672 __mmplayer_handle_missed_plugin(player);
9678 gst_object_unref(GST_OBJECT(pad));
9686 __mmplayer_create_decodebin(mm_player_t* player)
9688 GstElement *decodebin = NULL;
9692 /* create decodebin */
9693 decodebin = gst_element_factory_make("decodebin", NULL);
9696 LOGE("fail to create decodebin\n");
9700 /* raw pad handling signal */
9701 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9702 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9704 /* no-more-pad pad handling signal */
9705 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9706 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9708 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9709 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9711 /* This signal is emitted when a pad for which there is no further possible
9712 decoding is added to the decodebin.*/
9713 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9714 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9716 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9717 before looking for any elements that can handle that stream.*/
9718 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9719 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9721 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9722 before looking for any elements that can handle that stream.*/
9723 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9724 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9726 /* This signal is emitted once decodebin has finished decoding all the data.*/
9727 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9728 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9730 /* This signal is emitted when a element is added to the bin.*/
9731 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9732 G_CALLBACK(__mmplayer_gst_element_added), player);
9739 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9741 MMPlayerGstElement* mainbin = NULL;
9742 GstElement* decodebin = NULL;
9743 GstElement* queue2 = NULL;
9744 GstPad* sinkpad = NULL;
9745 GstPad* qsrcpad = NULL;
9746 gint64 dur_bytes = 0L;
9748 guint max_buffer_size_bytes = 0;
9749 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9752 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9754 mainbin = player->pipeline->mainbin;
9756 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9757 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9758 LOGD("creating http streaming buffering queue(queue2)\n");
9760 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9761 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9763 queue2 = gst_element_factory_make("queue2", "queue2");
9765 LOGE("failed to create buffering queue element\n");
9769 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9770 LOGE("failed to add buffering queue\n");
9774 sinkpad = gst_element_get_static_pad(queue2, "sink");
9775 qsrcpad = gst_element_get_static_pad(queue2, "src");
9777 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9778 LOGE("failed to link buffering queue");
9782 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9783 LOGE("fail to get duration");
9785 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9787 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9789 if (dur_bytes > 0) {
9790 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9791 type = MUXED_BUFFER_TYPE_FILE;
9793 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9794 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9800 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9801 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9802 if (!g_strrstr(player->type, "video/mpegts")) {
9803 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9804 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9806 /* FIXME : pass ini setting directly. is this ok? */
9807 __mm_player_streaming_set_queue2(player->streamer,
9810 max_buffer_size_bytes,
9811 player->ini.http_buffering_time,
9813 player->ini.http_buffering_limit, // no meaning
9815 player->http_file_buffering_path,
9816 (guint64)dur_bytes);
9819 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9820 LOGE("failed to sync queue2 state with parent\n");
9826 gst_object_unref(GST_OBJECT(sinkpad));
9828 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9829 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9833 /* create decodebin */
9834 decodebin = __mmplayer_create_decodebin(player);
9837 LOGE("can not create autoplug element\n");
9841 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9842 LOGE("failed to add decodebin\n");
9846 /* to force caps on the decodebin element and avoid reparsing stuff by
9847 * typefind. It also avoids a deadlock in the way typefind activates pads in
9848 * the state change */
9849 g_object_set(decodebin, "sink-caps", caps, NULL);
9851 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9853 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9854 LOGE("failed to link decodebin\n");
9858 gst_object_unref(GST_OBJECT(sinkpad));
9860 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9861 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9863 /* set decodebin property about buffer in streaming playback. *
9864 * in case of HLS/DASH, it does not need to have big buffer *
9865 * because it is kind of adaptive streaming. */
9866 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9867 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9868 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9869 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9871 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9872 || MMPLAYER_IS_DASH_STREAMING(player)) {
9873 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9874 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9877 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9878 "high-percent", (gint)player->ini.http_buffering_limit,
9879 "low-percent", 1, // 1%
9880 "max-size-bytes", max_size_bytes,
9881 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9882 "max-size-buffers", 0, NULL); // disable or automatic
9885 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9886 LOGE("failed to sync decodebin state with parent\n");
9897 gst_object_unref(GST_OBJECT(sinkpad));
9900 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9901 * You need to explicitly set elements to the NULL state before
9902 * dropping the final reference, to allow them to clean up.
9904 gst_element_set_state(queue2, GST_STATE_NULL);
9906 /* And, it still has a parent "player".
9907 * You need to let the parent manage the object instead of unreffing the object directly.
9909 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9910 gst_object_unref(queue2);
9915 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9916 * You need to explicitly set elements to the NULL state before
9917 * dropping the final reference, to allow them to clean up.
9919 gst_element_set_state(decodebin, GST_STATE_NULL);
9921 /* And, it still has a parent "player".
9922 * You need to let the parent manage the object instead of unreffing the object directly.
9925 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9926 gst_object_unref(decodebin);
9934 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9938 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9939 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9941 LOGD("class : %s, mime : %s \n", factory_class, mime);
9943 /* add missing plugin */
9944 /* NOTE : msl should check missing plugin for image mime type.
9945 * Some motion jpeg clips can have playable audio track.
9946 * So, msl have to play audio after displaying popup written video format not supported.
9948 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9949 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9950 LOGD("not found demuxer\n");
9951 player->not_found_demuxer = TRUE;
9952 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9958 if (!g_strrstr(factory_class, "Demuxer")) {
9959 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9960 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9961 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9963 /* check that clip have multi tracks or not */
9964 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9965 LOGD("video plugin is already linked\n");
9967 LOGW("add VIDEO to missing plugin\n");
9968 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9969 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9971 } else if (g_str_has_prefix(mime, "audio")) {
9972 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9973 LOGD("audio plugin is already linked\n");
9975 LOGW("add AUDIO to missing plugin\n");
9976 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9977 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9985 return MM_ERROR_NONE;
9990 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
9992 mm_player_t* player = (mm_player_t*)data;
9996 MMPLAYER_RETURN_IF_FAIL(player);
9998 /* remove fakesink. */
9999 if (!__mmplayer_gst_remove_fakesink(player,
10000 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10001 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10002 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10003 * source element are not same. To overcome this situation, this function will called
10004 * several places and several times. Therefore, this is not an error case.
10009 LOGD("[handle: %p] pipeline has completely constructed", player);
10011 if ((player->ini.async_start) &&
10012 (player->msg_posted == FALSE) &&
10013 (player->cmd >= MMPLAYER_COMMAND_START))
10014 __mmplayer_handle_missed_plugin(player);
10016 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10020 __mmplayer_verify_next_play_path(mm_player_t *player)
10022 MMHandleType attrs = 0;
10023 MMPlayerParseProfile profile;
10024 gint uri_idx = 0, check_cnt = 0;
10026 gint mode = MM_PLAYER_PD_MODE_NONE;
10030 guint num_of_list = 0;
10031 static int profile_tv = -1;
10035 LOGD("checking for gapless play");
10037 if (player->pipeline->textbin) {
10038 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10042 attrs = MMPLAYER_GET_ATTRS(player);
10044 LOGE("fail to get attributes.\n");
10048 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10050 if (__builtin_expect(profile_tv == -1, 0)) {
10052 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10053 switch (*profileName) {
10063 /* gapless playback is not supported in case of video at TV profile. */
10064 if (profile_tv && video) {
10065 LOGW("not support video gapless playback");
10069 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10070 if (mode == TRUE) {
10076 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10077 LOGE("can not get play count\n");
10079 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10080 LOGE("can not get gapless mode\n");
10082 if (video && !gapless) {
10083 LOGW("not enabled video gapless playback");
10087 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10091 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10095 num_of_list = g_list_length(player->uri_info.uri_list);
10097 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10099 if (num_of_list == 0) {
10100 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10101 LOGE("can not get profile_uri\n");
10106 LOGE("uri list is empty.\n");
10110 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10111 LOGD("add original path : %s ", uri);
10117 uri_idx = player->uri_info.uri_idx;
10122 if (check_cnt > num_of_list) {
10123 LOGE("there is no valid uri.");
10127 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10129 if (uri_idx < num_of_list-1) {
10132 if ((count <= 1) && (count != -1)) {
10133 LOGD("no repeat.");
10135 } else if (count > 1) {
10136 /* decrease play count */
10137 /* we succeeded to rewind. update play count and then wait for next EOS */
10140 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10142 /* commit attribute */
10143 if (mmf_attrs_commit(attrs))
10144 LOGE("failed to commit attribute\n");
10147 /* count < 0 : repeat continually */
10151 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10152 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10155 LOGW("next uri does not exist\n");
10159 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10160 LOGE("failed to parse profile\n");
10164 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10165 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10166 LOGW("uri type is not supported(%d).", profile.uri_type);
10173 player->uri_info.uri_idx = uri_idx;
10174 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10176 if (mmf_attrs_commit(player->attrs)) {
10177 LOGE("failed to commit.\n");
10181 LOGD("next uri %s(%d)\n", uri, uri_idx);
10187 LOGE("unable to play next path. EOS will be posted soon.\n");
10192 __mmplayer_initialize_next_play(mm_player_t *player)
10198 player->smooth_streaming = FALSE;
10199 player->videodec_linked = 0;
10200 player->audiodec_linked = 0;
10201 player->videosink_linked = 0;
10202 player->audiosink_linked = 0;
10203 player->textsink_linked = 0;
10204 player->is_external_subtitle_present = FALSE;
10205 player->is_external_subtitle_added_now = FALSE;
10206 player->not_supported_codec = MISSING_PLUGIN_NONE;
10207 player->can_support_codec = FOUND_PLUGIN_NONE;
10208 player->pending_seek.is_pending = FALSE;
10209 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10210 player->pending_seek.pos = 0;
10211 player->msg_posted = FALSE;
10212 player->has_many_types = FALSE;
10213 player->no_more_pad = FALSE;
10214 player->not_found_demuxer = 0;
10215 player->doing_seek = FALSE;
10216 player->max_audio_channels = 0;
10217 player->is_subtitle_force_drop = FALSE;
10218 player->play_subtitle = FALSE;
10219 player->adjust_subtitle_pos = 0;
10221 player->total_bitrate = 0;
10222 player->total_maximum_bitrate = 0;
10224 _mmplayer_track_initialize(player);
10225 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10227 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10228 player->bitrate[i] = 0;
10229 player->maximum_bitrate[i] = 0;
10232 if (player->v_stream_caps) {
10233 gst_caps_unref(player->v_stream_caps);
10234 player->v_stream_caps = NULL;
10237 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10239 /* clean found parsers */
10240 if (player->parsers) {
10241 GList *parsers = player->parsers;
10242 for (; parsers; parsers = g_list_next(parsers)) {
10243 gchar *name = parsers->data;
10244 MMPLAYER_FREEIF(name);
10246 g_list_free(player->parsers);
10247 player->parsers = NULL;
10250 /* clean found audio decoders */
10251 if (player->audio_decoders) {
10252 GList *a_dec = player->audio_decoders;
10253 for (; a_dec; a_dec = g_list_next(a_dec)) {
10254 gchar *name = a_dec->data;
10255 MMPLAYER_FREEIF(name);
10257 g_list_free(player->audio_decoders);
10258 player->audio_decoders = NULL;
10265 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10267 MMPlayerGstElement *mainbin = NULL;
10268 MMMessageParamType msg_param = {0,};
10269 GstElement *element = NULL;
10270 MMHandleType attrs = 0;
10272 enum MainElementID elemId = MMPLAYER_M_NUM;
10276 if ((player == NULL) ||
10277 (player->pipeline == NULL) ||
10278 (player->pipeline->mainbin == NULL)) {
10279 LOGE("player is null.\n");
10283 mainbin = player->pipeline->mainbin;
10284 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10286 attrs = MMPLAYER_GET_ATTRS(player);
10288 LOGE("fail to get attributes.\n");
10292 /* Initialize Player values */
10293 __mmplayer_initialize_next_play(player);
10295 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10297 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10298 LOGE("failed to parse profile\n");
10299 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10303 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10304 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10305 LOGE("it's dash or hls. not support.");
10306 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10311 switch (player->profile.uri_type) {
10313 case MM_PLAYER_URI_TYPE_FILE:
10315 LOGD("using filesrc for 'file://' handler.\n");
10316 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10317 LOGE("failed to get storage info");
10321 element = gst_element_factory_make("filesrc", "source");
10324 LOGE("failed to create filesrc\n");
10328 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10331 case MM_PLAYER_URI_TYPE_URL_HTTP:
10333 gchar *user_agent, *cookies, **cookie_list;
10334 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10335 user_agent = cookies = NULL;
10336 cookie_list = NULL;
10338 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10340 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10343 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10345 /* get attribute */
10346 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10347 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10349 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10350 LOGD("get timeout from ini\n");
10351 http_timeout = player->ini.http_timeout;
10354 /* get attribute */
10355 SECURE_LOGD("location : %s\n", player->profile.uri);
10356 SECURE_LOGD("cookies : %s\n", cookies);
10357 SECURE_LOGD("user_agent : %s\n", user_agent);
10358 LOGD("timeout : %d\n", http_timeout);
10360 /* setting property to streaming source */
10361 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10362 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10363 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10365 /* parsing cookies */
10366 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10367 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10369 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10373 LOGE("not support uri type %d\n", player->profile.uri_type);
10378 LOGE("no source element was created.\n");
10382 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10383 LOGE("failed to add source element to pipeline\n");
10384 gst_object_unref(GST_OBJECT(element));
10389 /* take source element */
10390 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10391 mainbin[MMPLAYER_M_SRC].gst = element;
10395 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10396 if (player->streamer == NULL) {
10397 player->streamer = __mm_player_streaming_create();
10398 __mm_player_streaming_initialize(player->streamer);
10401 elemId = MMPLAYER_M_TYPEFIND;
10402 element = gst_element_factory_make("typefind", "typefinder");
10403 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10404 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10406 elemId = MMPLAYER_M_AUTOPLUG;
10407 element = __mmplayer_create_decodebin(player);
10410 /* check autoplug element is OK */
10412 LOGE("can not create element(%d)\n", elemId);
10416 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10417 LOGE("failed to add sinkbin to pipeline\n");
10418 gst_object_unref(GST_OBJECT(element));
10423 mainbin[elemId].id = elemId;
10424 mainbin[elemId].gst = element;
10426 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10427 LOGE("Failed to link src - autoplug(or typefind)\n");
10431 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10432 LOGE("Failed to change state of src element\n");
10436 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10437 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10438 LOGE("Failed to change state of decodebin\n");
10442 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10443 LOGE("Failed to change state of src element\n");
10448 player->gapless.stream_changed = TRUE;
10449 player->gapless.running = TRUE;
10455 MMPLAYER_PLAYBACK_UNLOCK(player);
10457 if (!player->msg_posted) {
10458 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10459 player->msg_posted = TRUE;
10466 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10468 mm_player_selector_t *selector = &player->selector[type];
10469 MMPlayerGstElement *sinkbin = NULL;
10470 enum MainElementID selectorId = MMPLAYER_M_NUM;
10471 enum MainElementID sinkId = MMPLAYER_M_NUM;
10472 GstPad *srcpad = NULL;
10473 GstPad *sinkpad = NULL;
10474 gboolean send_notice = FALSE;
10477 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10479 LOGD("type %d", type);
10482 case MM_PLAYER_TRACK_TYPE_AUDIO:
10483 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10484 sinkId = MMPLAYER_A_BIN;
10485 sinkbin = player->pipeline->audiobin;
10487 case MM_PLAYER_TRACK_TYPE_VIDEO:
10488 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10489 sinkId = MMPLAYER_V_BIN;
10490 sinkbin = player->pipeline->videobin;
10491 send_notice = TRUE;
10493 case MM_PLAYER_TRACK_TYPE_TEXT:
10494 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10495 sinkId = MMPLAYER_T_BIN;
10496 sinkbin = player->pipeline->textbin;
10499 LOGE("requested type is not supportable");
10504 if (player->pipeline->mainbin[selectorId].gst) {
10507 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10509 if (selector->event_probe_id != 0)
10510 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10511 selector->event_probe_id = 0;
10513 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10514 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10516 if (srcpad && sinkpad) {
10517 /* after getting drained signal there is no data flows, so no need to do pad_block */
10518 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10519 gst_pad_unlink(srcpad, sinkpad);
10521 /* send custom event to sink pad to handle it at video sink */
10523 LOGD("send custom event to sinkpad");
10524 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10525 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10526 gst_pad_send_event(sinkpad, event);
10530 gst_object_unref(sinkpad);
10533 gst_object_unref(srcpad);
10536 LOGD("selector release");
10538 /* release and unref requests pad from the selector */
10539 for (n = 0; n < selector->channels->len; n++) {
10540 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10541 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10543 g_ptr_array_set_size(selector->channels, 0);
10545 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10546 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10548 player->pipeline->mainbin[selectorId].gst = NULL;
10556 __mmplayer_deactivate_old_path(mm_player_t *player)
10559 MMPLAYER_RETURN_IF_FAIL(player);
10561 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10562 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10563 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10564 LOGE("deactivate selector error");
10568 _mmplayer_track_destroy(player);
10569 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10571 if (player->streamer) {
10572 __mm_player_streaming_deinitialize(player->streamer);
10573 __mm_player_streaming_destroy(player->streamer);
10574 player->streamer = NULL;
10577 MMPLAYER_PLAYBACK_LOCK(player);
10578 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10585 if (!player->msg_posted) {
10586 MMMessageParamType msg = {0,};
10589 msg.code = MM_ERROR_PLAYER_INTERNAL;
10590 LOGE("next_uri_play> deactivate error");
10592 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10593 player->msg_posted = TRUE;
10598 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10600 int result = MM_ERROR_NONE;
10601 mm_player_t* player = (mm_player_t*) hplayer;
10604 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10607 player->http_file_buffering_path = (gchar*)file_path;
10608 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10614 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10616 int result = MM_ERROR_NONE;
10617 mm_player_t* player = (mm_player_t*) hplayer;
10620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10622 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10623 if (mmf_attrs_commit(player->attrs)) {
10624 LOGE("failed to commit the original uri.\n");
10625 result = MM_ERROR_PLAYER_INTERNAL;
10627 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10628 LOGE("failed to add the original uri in the uri list.\n");
10635 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10637 mm_player_t* player = (mm_player_t*) hplayer;
10638 guint num_of_list = 0;
10642 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10643 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10645 if (player->pipeline && player->pipeline->textbin) {
10646 LOGE("subtitle path is enabled.\n");
10647 return MM_ERROR_PLAYER_INVALID_STATE;
10650 num_of_list = g_list_length(player->uri_info.uri_list);
10652 if (is_first_path == TRUE) {
10653 if (num_of_list == 0) {
10654 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10655 LOGD("add original path : %s", uri);
10657 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10658 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10660 LOGD("change original path : %s", uri);
10663 MMHandleType attrs = 0;
10664 attrs = MMPLAYER_GET_ATTRS(player);
10666 if (num_of_list == 0) {
10667 char *original_uri = NULL;
10670 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10672 if (!original_uri) {
10673 LOGE("there is no original uri.");
10674 return MM_ERROR_PLAYER_INVALID_STATE;
10677 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10678 player->uri_info.uri_idx = 0;
10680 LOGD("add original path at first : %s(%d)", original_uri);
10684 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10685 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10689 return MM_ERROR_NONE;
10692 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10694 mm_player_t* player = (mm_player_t*) hplayer;
10695 char *next_uri = NULL;
10696 guint num_of_list = 0;
10699 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10701 num_of_list = g_list_length(player->uri_info.uri_list);
10703 if (num_of_list > 0) {
10704 gint uri_idx = player->uri_info.uri_idx;
10706 if (uri_idx < num_of_list-1)
10711 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10712 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10714 *uri = g_strdup(next_uri);
10718 return MM_ERROR_NONE;
10722 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10723 GstCaps *caps, gpointer data)
10725 mm_player_t* player = (mm_player_t*)data;
10726 const gchar* klass = NULL;
10727 const gchar* mime = NULL;
10728 gchar* caps_str = NULL;
10730 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10731 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10732 caps_str = gst_caps_to_string(caps);
10734 LOGW("unknown type of caps : %s from %s",
10735 caps_str, GST_ELEMENT_NAME(elem));
10737 MMPLAYER_FREEIF(caps_str);
10739 /* There is no available codec. */
10740 __mmplayer_check_not_supported_codec(player, klass, mime);
10744 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10745 GstCaps * caps, gpointer data)
10747 mm_player_t* player = (mm_player_t*)data;
10748 const char* mime = NULL;
10749 gboolean ret = TRUE;
10751 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10752 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10754 if (g_str_has_prefix(mime, "audio")) {
10755 GstStructure* caps_structure = NULL;
10756 gint samplerate = 0;
10758 gchar *caps_str = NULL;
10760 caps_structure = gst_caps_get_structure(caps, 0);
10761 gst_structure_get_int(caps_structure, "rate", &samplerate);
10762 gst_structure_get_int(caps_structure, "channels", &channels);
10764 if ((channels > 0 && samplerate == 0)) {
10765 LOGD("exclude audio...");
10769 caps_str = gst_caps_to_string(caps);
10770 /* set it directly because not sent by TAG */
10771 if (g_strrstr(caps_str, "mobile-xmf"))
10772 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10773 MMPLAYER_FREEIF(caps_str);
10774 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10775 MMMessageParamType msg_param;
10776 memset(&msg_param, 0, sizeof(MMMessageParamType));
10777 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10778 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10779 LOGD("video file is not supported on this device");
10781 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10782 LOGD("already video linked");
10785 LOGD("found new stream");
10792 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10794 int ret = MM_ERROR_NONE;
10796 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10798 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10799 GstStructure* str = NULL;
10801 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10803 LOGD("audio codec type: %d", codec_type);
10804 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10805 /* sw codec will be skipped */
10806 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10807 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10808 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10809 ret = MM_ERROR_PLAYER_INTERNAL;
10813 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10814 /* hw codec will be skipped */
10815 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10816 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10817 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10818 ret = MM_ERROR_PLAYER_INTERNAL;
10823 str = gst_caps_get_structure(caps, 0);
10825 gst_structure_get_int(str, "channels", &channels);
10827 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10828 if (player->max_audio_channels < channels)
10829 player->max_audio_channels = channels;
10831 /* set stream information */
10832 if (!player->audiodec_linked)
10833 __mmplayer_set_audio_attrs(player, caps);
10835 /* update codec info */
10836 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10837 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10838 player->audiodec_linked = 1;
10840 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10842 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10844 LOGD("video codec type: %d", codec_type);
10845 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10846 /* sw codec is skipped */
10847 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10848 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10849 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10850 ret = MM_ERROR_PLAYER_INTERNAL;
10854 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10855 /* hw codec is skipped */
10856 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10857 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10858 ret = MM_ERROR_PLAYER_INTERNAL;
10863 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10864 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10866 /* mark video decoder for acquire */
10867 if (player->video_decoder_resource == NULL) {
10868 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10869 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10870 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10871 &player->video_decoder_resource)
10872 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10873 LOGE("could not mark video_decoder resource for acquire");
10874 ret = MM_ERROR_PLAYER_INTERNAL;
10878 LOGW("video decoder resource is already acquired, skip it.");
10879 ret = MM_ERROR_PLAYER_INTERNAL;
10883 player->interrupted_by_resource = FALSE;
10884 /* acquire resources for video playing */
10885 if (mm_resource_manager_commit(player->resource_manager)
10886 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10887 LOGE("could not acquire resources for video decoding\n");
10888 ret = MM_ERROR_PLAYER_INTERNAL;
10893 /* update codec info */
10894 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10895 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10896 player->videodec_linked = 1;
10904 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10905 GstCaps* caps, GstElementFactory* factory, gpointer data)
10907 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10908 We are defining our own and will be removed when it actually exposed */
10910 GST_AUTOPLUG_SELECT_TRY,
10911 GST_AUTOPLUG_SELECT_EXPOSE,
10912 GST_AUTOPLUG_SELECT_SKIP
10913 } GstAutoplugSelectResult;
10915 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10916 mm_player_t* player = (mm_player_t*)data;
10918 gchar* factory_name = NULL;
10919 gchar* caps_str = NULL;
10920 const gchar* klass = NULL;
10923 factory_name = GST_OBJECT_NAME(factory);
10924 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10925 caps_str = gst_caps_to_string(caps);
10927 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10929 /* store type string */
10930 if (player->type == NULL) {
10931 player->type = gst_caps_to_string(caps);
10932 __mmplayer_update_content_type_info(player);
10935 /* filtering exclude keyword */
10936 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10937 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10938 LOGW("skipping [%s] by exculde keyword [%s]\n",
10939 factory_name, player->ini.exclude_element_keyword[idx]);
10941 result = GST_AUTOPLUG_SELECT_SKIP;
10946 /* exclude webm format */
10947 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10948 * because webm format is not supportable.
10949 * If webm is disabled in "autoplug-continue", there is no state change
10950 * failure or error because the decodebin will expose the pad directly.
10951 * It make MSL invoke _prepare_async_callback.
10952 * So, we need to disable webm format in "autoplug-select" */
10953 if (caps_str && strstr(caps_str, "webm")) {
10954 LOGW("webm is not supported");
10955 result = GST_AUTOPLUG_SELECT_SKIP;
10959 /* check factory class for filtering */
10960 /* NOTE : msl don't need to use image plugins.
10961 * So, those plugins should be skipped for error handling.
10963 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10964 LOGD("skipping [%s] by not required\n", factory_name);
10965 result = GST_AUTOPLUG_SELECT_SKIP;
10969 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10970 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10971 // TO CHECK : subtitle if needed, add subparse exception.
10972 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10973 result = GST_AUTOPLUG_SELECT_SKIP;
10977 if (g_strrstr(factory_name, "mpegpsdemux")) {
10978 LOGD("skipping PS container - not support\n");
10979 result = GST_AUTOPLUG_SELECT_SKIP;
10983 if (g_strrstr(factory_name, "mssdemux"))
10984 player->smooth_streaming = TRUE;
10986 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10987 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10990 GstStructure *str = NULL;
10991 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10993 /* don't make video because of not required */
10994 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10995 (player->set_mode.media_packet_video_stream == FALSE)) {
10996 LOGD("no video because it's not required. -> return expose");
10997 result = GST_AUTOPLUG_SELECT_EXPOSE;
11001 /* get w/h for omx state-tune */
11002 /* FIXME: deprecated? */
11003 str = gst_caps_get_structure(caps, 0);
11004 gst_structure_get_int(str, "width", &width);
11007 if (player->v_stream_caps) {
11008 gst_caps_unref(player->v_stream_caps);
11009 player->v_stream_caps = NULL;
11012 player->v_stream_caps = gst_caps_copy(caps);
11013 LOGD("take caps for video state tune");
11014 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11018 if (g_strrstr(klass, "Codec/Decoder")) {
11019 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11020 LOGD("skipping %s codec", factory_name);
11021 result = GST_AUTOPLUG_SELECT_SKIP;
11027 MMPLAYER_FREEIF(caps_str);
11033 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11036 //mm_player_t* player = (mm_player_t*)data;
11037 GstCaps* caps = NULL;
11039 LOGD("[Decodebin2] pad-removed signal\n");
11041 caps = gst_pad_query_caps(new_pad, NULL);
11043 gchar* caps_str = NULL;
11044 caps_str = gst_caps_to_string(caps);
11046 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11048 MMPLAYER_FREEIF(caps_str);
11049 gst_caps_unref(caps);
11054 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11056 mm_player_t* player = (mm_player_t*)data;
11057 GstIterator *iter = NULL;
11058 GValue item = { 0, };
11059 GstPad *pad = NULL;
11060 gboolean done = FALSE;
11061 gboolean is_all_drained = TRUE;
11064 MMPLAYER_RETURN_IF_FAIL(player);
11066 LOGD("__mmplayer_gst_decode_drained");
11068 if (player->use_deinterleave == TRUE) {
11069 LOGD("group playing mode.");
11073 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11074 LOGW("Fail to get cmd lock");
11078 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11079 !__mmplayer_verify_next_play_path(player)) {
11080 LOGD("decoding is finished.");
11081 __mmplayer_reset_gapless_state(player);
11082 MMPLAYER_CMD_UNLOCK(player);
11086 player->gapless.reconfigure = TRUE;
11088 /* check decodebin src pads whether they received EOS or not */
11089 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11092 switch (gst_iterator_next(iter, &item)) {
11093 case GST_ITERATOR_OK:
11094 pad = g_value_get_object(&item);
11095 if (pad && !GST_PAD_IS_EOS(pad)) {
11096 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11097 is_all_drained = FALSE;
11100 g_value_reset(&item);
11102 case GST_ITERATOR_RESYNC:
11103 gst_iterator_resync(iter);
11105 case GST_ITERATOR_ERROR:
11106 case GST_ITERATOR_DONE:
11111 g_value_unset(&item);
11112 gst_iterator_free(iter);
11114 if (!is_all_drained) {
11115 LOGD("Wait util the all pads get EOS.");
11116 MMPLAYER_CMD_UNLOCK(player);
11121 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11122 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11124 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11125 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11126 __mmplayer_deactivate_old_path(player);
11127 MMPLAYER_CMD_UNLOCK(player);
11133 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11135 mm_player_t* player = (mm_player_t*)data;
11136 const gchar* klass = NULL;
11137 gchar* factory_name = NULL;
11139 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11140 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11142 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11144 if (__mmplayer_add_dump_buffer_probe(player, element))
11145 LOGD("add buffer probe");
11148 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11149 gchar* selected = NULL;
11150 selected = g_strdup(GST_ELEMENT_NAME(element));
11151 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11155 if (g_strrstr(klass, "Parser")) {
11156 gchar* selected = NULL;
11158 selected = g_strdup(factory_name);
11159 player->parsers = g_list_append(player->parsers, selected);
11162 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11163 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11164 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11166 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11167 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11169 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11170 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11171 "max-video-width", player->adaptive_info.limit.width,
11172 "max-video-height", player->adaptive_info.limit.height, NULL);
11174 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11175 /* FIXIT : first value will be overwritten if there's more
11176 * than 1 demuxer/parser
11179 //LOGD("plugged element is demuxer. take it\n");
11180 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11181 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11183 /*Added for multi audio support */ // Q. del?
11184 if (g_strrstr(klass, "Demux")) {
11185 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11186 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11190 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11191 int surface_type = 0;
11193 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11196 // to support trust-zone only
11197 if (g_strrstr(factory_name, "asfdemux")) {
11198 LOGD("set file-location %s\n", player->profile.uri);
11199 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11201 if (player->video_hub_download_mode == TRUE)
11202 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11203 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11204 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11205 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11206 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11207 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11208 (__mmplayer_is_only_mp3_type(player->type))) {
11209 LOGD("[mpegaudioparse] set streaming pull mode.");
11210 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11212 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11213 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11216 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11217 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11218 LOGD("plugged element is multiqueue. take it\n");
11220 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11221 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11223 if (!MMPLAYER_IS_HTTP_PD(player) &&
11224 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11225 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11226 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11227 __mm_player_streaming_set_multiqueue(player->streamer,
11230 player->ini.http_buffering_time,
11232 player->ini.http_buffering_limit);
11234 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11241 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11244 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11246 if (MMPLAYER_IS_STREAMING(player))
11249 /* This callback can be set to music player only. */
11250 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11251 LOGW("audio callback is not supported for video");
11255 if (player->audio_stream_cb) {
11256 GstPad *pad = NULL;
11258 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11261 LOGE("failed to get sink pad from audiosink to probe data\n");
11264 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11265 __mmplayer_audio_stream_probe, player, NULL);
11267 gst_object_unref(pad);
11271 LOGE("There is no audio callback to configure.\n");
11281 __mmplayer_release_misc(mm_player_t* player)
11284 bool cur_mode = player->set_mode.rich_audio;
11287 MMPLAYER_RETURN_IF_FAIL(player);
11289 player->video_stream_cb = NULL;
11290 player->video_stream_cb_user_param = NULL;
11291 player->video_stream_prerolled = FALSE;
11293 player->audio_stream_cb = NULL;
11294 player->audio_stream_render_cb_ex = NULL;
11295 player->audio_stream_cb_user_param = NULL;
11296 player->audio_stream_sink_sync = false;
11298 player->video_stream_changed_cb = NULL;
11299 player->video_stream_changed_cb_user_param = NULL;
11301 player->audio_stream_changed_cb = NULL;
11302 player->audio_stream_changed_cb_user_param = NULL;
11304 player->sent_bos = FALSE;
11305 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11307 player->doing_seek = FALSE;
11309 player->total_bitrate = 0;
11310 player->total_maximum_bitrate = 0;
11312 player->not_found_demuxer = 0;
11314 player->last_position = 0;
11315 player->duration = 0;
11316 player->http_content_size = 0;
11317 player->not_supported_codec = MISSING_PLUGIN_NONE;
11318 player->can_support_codec = FOUND_PLUGIN_NONE;
11319 player->pending_seek.is_pending = FALSE;
11320 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11321 player->pending_seek.pos = 0;
11322 player->msg_posted = FALSE;
11323 player->has_many_types = FALSE;
11324 player->max_audio_channels = 0;
11325 player->video_share_api_delta = 0;
11326 player->video_share_clock_delta = 0;
11327 player->is_subtitle_force_drop = FALSE;
11328 player->play_subtitle = FALSE;
11329 player->adjust_subtitle_pos = 0;
11330 player->last_multiwin_status = FALSE;
11331 player->has_closed_caption = FALSE;
11332 player->set_mode.media_packet_video_stream = FALSE;
11333 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11334 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11336 player->set_mode.rich_audio = cur_mode;
11338 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11339 player->bitrate[i] = 0;
11340 player->maximum_bitrate[i] = 0;
11343 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11345 /* remove media stream cb(appsrc cb) */
11346 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11347 player->media_stream_buffer_status_cb[i] = NULL;
11348 player->media_stream_seek_data_cb[i] = NULL;
11349 player->buffer_cb_user_param[i] = NULL;
11350 player->seek_cb_user_param[i] = NULL;
11352 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11354 /* free memory related to audio effect */
11355 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11357 if (player->adaptive_info.var_list) {
11358 g_list_free_full(player->adaptive_info.var_list, g_free);
11359 player->adaptive_info.var_list = NULL;
11362 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11363 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11364 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11366 /* Reset video360 settings to their defaults in case if the pipeline is to be
11369 player->video360_metadata.is_spherical = -1;
11370 player->is_openal_plugin_used = FALSE;
11372 player->is_content_spherical = FALSE;
11373 player->is_video360_enabled = TRUE;
11374 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11375 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11376 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11377 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11378 player->video360_zoom = 1.0f;
11379 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11380 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11382 player->sound.rg_enable = false;
11388 __mmplayer_release_misc_post(mm_player_t* player)
11390 char *original_uri = NULL;
11393 /* player->pipeline is already released before. */
11395 MMPLAYER_RETURN_IF_FAIL(player);
11397 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11399 /* clean found parsers */
11400 if (player->parsers) {
11401 GList *parsers = player->parsers;
11402 for (; parsers; parsers = g_list_next(parsers)) {
11403 gchar *name = parsers->data;
11404 MMPLAYER_FREEIF(name);
11406 g_list_free(player->parsers);
11407 player->parsers = NULL;
11410 /* clean found audio decoders */
11411 if (player->audio_decoders) {
11412 GList *a_dec = player->audio_decoders;
11413 for (; a_dec; a_dec = g_list_next(a_dec)) {
11414 gchar *name = a_dec->data;
11415 MMPLAYER_FREEIF(name);
11417 g_list_free(player->audio_decoders);
11418 player->audio_decoders = NULL;
11421 /* clean the uri list except original uri */
11422 if (player->uri_info.uri_list) {
11423 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11425 if (player->attrs) {
11426 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11427 LOGD("restore original uri = %s\n", original_uri);
11429 if (mmf_attrs_commit(player->attrs))
11430 LOGE("failed to commit the original uri.\n");
11433 GList *uri_list = player->uri_info.uri_list;
11434 for (; uri_list; uri_list = g_list_next(uri_list)) {
11435 gchar *uri = uri_list->data;
11436 MMPLAYER_FREEIF(uri);
11438 g_list_free(player->uri_info.uri_list);
11439 player->uri_info.uri_list = NULL;
11442 /* clear the audio stream buffer list */
11443 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11445 /* clear the video stream bo list */
11446 __mmplayer_video_stream_destroy_bo_list(player);
11447 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11449 if (player->profile.input_mem.buf) {
11450 free(player->profile.input_mem.buf);
11451 player->profile.input_mem.buf = NULL;
11453 player->profile.input_mem.len = 0;
11454 player->profile.input_mem.offset = 0;
11456 player->uri_info.uri_idx = 0;
11460 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11462 GstElement *element = NULL;
11465 LOGD("creating %s to plug\n", name);
11467 element = gst_element_factory_make(name, NULL);
11469 LOGE("failed to create queue\n");
11473 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11474 LOGE("failed to set state READY to %s\n", name);
11475 gst_object_unref(element);
11479 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11480 LOGE("failed to add %s\n", name);
11481 gst_object_unref(element);
11485 sinkpad = gst_element_get_static_pad(element, "sink");
11487 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11488 LOGE("failed to link %s\n", name);
11489 gst_object_unref(sinkpad);
11490 gst_object_unref(element);
11494 LOGD("linked %s to pipeline successfully\n", name);
11496 gst_object_unref(sinkpad);
11502 __mmplayer_check_subtitle(mm_player_t* player)
11504 MMHandleType attrs = 0;
11505 char *subtitle_uri = NULL;
11509 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11511 /* get subtitle attribute */
11512 attrs = MMPLAYER_GET_ATTRS(player);
11516 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11517 if (!subtitle_uri || !strlen(subtitle_uri))
11520 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11521 player->is_external_subtitle_present = TRUE;
11529 __mmplayer_can_extract_pcm(mm_player_t* player)
11531 MMHandleType attrs = 0;
11532 gboolean sound_extraction = FALSE;
11534 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11536 attrs = MMPLAYER_GET_ATTRS(player);
11538 LOGE("fail to get attributes.");
11542 /* get sound_extraction property */
11543 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11545 if (!sound_extraction) {
11546 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11554 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11557 MMMessageParamType msg_param;
11558 gchar *msg_src_element = NULL;
11559 GstStructure *s = NULL;
11560 guint error_id = 0;
11561 gchar *error_string = NULL;
11565 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11566 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11568 s = gst_structure_copy(gst_message_get_structure(message));
11571 if (!gst_structure_get_uint(s, "error_id", &error_id))
11572 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11574 switch (error_id) {
11575 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11576 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11578 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11579 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11581 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11582 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11584 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11585 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11587 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11588 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11590 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11591 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11593 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11594 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11596 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11597 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11599 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11600 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11602 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11603 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11605 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11606 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11608 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11609 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11611 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11612 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11614 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11615 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11617 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11618 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11620 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11621 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11623 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11624 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11626 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11627 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11629 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11630 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11632 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11633 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11635 case MMPLAYER_STREAMING_ERROR_GONE:
11636 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11638 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11639 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11641 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11642 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11644 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11645 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11647 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11648 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11650 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11651 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11653 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11654 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11656 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11657 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11659 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11660 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11662 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11663 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11665 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11666 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11668 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11669 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11671 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11672 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11674 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11675 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11677 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11678 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11680 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11681 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11683 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11684 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11686 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11687 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11689 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11690 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11692 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11693 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11695 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11696 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11698 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11699 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11701 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11702 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11704 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11705 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11707 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11708 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11712 gst_structure_free(s);
11713 return MM_ERROR_PLAYER_STREAMING_FAIL;
11717 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11719 msg_param.data = (void *) error_string;
11721 if (message->src) {
11722 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11724 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11725 msg_src_element, msg_param.code, (char*)msg_param.data);
11728 /* post error to application */
11729 if (!player->msg_posted) {
11730 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11732 /* don't post more if one was sent already */
11733 player->msg_posted = TRUE;
11735 LOGD("skip error post because it's sent already.\n");
11737 gst_structure_free(s);
11739 g_free(error_string);
11746 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11748 MMPLAYER_RETURN_IF_FAIL(player);
11750 /* post now if delay is zero */
11751 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11752 LOGD("eos delay is zero. posting EOS now\n");
11753 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11755 if (player->set_mode.pcm_extraction)
11756 __mmplayer_cancel_eos_timer(player);
11761 /* cancel if existing */
11762 __mmplayer_cancel_eos_timer(player);
11764 /* init new timeout */
11765 /* NOTE : consider give high priority to this timer */
11766 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11768 player->eos_timer = g_timeout_add(delay_in_ms,
11769 __mmplayer_eos_timer_cb, player);
11771 player->context.global_default = g_main_context_default();
11772 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11774 /* check timer is valid. if not, send EOS now */
11775 if (player->eos_timer == 0) {
11776 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11777 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11782 __mmplayer_cancel_eos_timer(mm_player_t* player)
11784 MMPLAYER_RETURN_IF_FAIL(player);
11786 if (player->eos_timer) {
11787 LOGD("cancel eos timer");
11788 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11789 player->eos_timer = 0;
11796 __mmplayer_eos_timer_cb(gpointer u_data)
11798 mm_player_t* player = NULL;
11799 MMHandleType attrs = 0;
11802 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11804 player = (mm_player_t*) u_data;
11805 attrs = MMPLAYER_GET_ATTRS(player);
11807 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11810 gint ret_value = 0;
11811 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11812 if (ret_value != MM_ERROR_NONE)
11813 LOGE("seeking to 0 failed in repeat play");
11816 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11819 /* we are returning FALSE as we need only one posting */
11823 /* sending event to one of sinkelements */
11825 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11827 GstEvent * event2 = NULL;
11828 GList *sinks = NULL;
11829 gboolean res = FALSE;
11832 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11833 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11835 /* While adding subtitles in live feeds seek is getting called.
11836 Adding defensive check in framework layer.*/
11837 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11838 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11839 LOGE("Should not send seek event during live playback");
11844 if (player->play_subtitle)
11845 event2 = gst_event_copy((const GstEvent *)event);
11847 sinks = player->sink_elements;
11849 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11851 if (GST_IS_ELEMENT(sink)) {
11852 /* keep ref to the event */
11853 gst_event_ref(event);
11855 if ((res = gst_element_send_event(sink, event))) {
11856 LOGD("sending event[%s] to sink element [%s] success!\n",
11857 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11859 /* rtsp case, asyn_done is not called after seek during pause state */
11860 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11861 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11862 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11863 LOGD("RTSP seek completed, after pause state..\n");
11864 player->doing_seek = FALSE;
11865 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11871 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11872 sinks = g_list_next(sinks);
11879 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11880 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11883 sinks = g_list_next(sinks);
11886 /* Note : Textbin is not linked to the video or audio bin.
11887 * It needs to send the event to the text sink seperatelly.
11889 if (player->play_subtitle && player->pipeline) {
11890 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11892 if (GST_IS_ELEMENT(text_sink)) {
11893 /* keep ref to the event */
11894 gst_event_ref(event2);
11896 if ((res = gst_element_send_event(text_sink, event2)))
11897 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11898 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11900 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11901 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11903 gst_event_unref(event2);
11907 gst_event_unref(event);
11915 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11919 MMPLAYER_RETURN_IF_FAIL(player);
11920 MMPLAYER_RETURN_IF_FAIL(sink);
11922 player->sink_elements =
11923 g_list_append(player->sink_elements, sink);
11929 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11933 MMPLAYER_RETURN_IF_FAIL(player);
11934 MMPLAYER_RETURN_IF_FAIL(sink);
11936 player->sink_elements =
11937 g_list_remove(player->sink_elements, sink);
11943 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11944 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11945 gint64 cur, GstSeekType stop_type, gint64 stop)
11947 GstEvent* event = NULL;
11948 gboolean result = FALSE;
11952 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11954 if (player->pipeline && player->pipeline->textbin)
11955 __mmplayer_drop_subtitle(player, FALSE);
11957 event = gst_event_new_seek(rate, format, flags, cur_type,
11958 cur, stop_type, stop);
11960 result = __gst_send_event_to_sink(player, event);
11967 /* NOTE : be careful with calling this api. please refer to below glib comment
11968 * glib comment : Note that there is a bug in GObject that makes this function much
11969 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11970 * will no longer be called, but, the signal handler is not currently disconnected.
11971 * If the instance is itself being freed at the same time than this doesn't matter,
11972 * since the signal will automatically be removed, but if instance persists,
11973 * then the signal handler will leak. You should not remove the signal yourself
11974 * because in a future versions of GObject, the handler will automatically be
11977 * It's possible to work around this problem in a way that will continue to work
11978 * with future versions of GObject by checking that the signal handler is still
11979 * connected before disconnected it:
11981 * if (g_signal_handler_is_connected(instance, id))
11982 * g_signal_handler_disconnect(instance, id);
11985 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11987 GList* sig_list = NULL;
11988 MMPlayerSignalItem* item = NULL;
11992 MMPLAYER_RETURN_IF_FAIL(player);
11994 LOGD("release signals type : %d", type);
11996 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11997 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11998 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11999 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12000 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12001 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12005 sig_list = player->signals[type];
12007 for (; sig_list; sig_list = sig_list->next) {
12008 item = sig_list->data;
12010 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12011 if (g_signal_handler_is_connected(item->obj, item->sig))
12012 g_signal_handler_disconnect(item->obj, item->sig);
12015 MMPLAYER_FREEIF(item);
12018 g_list_free(player->signals[type]);
12019 player->signals[type] = NULL;
12026 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12028 mm_player_t* player = 0;
12029 int prev_display_surface_type = 0;
12030 void *prev_display_overlay = NULL;
12031 const gchar *klass = NULL;
12032 gchar *cur_videosink_name = NULL;
12035 int num_of_dec = 2; /* DEC1, DEC2 */
12039 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12040 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12042 player = MM_PLAYER_CAST(handle);
12044 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12045 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12047 return MM_ERROR_INVALID_ARGUMENT;
12050 /* load previous attributes */
12051 if (player->attrs) {
12052 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12053 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12054 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12055 if (prev_display_surface_type == surface_type) {
12056 LOGD("incoming display surface type is same as previous one, do nothing..");
12058 return MM_ERROR_NONE;
12061 LOGE("failed to load attributes");
12063 return MM_ERROR_PLAYER_INTERNAL;
12066 /* check videosink element is created */
12067 if (!player->pipeline || !player->pipeline->videobin ||
12068 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12069 LOGD("videosink element is not yet ready");
12071 /* videobin is not created yet, so we just set attributes related to display surface */
12072 LOGD("store display attribute for given surface type(%d)", surface_type);
12073 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12074 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12075 if (mmf_attrs_commit(player->attrs)) {
12076 LOGE("failed to commit attribute");
12078 return MM_ERROR_PLAYER_INTERNAL;
12081 return MM_ERROR_NONE;
12083 /* get player command status */
12084 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12085 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12087 return MM_ERROR_PLAYER_INVALID_STATE;
12090 /* surface change */
12091 for (i = 0 ; i < num_of_dec ; i++) {
12092 if (player->pipeline->mainbin &&
12093 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12094 GstElementFactory *decfactory;
12095 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12097 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12098 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12099 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12100 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12104 LOGW("success to changing display surface(%d)", surface_type);
12106 return MM_ERROR_NONE;
12108 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12109 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12113 LOGW("success to changing display surface(%d)", surface_type);
12115 return MM_ERROR_NONE;
12118 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12119 ret = MM_ERROR_PLAYER_INTERNAL;
12128 /* rollback to previous attributes */
12129 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12130 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12131 if (mmf_attrs_commit(player->attrs)) {
12132 LOGE("failed to commit attributes to rollback");
12134 return MM_ERROR_PLAYER_INTERNAL;
12140 /* NOTE : It does not support some use cases, eg using colorspace converter */
12142 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12144 GstPad *src_pad_dec = NULL;
12145 GstPad *sink_pad_videosink = NULL;
12146 GstPad *sink_pad_videobin = NULL;
12147 GstClock *clock = NULL;
12148 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12149 int ret = MM_ERROR_NONE;
12150 gboolean is_audiobin_created = TRUE;
12154 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12155 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12156 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12158 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12159 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12161 /* get information whether if audiobin is created */
12162 if (!player->pipeline->audiobin ||
12163 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12164 LOGW("audiobin is null, this video content may not have audio data");
12165 is_audiobin_created = FALSE;
12168 /* get current state of player */
12169 previous_state = MMPLAYER_CURRENT_STATE(player);
12170 LOGD("previous state(%d)", previous_state);
12173 /* get src pad of decoder and block it */
12174 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12175 if (!src_pad_dec) {
12176 LOGE("failed to get src pad from decode in mainbin");
12177 return MM_ERROR_PLAYER_INTERNAL;
12180 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12181 LOGW("trying to block pad(video)");
12182 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12183 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12186 LOGE("failed to set block pad(video)");
12187 return MM_ERROR_PLAYER_INTERNAL;
12189 LOGW("pad is blocked(video)");
12191 /* no data flows, so no need to do pad_block */
12192 if (player->doing_seek)
12193 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12195 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12199 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12200 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12201 LOGE("failed to remove previous ghost_pad for videobin");
12202 return MM_ERROR_PLAYER_INTERNAL;
12205 /* change state of videobin to NULL */
12206 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12207 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12208 if (ret != GST_STATE_CHANGE_SUCCESS) {
12209 LOGE("failed to change state of videobin to NULL");
12210 return MM_ERROR_PLAYER_INTERNAL;
12213 /* unlink between decoder and videobin and remove previous videosink from videobin */
12214 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12215 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12216 LOGE("failed to remove former videosink from videobin");
12217 return MM_ERROR_PLAYER_INTERNAL;
12220 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12222 /* create a new videosink and add it to videobin */
12223 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12224 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12225 LOGE("failed to create videosink element\n");
12227 return MM_ERROR_PLAYER_INTERNAL;
12229 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12230 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12231 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12233 /* save attributes */
12234 if (player->attrs) {
12235 /* set a new display surface type */
12236 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12237 /* set a new diplay overlay */
12238 switch (surface_type) {
12239 case MM_DISPLAY_SURFACE_OVERLAY:
12240 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12241 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12244 LOGE("invalid type(%d) for changing display surface", surface_type);
12246 return MM_ERROR_INVALID_ARGUMENT;
12248 if (mmf_attrs_commit(player->attrs)) {
12249 LOGE("failed to commit");
12251 return MM_ERROR_PLAYER_INTERNAL;
12254 LOGE("player->attrs is null, failed to save attributes");
12256 return MM_ERROR_PLAYER_INTERNAL;
12259 /* update video param */
12260 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12261 LOGE("failed to update video param");
12262 return MM_ERROR_PLAYER_INTERNAL;
12265 /* change state of videobin to READY */
12266 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12267 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12268 if (ret != GST_STATE_CHANGE_SUCCESS) {
12269 LOGE("failed to change state of videobin to READY");
12270 return MM_ERROR_PLAYER_INTERNAL;
12273 /* change ghostpad */
12274 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12275 if (!sink_pad_videosink) {
12276 LOGE("failed to get sink pad from videosink element");
12277 return MM_ERROR_PLAYER_INTERNAL;
12279 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12280 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12281 LOGE("failed to set active to ghost_pad");
12282 return MM_ERROR_PLAYER_INTERNAL;
12284 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12285 LOGE("failed to change ghostpad for videobin");
12286 return MM_ERROR_PLAYER_INTERNAL;
12288 gst_object_unref(sink_pad_videosink);
12290 /* link decoder with videobin */
12291 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12292 if (!sink_pad_videobin) {
12293 LOGE("failed to get sink pad from videobin");
12294 return MM_ERROR_PLAYER_INTERNAL;
12296 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12297 LOGE("failed to link");
12298 return MM_ERROR_PLAYER_INTERNAL;
12300 gst_object_unref(sink_pad_videobin);
12302 /* clock setting for a new videosink plugin */
12303 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12304 so we set it from audiosink plugin or pipeline(system clock) */
12305 if (!is_audiobin_created) {
12306 LOGW("audiobin is not created, get clock from pipeline..");
12307 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12309 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12313 GstClockTime base_time;
12314 LOGD("set the clock to videosink");
12315 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12316 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12318 LOGD("got clock of videosink");
12319 now = gst_clock_get_time(clock);
12320 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12321 LOGD("at time %" GST_TIME_FORMAT ", base %"
12322 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12324 LOGE("failed to get clock of videosink after setting clock");
12325 return MM_ERROR_PLAYER_INTERNAL;
12328 LOGW("failed to get clock, maybe it is the time before first playing");
12330 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12331 /* change state of videobin to PAUSED */
12332 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12333 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12334 if (ret != GST_STATE_CHANGE_FAILURE) {
12335 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12337 LOGE("failed to change state of videobin to PLAYING");
12338 return MM_ERROR_PLAYER_INTERNAL;
12341 /* release blocked and unref src pad of video decoder */
12343 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12344 LOGE("failed to set pad blocked FALSE(video)");
12345 return MM_ERROR_PLAYER_INTERNAL;
12348 LOGW("pad is unblocked(video)");
12350 if (player->doing_seek)
12351 LOGW("not completed seek(%d)", player->doing_seek);
12352 /* change state of videobin to PAUSED */
12353 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12354 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12355 if (ret != GST_STATE_CHANGE_FAILURE) {
12356 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12358 LOGE("failed to change state of videobin to PLAYING");
12359 return MM_ERROR_PLAYER_INTERNAL;
12362 /* already skipped pad block */
12363 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12366 /* do get/set position for new videosink plugin */
12368 gint64 position = 0;
12370 LOGD("do get/set position for new videosink plugin");
12371 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12372 LOGE("failed to get position");
12373 return MM_ERROR_PLAYER_INTERNAL;
12375 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12376 /* accurate seek */
12377 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12378 LOGE("failed to set position");
12379 return MM_ERROR_PLAYER_INTERNAL;
12382 /* key unit seek */
12383 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12384 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12385 GST_SEEK_TYPE_SET, position,
12386 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12388 LOGE("failed to set position");
12389 return MM_ERROR_PLAYER_INTERNAL;
12395 gst_object_unref(src_pad_dec);
12396 LOGD("success to change sink");
12400 return MM_ERROR_NONE;
12404 /* Note : if silent is true, then subtitle would not be displayed. :*/
12405 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12407 mm_player_t* player = (mm_player_t*) hplayer;
12411 /* check player handle */
12412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12414 player->set_mode.subtitle_off = silent;
12416 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12420 return MM_ERROR_NONE;
12423 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12425 MMPlayerGstElement* mainbin = NULL;
12426 MMPlayerGstElement* textbin = NULL;
12427 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12428 GstState current_state = GST_STATE_VOID_PENDING;
12429 GstState element_state = GST_STATE_VOID_PENDING;
12430 GstState element_pending_state = GST_STATE_VOID_PENDING;
12432 GstEvent *event = NULL;
12433 int result = MM_ERROR_NONE;
12435 GstClock *curr_clock = NULL;
12436 GstClockTime base_time, start_time, curr_time;
12441 /* check player handle */
12442 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12443 player->pipeline &&
12444 player->pipeline->mainbin &&
12445 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12447 mainbin = player->pipeline->mainbin;
12448 textbin = player->pipeline->textbin;
12450 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12452 // sync clock with current pipeline
12453 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12454 curr_time = gst_clock_get_time(curr_clock);
12456 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12457 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12459 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12460 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12462 if (current_state > GST_STATE_READY) {
12463 // sync state with current pipeline
12464 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12465 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12466 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12468 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12469 if (GST_STATE_CHANGE_FAILURE == ret) {
12470 LOGE("fail to state change.\n");
12471 result = MM_ERROR_PLAYER_INTERNAL;
12476 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12477 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12480 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12481 gst_object_unref(curr_clock);
12484 // seek to current position
12485 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12486 result = MM_ERROR_PLAYER_INVALID_STATE;
12487 LOGE("gst_element_query_position failed, invalid state\n");
12491 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12492 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);
12494 __gst_send_event_to_sink(player, event);
12496 result = MM_ERROR_PLAYER_INTERNAL;
12497 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12501 /* sync state with current pipeline */
12502 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12503 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12504 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12506 return MM_ERROR_NONE;
12509 /* release text pipeline resource */
12510 player->textsink_linked = 0;
12512 /* release signal */
12513 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12515 /* release textbin with it's childs */
12516 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12517 MMPLAYER_FREEIF(player->pipeline->textbin);
12518 player->pipeline->textbin = NULL;
12520 /* release subtitle elem */
12521 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12522 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12528 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12530 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12531 GstState current_state = GST_STATE_VOID_PENDING;
12533 MMHandleType attrs = 0;
12534 MMPlayerGstElement* mainbin = NULL;
12535 MMPlayerGstElement* textbin = NULL;
12537 gchar* subtitle_uri = NULL;
12538 int result = MM_ERROR_NONE;
12539 const gchar *charset = NULL;
12543 /* check player handle */
12544 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12545 player->pipeline &&
12546 player->pipeline->mainbin &&
12547 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12548 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12550 mainbin = player->pipeline->mainbin;
12551 textbin = player->pipeline->textbin;
12553 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12554 if (current_state < GST_STATE_READY) {
12555 result = MM_ERROR_PLAYER_INVALID_STATE;
12556 LOGE("Pipeline is not in proper state\n");
12560 attrs = MMPLAYER_GET_ATTRS(player);
12562 LOGE("cannot get content attribute\n");
12563 result = MM_ERROR_PLAYER_INTERNAL;
12567 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12568 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12569 LOGE("subtitle uri is not proper filepath\n");
12570 result = MM_ERROR_PLAYER_INVALID_URI;
12574 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12575 LOGE("failed to get storage info of subtitle path");
12576 result = MM_ERROR_PLAYER_INVALID_URI;
12580 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12581 LOGD("new subtitle file path is [%s]\n", filepath);
12583 if (!strcmp(filepath, subtitle_uri)) {
12584 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12587 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12588 if (mmf_attrs_commit(player->attrs)) {
12589 LOGE("failed to commit.\n");
12594 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12595 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12596 player->subtitle_language_list = NULL;
12597 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12599 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12600 if (ret != GST_STATE_CHANGE_SUCCESS) {
12601 LOGE("failed to change state of textbin to READY");
12602 result = MM_ERROR_PLAYER_INTERNAL;
12606 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12607 if (ret != GST_STATE_CHANGE_SUCCESS) {
12608 LOGE("failed to change state of subparse to READY");
12609 result = MM_ERROR_PLAYER_INTERNAL;
12613 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12614 if (ret != GST_STATE_CHANGE_SUCCESS) {
12615 LOGE("failed to change state of filesrc to READY");
12616 result = MM_ERROR_PLAYER_INTERNAL;
12620 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12622 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12624 charset = util_get_charset(filepath);
12626 LOGD("detected charset is %s\n", charset);
12627 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12630 result = _mmplayer_sync_subtitle_pipeline(player);
12637 /* API to switch between external subtitles */
12638 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12640 int result = MM_ERROR_NONE;
12641 mm_player_t* player = (mm_player_t*)hplayer;
12646 /* check player handle */
12647 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12649 /* filepath can be null in idle state */
12651 /* check file path */
12652 if ((path = strstr(filepath, "file://")))
12653 result = util_exist_file_path(path + 7);
12655 result = util_exist_file_path(filepath);
12657 if (result != MM_ERROR_NONE) {
12658 LOGE("invalid subtitle path 0x%X", result);
12659 return result; /* file not found or permission denied */
12663 if (!player->pipeline) {
12665 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12666 if (mmf_attrs_commit(player->attrs)) {
12667 LOGE("failed to commit"); /* subtitle path will not be created */
12668 return MM_ERROR_PLAYER_INTERNAL;
12671 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12672 /* check filepath */
12673 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12675 if (!__mmplayer_check_subtitle(player)) {
12676 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12677 if (mmf_attrs_commit(player->attrs)) {
12678 LOGE("failed to commit");
12679 return MM_ERROR_PLAYER_INTERNAL;
12682 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12683 LOGE("fail to create text pipeline");
12684 return MM_ERROR_PLAYER_INTERNAL;
12687 result = _mmplayer_sync_subtitle_pipeline(player);
12689 result = __mmplayer_change_external_subtitle_language(player, filepath);
12692 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12693 player->is_external_subtitle_added_now = TRUE;
12695 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12696 if (!player->subtitle_language_list) {
12697 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12698 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12699 LOGW("subtitle language list is not updated yet");
12701 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12709 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12711 int result = MM_ERROR_NONE;
12712 gchar* change_pad_name = NULL;
12713 GstPad* sinkpad = NULL;
12714 MMPlayerGstElement* mainbin = NULL;
12715 enum MainElementID elemId = MMPLAYER_M_NUM;
12716 GstCaps* caps = NULL;
12717 gint total_track_num = 0;
12721 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12722 MM_ERROR_PLAYER_NOT_INITIALIZED);
12724 LOGD("Change Track(%d) to %d\n", type, index);
12726 mainbin = player->pipeline->mainbin;
12728 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12729 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12730 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12731 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12733 /* Changing Video Track is not supported. */
12734 LOGE("Track Type Error\n");
12738 if (mainbin[elemId].gst == NULL) {
12739 result = MM_ERROR_PLAYER_NO_OP;
12740 LOGD("Req track doesn't exist\n");
12744 total_track_num = player->selector[type].total_track_num;
12745 if (total_track_num <= 0) {
12746 result = MM_ERROR_PLAYER_NO_OP;
12747 LOGD("Language list is not available \n");
12751 if ((index < 0) || (index >= total_track_num)) {
12752 result = MM_ERROR_INVALID_ARGUMENT;
12753 LOGD("Not a proper index : %d \n", index);
12757 /*To get the new pad from the selector*/
12758 change_pad_name = g_strdup_printf("sink_%u", index);
12759 if (change_pad_name == NULL) {
12760 result = MM_ERROR_PLAYER_INTERNAL;
12761 LOGD("Pad does not exists\n");
12765 LOGD("new active pad name: %s\n", change_pad_name);
12767 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12768 if (sinkpad == NULL) {
12769 LOGD("sinkpad is NULL");
12770 result = MM_ERROR_PLAYER_INTERNAL;
12774 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12775 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12777 caps = gst_pad_get_current_caps(sinkpad);
12778 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12781 gst_object_unref(sinkpad);
12783 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12784 __mmplayer_set_audio_attrs(player, caps);
12788 MMPLAYER_FREEIF(change_pad_name);
12792 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12794 int result = MM_ERROR_NONE;
12795 mm_player_t* player = NULL;
12796 MMPlayerGstElement* mainbin = NULL;
12798 gint current_active_index = 0;
12800 GstState current_state = GST_STATE_VOID_PENDING;
12801 GstEvent* event = NULL;
12806 player = (mm_player_t*)hplayer;
12807 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12809 if (!player->pipeline) {
12810 LOGE("Track %d pre setting -> %d\n", type, index);
12812 player->selector[type].active_pad_index = index;
12816 mainbin = player->pipeline->mainbin;
12818 current_active_index = player->selector[type].active_pad_index;
12820 /*If index is same as running index no need to change the pad*/
12821 if (current_active_index == index)
12824 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12825 result = MM_ERROR_PLAYER_INVALID_STATE;
12829 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12830 if (current_state < GST_STATE_PAUSED) {
12831 result = MM_ERROR_PLAYER_INVALID_STATE;
12832 LOGW("Pipeline not in porper state\n");
12836 result = __mmplayer_change_selector_pad(player, type, index);
12837 if (result != MM_ERROR_NONE) {
12838 LOGE("change selector pad error\n");
12842 player->selector[type].active_pad_index = index;
12844 if (current_state == GST_STATE_PLAYING) {
12845 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);
12847 __gst_send_event_to_sink(player, event);
12849 result = MM_ERROR_PLAYER_INTERNAL;
12858 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12860 mm_player_t* player = (mm_player_t*) hplayer;
12864 /* check player handle */
12865 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12867 *silent = player->set_mode.subtitle_off;
12869 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12873 return MM_ERROR_NONE;
12877 __is_ms_buff_src(mm_player_t* player)
12879 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12881 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12885 __has_suffix(mm_player_t* player, const gchar* suffix)
12887 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12888 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12890 gboolean ret = FALSE;
12891 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12892 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12894 if (g_str_has_suffix(player->profile.uri, suffix))
12897 MMPLAYER_FREEIF(t_url);
12898 MMPLAYER_FREEIF(t_suffix);
12904 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12906 mm_player_t* player = (mm_player_t*) hplayer;
12908 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12910 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12911 MMPLAYER_PRINT_STATE(player);
12912 LOGE("wrong-state : can't set the download mode to parse");
12913 return MM_ERROR_PLAYER_INVALID_STATE;
12916 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12917 player->video_hub_download_mode = mode;
12919 return MM_ERROR_NONE;
12923 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12925 mm_player_t* player = (mm_player_t*) hplayer;
12927 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12929 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12930 player->sync_handler = enable;
12932 return MM_ERROR_NONE;
12936 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12937 gint64 video_time, gint64 media_clock, gint64 audio_time)
12939 mm_player_t* player = (mm_player_t*) hplayer;
12940 MMPlayerGstElement* mainbin = NULL;
12941 GstClockTime start_time_audio = 0, start_time_video = 0;
12942 GstClockTimeDiff base_time = 0, new_base_time = 0;
12943 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12944 gint64 api_delta = 0;
12945 gint64 position = 0, position_delta = 0;
12946 gint64 adj_base_time = 0;
12947 GstClock *curr_clock = NULL;
12948 GstClockTime curr_time = 0;
12949 gboolean query_ret = TRUE;
12950 int result = MM_ERROR_NONE;
12954 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12955 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12956 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12958 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12959 clock, clock_delta, video_time, media_clock, audio_time); */
12961 if ((video_time < 0) || (player->doing_seek)) {
12962 LOGD("skip setting master clock. %lld", video_time);
12966 mainbin = player->pipeline->mainbin;
12968 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12969 curr_time = gst_clock_get_time(curr_clock);
12971 current_state = MMPLAYER_CURRENT_STATE(player);
12973 if (current_state == MM_PLAYER_STATE_PLAYING)
12974 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12976 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12978 position = player->last_position;
12979 LOGD("query fail. %"G_GINT64_FORMAT, position);
12982 clock *= GST_USECOND;
12983 clock_delta *= GST_USECOND;
12985 api_delta = clock - curr_time;
12986 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12987 player->video_share_api_delta = api_delta;
12989 clock_delta += (api_delta - player->video_share_api_delta);
12991 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12992 player->video_share_clock_delta = (gint64)clock_delta;
12994 position_delta = (position/GST_USECOND) - video_time;
12995 position_delta *= GST_USECOND;
12997 adj_base_time = position_delta;
12998 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13001 gint64 new_play_time = 0;
13002 gint64 network_delay = 0;
13004 video_time *= GST_USECOND;
13006 network_delay = clock_delta - player->video_share_clock_delta;
13007 new_play_time = video_time + network_delay;
13009 adj_base_time = position - new_play_time;
13011 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13012 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13013 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13016 /* Adjust Current Stream Time with base_time of sink
13017 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13018 * 2. Set new base time
13019 * if adj_base_time is positive value, the stream time will be decreased.
13020 * 3. If seek event is occurred, the start time will be reset. */
13021 if ((player->pipeline->audiobin) &&
13022 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13023 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13025 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13026 LOGD("audio sink : gst_element_set_start_time -> NONE");
13027 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13030 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13033 if ((player->pipeline->videobin) &&
13034 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13035 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13037 if (start_time_video != GST_CLOCK_TIME_NONE) {
13038 LOGD("video sink : gst_element_set_start_time -> NONE");
13039 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13042 // if videobin exist, get base_time from videobin.
13043 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13046 new_base_time = base_time + adj_base_time;
13048 if ((player->pipeline->audiobin) &&
13049 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13050 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13052 if ((player->pipeline->videobin) &&
13053 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13054 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13063 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13065 mm_player_t* player = (mm_player_t*) hplayer;
13066 MMPlayerGstElement* mainbin = NULL;
13067 GstClock *curr_clock = NULL;
13068 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13069 gint64 position = 0;
13070 gboolean query_ret = TRUE;
13074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13075 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13076 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13078 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13079 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13080 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13082 mainbin = player->pipeline->mainbin;
13084 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13086 current_state = MMPLAYER_CURRENT_STATE(player);
13088 if (current_state != MM_PLAYER_STATE_PAUSED)
13089 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13091 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13093 position = player->last_position;
13095 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13097 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13100 gst_object_unref(curr_clock);
13104 return MM_ERROR_NONE;
13108 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13110 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13111 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13113 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13114 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13118 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13119 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13120 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13121 mm_player_dump_t *dump_s;
13122 dump_s = g_malloc(sizeof(mm_player_dump_t));
13124 if (dump_s == NULL) {
13125 LOGE("malloc fail");
13129 dump_s->dump_element_file = NULL;
13130 dump_s->dump_pad = NULL;
13131 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13133 if (dump_s->dump_pad) {
13134 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13135 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]);
13136 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13137 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);
13138 /* add list for removed buffer probe and close FILE */
13139 player->dump_list = g_list_append(player->dump_list, dump_s);
13140 LOGD("%s sink pad added buffer probe for dump", factory_name);
13145 LOGE("failed to get %s sink pad added", factory_name);
13154 static GstPadProbeReturn
13155 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13157 FILE *dump_data = (FILE *) u_data;
13158 // int written = 0;
13159 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13160 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13162 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13164 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13166 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13168 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13170 return GST_PAD_PROBE_OK;
13174 __mmplayer_release_dump_list(GList *dump_list)
13177 GList *d_list = dump_list;
13178 for (; d_list; d_list = g_list_next(d_list)) {
13179 mm_player_dump_t *dump_s = d_list->data;
13180 if (dump_s->dump_pad) {
13181 if (dump_s->probe_handle_id)
13182 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13184 if (dump_s->dump_element_file) {
13185 fclose(dump_s->dump_element_file);
13186 dump_s->dump_element_file = NULL;
13188 MMPLAYER_FREEIF(dump_s);
13190 g_list_free(dump_list);
13196 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13198 mm_player_t* player = (mm_player_t*) hplayer;
13202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13203 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13205 *exist = player->has_closed_caption;
13209 return MM_ERROR_NONE;
13212 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13216 // LOGD("unref internal gst buffer %p", buffer);
13217 gst_buffer_unref((GstBuffer *)buffer);
13224 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13226 mm_player_t *player = (mm_player_t*)user_data;
13227 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13228 guint64 current_level_bytes = 0;
13230 MMPLAYER_RETURN_IF_FAIL(player);
13232 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13234 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13235 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13237 if (player->media_stream_buffer_status_cb[type])
13238 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13239 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13244 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13246 mm_player_t *player = (mm_player_t*)user_data;
13247 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13248 guint64 current_level_bytes = 0;
13250 MMPLAYER_RETURN_IF_FAIL(player);
13252 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13254 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13256 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13257 if (player->media_stream_buffer_status_cb[type])
13258 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13259 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13263 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13265 mm_player_t *player = (mm_player_t*)user_data;
13266 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13267 guint64 current_level_bytes = 0;
13269 MMPLAYER_RETURN_IF_FAIL(player);
13271 LOGI("app-src: feed subtitle\n");
13273 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13275 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13276 if (player->media_stream_buffer_status_cb[type])
13277 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13279 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13283 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13285 mm_player_t *player = (mm_player_t*)user_data;
13286 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13287 guint64 current_level_bytes = 0;
13289 MMPLAYER_RETURN_IF_FAIL(player);
13291 LOGI("app-src: audio buffer is full.\n");
13293 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13295 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13297 if (player->media_stream_buffer_status_cb[type])
13298 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13300 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13304 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13306 mm_player_t *player = (mm_player_t*)user_data;
13307 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13308 guint64 current_level_bytes = 0;
13310 MMPLAYER_RETURN_IF_FAIL(player);
13312 LOGI("app-src: video buffer is full.\n");
13314 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13316 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13317 if (player->media_stream_buffer_status_cb[type])
13318 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13320 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13324 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13326 mm_player_t *player = (mm_player_t*)user_data;
13327 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13329 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13331 LOGD("app-src: seek audio data %llu\n", position);
13332 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13334 if (player->media_stream_seek_data_cb[type])
13335 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13336 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13342 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13344 mm_player_t *player = (mm_player_t*)user_data;
13345 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13347 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13349 LOGD("app-src: seek video data %llu\n", position);
13350 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13351 if (player->media_stream_seek_data_cb[type])
13352 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13353 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13359 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13361 mm_player_t *player = (mm_player_t*)user_data;
13362 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13364 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13366 LOGD("app-src: seek subtitle data\n");
13367 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13369 if (player->media_stream_seek_data_cb[type])
13370 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13371 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13377 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13379 mm_player_t* player = (mm_player_t*) hplayer;
13383 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13385 player->pcm_samplerate = samplerate;
13386 player->pcm_channel = channel;
13389 return MM_ERROR_NONE;
13392 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13394 mm_player_t* player = (mm_player_t*) hplayer;
13398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13399 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13401 if (MMPLAYER_IS_STREAMING(player))
13402 *timeout = player->ini.live_state_change_timeout;
13404 *timeout = player->ini.localplayback_state_change_timeout;
13406 LOGD("timeout = %d\n", *timeout);
13409 return MM_ERROR_NONE;
13412 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13414 mm_player_t* player = (mm_player_t*) hplayer;
13418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13419 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13421 *num = player->video_num_buffers;
13422 *extra_num = player->video_extra_num_buffers;
13424 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13427 return MM_ERROR_NONE;
13431 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13435 MMPLAYER_RETURN_IF_FAIL(player);
13437 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13439 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13440 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13441 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13442 player->storage_info[i].id = -1;
13443 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13445 if (path_type != MMPLAYER_PATH_MAX)
13453 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13455 int ret = MM_ERROR_NONE;
13456 mm_player_t* player = (mm_player_t*)hplayer;
13457 MMMessageParamType msg_param = {0, };
13460 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13462 LOGW("state changed storage %d:%d", id, state);
13464 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13465 return MM_ERROR_NONE;
13467 /* FIXME: text path should be handled seperately. */
13468 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13469 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13470 LOGW("external storage is removed");
13472 if (player->msg_posted == FALSE) {
13473 memset(&msg_param, 0, sizeof(MMMessageParamType));
13474 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13475 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13476 player->msg_posted = TRUE;
13479 /* unrealize the player */
13480 ret = _mmplayer_unrealize(hplayer);
13481 if (ret != MM_ERROR_NONE)
13482 LOGE("failed to unrealize");
13489 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13491 int ret = MM_ERROR_NONE;
13492 mm_player_t* player = (mm_player_t*) hplayer;
13493 int idx = 0, total = 0;
13494 gchar *result = NULL, *tmp = NULL;
13497 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13498 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13500 total = *num = g_list_length(player->adaptive_info.var_list);
13502 LOGW("There is no stream variant info.");
13506 result = g_strdup("");
13507 for (idx = 0 ; idx < total ; idx++) {
13508 VariantData *v_data = NULL;
13509 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13512 gchar data[64] = {0};
13513 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13515 tmp = g_strconcat(result, data, NULL);
13519 LOGW("There is no variant data in %d", idx);
13524 *var_info = (char *)result;
13526 LOGD("variant info %d:%s", *num, *var_info);
13531 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13533 int ret = MM_ERROR_NONE;
13534 mm_player_t* player = (mm_player_t*) hplayer;
13537 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13539 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13541 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13542 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13543 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13545 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13546 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13547 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13548 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13550 /* FIXME: seek to current position for applying new variant limitation */
13558 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13560 int ret = MM_ERROR_NONE;
13561 mm_player_t* player = (mm_player_t*) hplayer;
13564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13565 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13567 *bandwidth = player->adaptive_info.limit.bandwidth;
13568 *width = player->adaptive_info.limit.width;
13569 *height = player->adaptive_info.limit.height;
13571 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13577 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13579 int ret = MM_ERROR_NONE;
13580 mm_player_t* player = (mm_player_t*) hplayer;
13583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13585 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13586 LOGW("buffer_ms will not be applied.");
13589 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13591 if (player->streamer == NULL) {
13592 player->streamer = __mm_player_streaming_create();
13593 __mm_player_streaming_initialize(player->streamer);
13596 if (buffer_ms >= 0)
13597 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13599 if (rebuffer_ms >= 0)
13600 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13607 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13609 int ret = MM_ERROR_NONE;
13610 mm_player_t* player = (mm_player_t*) hplayer;
13613 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13614 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13616 if (player->streamer == NULL) {
13617 player->streamer = __mm_player_streaming_create();
13618 __mm_player_streaming_initialize(player->streamer);
13621 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13622 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13624 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13630 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13632 #define IDX_FIRST_SW_CODEC 0
13633 mm_player_t* player = (mm_player_t*) hplayer;
13634 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13635 MMHandleType attrs = 0;
13638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13640 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13641 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13642 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13644 switch (stream_type) {
13645 case MM_PLAYER_STREAM_TYPE_AUDIO:
13646 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13647 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13648 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13649 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13650 LOGE("There is no a codec for codec_type %d", codec_type);
13651 return MM_ERROR_PLAYER_NO_OP;
13654 case MM_PLAYER_STREAM_TYPE_VIDEO:
13655 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13656 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13657 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13658 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13659 LOGE("There is no v codec for codec_type %d", codec_type);
13660 return MM_ERROR_PLAYER_NO_OP;
13665 LOGE("Invalid stream type %d", stream_type);
13666 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13670 LOGD("update %s codec_type to %d", attr_name, codec_type);
13672 attrs = MMPLAYER_GET_ATTRS(player);
13673 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13675 if (mmf_attrs_commit(player->attrs)) {
13676 LOGE("failed to commit codec_type attributes");
13677 return MM_ERROR_PLAYER_INTERNAL;
13681 return MM_ERROR_NONE;
13685 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13687 mm_player_t* player = (mm_player_t*) hplayer;
13688 GstElement* rg_vol_element = NULL;
13692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13694 player->sound.rg_enable = enabled;
13696 /* just hold rgvolume enable value if pipeline is not ready */
13697 if (!player->pipeline || !player->pipeline->audiobin) {
13698 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13699 return MM_ERROR_NONE;
13702 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13704 if (!rg_vol_element) {
13705 LOGD("rgvolume element is not created");
13706 return MM_ERROR_PLAYER_INTERNAL;
13710 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13712 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13716 return MM_ERROR_NONE;
13720 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13722 mm_player_t* player = (mm_player_t*) hplayer;
13723 GstElement* rg_vol_element = NULL;
13724 gboolean enable = FALSE;
13728 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13729 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13731 /* just hold enable_rg value if pipeline is not ready */
13732 if (!player->pipeline || !player->pipeline->audiobin) {
13733 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13734 *enabled = player->sound.rg_enable;
13735 return MM_ERROR_NONE;
13738 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13740 if (!rg_vol_element) {
13741 LOGD("rgvolume element is not created");
13742 return MM_ERROR_PLAYER_INTERNAL;
13745 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13750 return MM_ERROR_NONE;