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, buffering_msg, data_size, player->last_position, player->duration);
768 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
774 __mmplayer_handle_buffering_message(mm_player_t* player)
776 int ret = MM_ERROR_NONE;
777 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
778 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
779 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
780 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
782 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
783 LOGW("do nothing for buffering msg\n");
784 ret = MM_ERROR_PLAYER_INVALID_STATE;
788 prev_state = MMPLAYER_PREV_STATE(player);
789 current_state = MMPLAYER_CURRENT_STATE(player);
790 target_state = MMPLAYER_TARGET_STATE(player);
791 pending_state = MMPLAYER_PENDING_STATE(player);
793 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering state 0x%X",
794 MMPLAYER_STATE_GET_NAME(prev_state),
795 MMPLAYER_STATE_GET_NAME(current_state),
796 MMPLAYER_STATE_GET_NAME(pending_state),
797 MMPLAYER_STATE_GET_NAME(target_state),
798 player->streamer->buffering_state);
800 if (!(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
801 /* NOTE : if buffering has done, player has to go to target state. */
802 switch (target_state) {
803 case MM_PLAYER_STATE_PAUSED:
805 switch (pending_state) {
806 case MM_PLAYER_STATE_PLAYING:
807 __gst_pause(player, TRUE);
810 case MM_PLAYER_STATE_PAUSED:
811 LOGD("player is already going to paused state, there is nothing to do.\n");
814 case MM_PLAYER_STATE_NONE:
815 case MM_PLAYER_STATE_NULL:
816 case MM_PLAYER_STATE_READY:
818 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
824 case MM_PLAYER_STATE_PLAYING:
826 switch (pending_state) {
827 case MM_PLAYER_STATE_NONE:
829 if (current_state != MM_PLAYER_STATE_PLAYING)
830 __gst_resume(player, TRUE);
834 case MM_PLAYER_STATE_PAUSED:
835 /* NOTE: It should be worked as asynchronously.
836 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
838 if (current_state == MM_PLAYER_STATE_PLAYING) {
839 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
840 * The current state should be changed to paused purposely to prevent state conflict.
842 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
844 __gst_resume(player, TRUE);
847 case MM_PLAYER_STATE_PLAYING:
848 LOGD("player is already going to playing state, there is nothing to do.\n");
851 case MM_PLAYER_STATE_NULL:
852 case MM_PLAYER_STATE_READY:
854 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
860 case MM_PLAYER_STATE_NULL:
861 case MM_PLAYER_STATE_READY:
862 case MM_PLAYER_STATE_NONE:
864 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
868 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
869 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
871 switch (pending_state) {
872 case MM_PLAYER_STATE_NONE:
874 if (current_state != MM_PLAYER_STATE_PAUSED) {
875 /* rtsp streaming pause makes rtsp server stop sending data. */
876 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
877 LOGD("set pause state during buffering\n");
878 __gst_pause(player, TRUE);
884 case MM_PLAYER_STATE_PLAYING:
885 /* rtsp streaming pause makes rtsp server stop sending data. */
886 if (!MMPLAYER_IS_RTSP_STREAMING(player))
887 __gst_pause(player, TRUE);
890 case MM_PLAYER_STATE_PAUSED:
893 case MM_PLAYER_STATE_NULL:
894 case MM_PLAYER_STATE_READY:
896 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
906 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
908 MMPlayerGstElement *textbin;
911 MMPLAYER_RETURN_IF_FAIL(player &&
913 player->pipeline->textbin);
915 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
917 textbin = player->pipeline->textbin;
920 LOGD("Drop subtitle text after getting EOS\n");
922 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
923 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
925 player->is_subtitle_force_drop = TRUE;
927 if (player->is_subtitle_force_drop == TRUE) {
928 LOGD("Enable subtitle data path without drop\n");
930 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
931 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
933 LOGD("non-connected with external display");
935 player->is_subtitle_force_drop = FALSE;
941 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
943 VariantData *var_info = NULL;
944 g_return_val_if_fail(self != NULL, NULL);
946 var_info = g_new0(VariantData, 1);
947 if (!var_info) return NULL;
948 var_info->bandwidth = self->bandwidth;
949 var_info->width = self->width;
950 var_info->height = self->height;
954 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
956 mm_player_t* player = (mm_player_t*)hplayer;
957 GstMessage *msg = NULL;
958 GQueue *queue = NULL;
961 MMPLAYER_RETURN_IF_FAIL(player);
963 /* disconnecting bus watch */
964 if (player->bus_watcher)
965 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
966 player->bus_watcher = 0;
968 /* destroy the gst bus msg thread */
969 if (player->bus_msg_thread) {
970 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
971 player->bus_msg_thread_exit = TRUE;
972 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
973 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
975 LOGD("gst bus msg thread exit.");
976 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
977 player->bus_msg_thread = NULL;
979 g_mutex_clear(&player->bus_msg_thread_mutex);
980 g_cond_clear(&player->bus_msg_thread_cond);
983 g_mutex_lock(&player->bus_msg_q_lock);
984 queue = player->bus_msg_q;
985 while (!g_queue_is_empty(queue)) {
986 msg = (GstMessage *)g_queue_pop_head(queue);
987 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
988 gst_message_unref(msg);
990 g_mutex_unlock(&player->bus_msg_q_lock);
995 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
997 mm_player_t *player = (mm_player_t *) data;
999 g_return_val_if_fail(player, FALSE);
1000 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1002 gst_message_ref(msg);
1004 g_mutex_lock(&player->bus_msg_q_lock);
1005 g_queue_push_tail(player->bus_msg_q, msg);
1006 g_mutex_unlock(&player->bus_msg_q_lock);
1008 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1009 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1010 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1014 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1016 mm_player_t *player = (mm_player_t*)(data);
1017 GstMessage *msg = NULL;
1021 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1023 player->pipeline->mainbin &&
1024 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1027 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1029 LOGE("cannot get BUS from the pipeline");
1033 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1035 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1036 while (!player->bus_msg_thread_exit) {
1037 g_mutex_lock(&player->bus_msg_q_lock);
1038 msg = g_queue_pop_head(player->bus_msg_q);
1039 g_mutex_unlock(&player->bus_msg_q_lock);
1041 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1044 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1045 /* handle the gst msg */
1046 __mmplayer_gst_callback(msg, player);
1047 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1048 gst_message_unref(msg);
1051 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1052 gst_object_unref(GST_OBJECT(bus));
1059 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1061 mm_player_t* player = (mm_player_t*)(data);
1063 MMPLAYER_RETURN_IF_FAIL(player);
1064 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1066 switch (GST_MESSAGE_TYPE(msg)) {
1067 case GST_MESSAGE_UNKNOWN:
1068 LOGD("unknown message received\n");
1071 case GST_MESSAGE_EOS:
1073 MMHandleType attrs = 0;
1076 LOGD("GST_MESSAGE_EOS received\n");
1078 /* NOTE : EOS event is comming multiple time. watch out it */
1079 /* check state. we only process EOS when pipeline state goes to PLAYING */
1080 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1081 LOGD("EOS received on non-playing state. ignoring it\n");
1085 if (player->pipeline) {
1086 if (player->pipeline->textbin)
1087 __mmplayer_drop_subtitle(player, TRUE);
1089 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1092 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1094 LOGD("release audio callback\n");
1096 /* release audio callback */
1097 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1098 player->audio_cb_probe_id = 0;
1099 /* audio callback should be free because it can be called even though probe remove.*/
1100 player->audio_stream_cb = NULL;
1101 player->audio_stream_cb_user_param = NULL;
1105 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1106 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1108 /* rewind if repeat count is greater then zero */
1109 /* get play count */
1110 attrs = MMPLAYER_GET_ATTRS(player);
1113 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1115 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1117 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1118 if (player->playback_rate < 0.0) {
1119 player->resumed_by_rewind = TRUE;
1120 _mmplayer_set_mute((MMHandleType)player, 0);
1121 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1124 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1127 player->sent_bos = FALSE;
1129 /* not posting eos when repeating */
1134 if (player->pipeline)
1135 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1137 /* post eos message to application */
1138 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1140 /* reset last position */
1141 player->last_position = 0;
1145 case GST_MESSAGE_ERROR:
1147 GError *error = NULL;
1148 gchar* debug = NULL;
1150 /* generating debug info before returning error */
1151 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1153 /* get error code */
1154 gst_message_parse_error(msg, &error, &debug);
1156 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1157 /* Note : the streaming error from the streaming source is handled
1158 * using __mmplayer_handle_streaming_error.
1160 __mmplayer_handle_streaming_error(player, msg);
1162 /* dump state of all element */
1163 __mmplayer_dump_pipeline_state(player);
1165 /* traslate gst error code to msl error code. then post it
1166 * to application if needed
1168 __mmplayer_handle_gst_error(player, msg, error);
1171 LOGE("error debug : %s", debug);
1174 if (MMPLAYER_IS_HTTP_PD(player))
1175 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1177 MMPLAYER_FREEIF(debug);
1178 g_error_free(error);
1182 case GST_MESSAGE_WARNING:
1185 GError* error = NULL;
1187 gst_message_parse_warning(msg, &error, &debug);
1189 LOGD("warning : %s\n", error->message);
1190 LOGD("debug : %s\n", debug);
1192 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1194 MMPLAYER_FREEIF(debug);
1195 g_error_free(error);
1199 case GST_MESSAGE_TAG:
1201 LOGD("GST_MESSAGE_TAG\n");
1202 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1203 LOGW("failed to extract tags from gstmessage\n");
1207 case GST_MESSAGE_BUFFERING:
1209 MMMessageParamType msg_param = {0, };
1210 int bRet = MM_ERROR_NONE;
1212 if (!(player->pipeline && player->pipeline->mainbin)) {
1213 LOGE("Pipeline is not initialized");
1217 if (!MMPLAYER_IS_STREAMING(player))
1220 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1221 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1222 /* skip the playback control by buffering msg while user request is handled. */
1225 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1227 gst_message_parse_buffering(msg, &per);
1228 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1230 msg_param.connection.buffering = per;
1231 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1235 MMPLAYER_CMD_LOCK(player);
1238 if (!player->streamer) {
1239 LOGW("Pipeline is shutting down");
1240 MMPLAYER_CMD_UNLOCK(player);
1244 /* ignore the remained buffering message till getting 100% msg */
1245 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1246 gint buffer_percent = 0;
1248 gst_message_parse_buffering(msg, &buffer_percent);
1250 if (buffer_percent == MAX_BUFFER_PERCENT) {
1251 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1252 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1254 MMPLAYER_CMD_UNLOCK(player);
1258 /* ignore the remained buffering message */
1259 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1260 gint buffer_percent = 0;
1262 gst_message_parse_buffering(msg, &buffer_percent);
1264 LOGD("interrupted buffering -last posted %d %%, new per %d %%",
1265 player->streamer->buffering_percent, buffer_percent);
1267 if (player->streamer->buffering_percent > buffer_percent || buffer_percent <= 0) {
1268 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1269 player->streamer->buffering_req.is_pre_buffering = FALSE;
1271 LOGD("interrupted buffering - need to enter the buffering mode again - %d %%", buffer_percent);
1273 LOGD("interrupted buffering - ignored the remained buffering msg!");
1274 MMPLAYER_CMD_UNLOCK(player);
1279 __mmplayer_update_buffer_setting(player, msg);
1281 bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1283 if (bRet == MM_ERROR_NONE) {
1284 msg_param.connection.buffering = player->streamer->buffering_percent;
1285 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1287 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1288 player->pending_resume &&
1289 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1291 player->is_external_subtitle_added_now = FALSE;
1292 player->pending_resume = FALSE;
1293 _mmplayer_resume((MMHandleType)player);
1296 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1297 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1299 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1300 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1301 player->seek_state = MMPLAYER_SEEK_NONE;
1302 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1303 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1304 /* Considering the async state trasition in case of RTSP.
1305 After getting state change gst msg, seek cmpleted msg will be posted. */
1306 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1310 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1311 if (!player->streamer) {
1312 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1313 MMPLAYER_CMD_UNLOCK(player);
1317 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1319 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1320 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1322 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1323 msg_param.connection.buffering = player->streamer->buffering_percent;
1324 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1326 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1329 msg_param.connection.buffering = player->streamer->buffering_percent;
1330 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1333 MMPLAYER_CMD_UNLOCK(player);
1337 case GST_MESSAGE_STATE_CHANGED:
1339 MMPlayerGstElement *mainbin;
1340 const GValue *voldstate, *vnewstate, *vpending;
1341 GstState oldstate = GST_STATE_NULL;
1342 GstState newstate = GST_STATE_NULL;
1343 GstState pending = GST_STATE_NULL;
1345 if (!(player->pipeline && player->pipeline->mainbin)) {
1346 LOGE("player pipeline handle is null");
1350 mainbin = player->pipeline->mainbin;
1352 /* we only handle messages from pipeline */
1353 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1356 /* get state info from msg */
1357 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1358 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1359 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1361 if (!voldstate || !vnewstate) {
1362 LOGE("received msg has wrong format.");
1366 oldstate = (GstState)voldstate->data[0].v_int;
1367 newstate = (GstState)vnewstate->data[0].v_int;
1369 pending = (GstState)vpending->data[0].v_int;
1371 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1372 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1373 gst_element_state_get_name((GstState)oldstate),
1374 gst_element_state_get_name((GstState)newstate),
1375 gst_element_state_get_name((GstState)pending));
1377 if (newstate == GST_STATE_PLAYING) {
1378 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1380 int retVal = MM_ERROR_NONE;
1381 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1383 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1385 if (MM_ERROR_NONE != retVal)
1386 LOGE("failed to seek pending postion. just keep staying current position.\n");
1388 player->pending_seek.is_pending = FALSE;
1392 if (oldstate == newstate) {
1393 LOGD("pipeline reports state transition to old state");
1398 case GST_STATE_VOID_PENDING:
1401 case GST_STATE_NULL:
1404 case GST_STATE_READY:
1407 case GST_STATE_PAUSED:
1409 gboolean prepare_async = FALSE;
1411 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1412 __mmplayer_configure_audio_callback(player);
1414 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1415 // managed prepare async case
1416 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1417 LOGD("checking prepare mode for async transition - %d", prepare_async);
1420 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1421 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1423 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1424 __mm_player_streaming_set_content_bitrate(player->streamer,
1425 player->total_maximum_bitrate, player->total_bitrate);
1427 if (player->pending_seek.is_pending) {
1428 LOGW("trying to do pending seek");
1429 MMPLAYER_CMD_LOCK(player);
1430 __gst_pending_seek(player);
1431 MMPLAYER_CMD_UNLOCK(player);
1437 case GST_STATE_PLAYING:
1439 if (MMPLAYER_IS_STREAMING(player)) {
1440 // managed prepare async case when buffering is completed
1441 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1442 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1443 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1444 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1446 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1448 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1449 if (player->streamer->buffering_percent < 100) {
1451 MMMessageParamType msg_param = {0, };
1452 LOGW("Posting Buffering Completed Message to Application !!!");
1454 msg_param.connection.buffering = 100;
1455 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1460 if (player->gapless.stream_changed) {
1461 _mmplayer_update_content_attrs(player, ATTR_ALL);
1462 player->gapless.stream_changed = FALSE;
1465 if (player->seek_state == MMPLAYER_SEEK_COMPLETED) {
1466 player->seek_state = MMPLAYER_SEEK_NONE;
1467 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1478 case GST_MESSAGE_CLOCK_LOST:
1480 GstClock *clock = NULL;
1481 gboolean need_new_clock = FALSE;
1483 gst_message_parse_clock_lost(msg, &clock);
1484 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1486 if (!player->videodec_linked)
1487 need_new_clock = TRUE;
1488 else if (!player->ini.use_system_clock)
1489 need_new_clock = TRUE;
1491 if (need_new_clock) {
1492 LOGD("Provide clock is TRUE, do pause->resume\n");
1493 __gst_pause(player, FALSE);
1494 __gst_resume(player, FALSE);
1499 case GST_MESSAGE_NEW_CLOCK:
1501 GstClock *clock = NULL;
1502 gst_message_parse_new_clock(msg, &clock);
1503 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1507 case GST_MESSAGE_ELEMENT:
1509 const gchar *structure_name;
1510 gint count = 0, idx = 0;
1511 MMHandleType attrs = 0;
1513 attrs = MMPLAYER_GET_ATTRS(player);
1515 LOGE("cannot get content attribute");
1519 if (gst_message_get_structure(msg) == NULL)
1522 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1523 if (!structure_name)
1526 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1528 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1529 const GValue *var_info = NULL;
1531 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1532 if (var_info != NULL) {
1533 if (player->adaptive_info.var_list)
1534 g_list_free_full(player->adaptive_info.var_list, g_free);
1536 /* share addr or copy the list */
1537 player->adaptive_info.var_list =
1538 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1540 count = g_list_length(player->adaptive_info.var_list);
1542 VariantData *temp = NULL;
1544 /* print out for debug */
1545 LOGD("num of variant_info %d", count);
1546 for (idx = 0; idx < count; idx++) {
1547 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1549 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1555 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1556 gint num_buffers = 0;
1557 gint extra_num_buffers = 0;
1559 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1560 player->video_num_buffers = num_buffers;
1561 LOGD("video_num_buffers : %d", player->video_num_buffers);
1564 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1565 player->video_extra_num_buffers = extra_num_buffers;
1566 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1571 if (!strcmp(structure_name, "Language_list")) {
1572 const GValue *lang_list = NULL;
1573 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1574 if (lang_list != NULL) {
1575 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1577 LOGD("Total audio tracks(from parser) = %d \n", count);
1581 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1582 const GValue *lang_list = NULL;
1583 MMPlayerLangStruct *temp = NULL;
1585 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1586 if (lang_list != NULL) {
1587 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1589 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1590 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1591 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1592 if (mmf_attrs_commit(attrs))
1593 LOGE("failed to commit.\n");
1594 LOGD("Total subtitle tracks = %d \n", count);
1597 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1599 LOGD("value of lang_key is %s and lang_code is %s",
1600 temp->language_key, temp->language_code);
1603 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1604 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1609 /* custom message */
1610 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1611 MMMessageParamType msg_param = {0,};
1612 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1613 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1616 /* custom message for RTSP attribute :
1617 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1618 sdp which has contents info is received when rtsp connection is opened.
1619 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1620 if (!strcmp(structure_name, "rtspsrc_properties")) {
1622 gchar *audio_codec = NULL;
1623 gchar *video_codec = NULL;
1624 gchar *video_frame_size = NULL;
1626 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1627 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1628 player->streaming_type = __mmplayer_get_stream_service_type(player);
1630 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1631 LOGD("rtsp_audio_codec : %s", audio_codec);
1633 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1635 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1636 LOGD("rtsp_video_codec : %s", video_codec);
1638 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1640 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1641 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1642 if (video_frame_size) {
1644 char *seperator = strchr(video_frame_size, '-');
1647 char video_width[10] = {0,};
1648 int frame_size_len = strlen(video_frame_size);
1649 int separtor_len = strlen(seperator);
1651 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1652 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1655 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1659 if (mmf_attrs_commit(attrs))
1660 LOGE("failed to commit.\n");
1665 case GST_MESSAGE_DURATION_CHANGED:
1667 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1668 if (!__mmplayer_gst_handle_duration(player, msg))
1669 LOGW("failed to update duration");
1674 case GST_MESSAGE_ASYNC_START:
1675 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1678 case GST_MESSAGE_ASYNC_DONE:
1680 MMPlayerGstElement *mainbin;
1682 if (!(player->pipeline && player->pipeline->mainbin)) {
1683 LOGE("player pipeline handle is null");
1687 mainbin = player->pipeline->mainbin;
1689 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1691 /* we only handle messages from pipeline */
1692 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1695 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS) {
1696 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1697 player->seek_state = MMPLAYER_SEEK_NONE;
1698 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1699 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1700 if (mainbin[MMPLAYER_M_AUTOPLUG].gst) {
1701 LOGD("sync %s state(%s) with parent state(%s)",
1702 GST_ELEMENT_NAME(mainbin[MMPLAYER_M_AUTOPLUG].gst),
1703 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_AUTOPLUG].gst)),
1704 gst_element_state_get_name(GST_STATE(mainbin[MMPLAYER_M_PIPE].gst)));
1706 /* In case of streaming, pause is required before finishing seeking by buffering.
1707 After completing the seek(during buffering), the player and sink elems has paused state but others in playing state.
1708 Because the buffering state is controlled according to the state transition for force resume,
1709 the decodebin state should be paused as player state. */
1710 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_AUTOPLUG].gst);
1713 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1714 (player->streamer) &&
1715 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1716 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1717 GstQuery *query = NULL;
1718 gboolean busy = FALSE;
1721 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1722 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1723 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1724 gst_query_parse_buffering_percent(query, &busy, &percent);
1725 gst_query_unref(query);
1727 LOGD("buffered percent(%s): %d\n",
1728 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1732 __mmplayer_handle_buffering_message(player);
1735 player->seek_state = MMPLAYER_SEEK_COMPLETED;
1741 #if 0 /* delete unnecessary logs */
1742 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1743 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1744 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1745 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1746 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1747 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1748 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1749 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1750 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1751 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1752 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1753 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1754 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1755 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1756 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1763 /* should not call 'gst_message_unref(msg)' */
1768 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1774 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1775 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1777 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1778 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1779 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1781 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1782 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1783 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1786 /* handling audio clip which has vbr. means duration is keep changing */
1787 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1795 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1796 mm_player_spherical_metadata_t *metadata) {
1797 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1798 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1799 gst_tag_list_get_string(tags, "stitching_software",
1800 &metadata->stitching_software);
1801 gst_tag_list_get_string(tags, "projection_type",
1802 &metadata->projection_type_string);
1803 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1804 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1805 gst_tag_list_get_int(tags, "init_view_heading",
1806 &metadata->init_view_heading);
1807 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1808 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1809 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1810 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1811 &metadata->full_pano_width_pixels);
1812 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1813 &metadata->full_pano_height_pixels);
1814 gst_tag_list_get_int(tags, "cropped_area_image_width",
1815 &metadata->cropped_area_image_width);
1816 gst_tag_list_get_int(tags, "cropped_area_image_height",
1817 &metadata->cropped_area_image_height);
1818 gst_tag_list_get_int(tags, "cropped_area_left",
1819 &metadata->cropped_area_left);
1820 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1821 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1822 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1823 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1827 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1830 /* macro for better code readability */
1831 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1832 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1833 if (string != NULL) { \
1834 SECURE_LOGD("update tag string : %s\n", string); \
1835 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1836 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1837 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1838 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1839 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1840 g_free(new_string); \
1841 new_string = NULL; \
1843 mm_attrs_set_string_by_name(attribute, playertag, string); \
1850 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1852 GstSample *sample = NULL;\
1853 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1854 GstMapInfo info = GST_MAP_INFO_INIT;\
1855 buffer = gst_sample_get_buffer(sample);\
1856 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1857 LOGD("failed to get image data from tag");\
1858 gst_sample_unref(sample);\
1861 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1862 MMPLAYER_FREEIF(player->album_art);\
1863 player->album_art = (gchar *)g_malloc(info.size);\
1864 if (player->album_art) {\
1865 memcpy(player->album_art, info.data, info.size);\
1866 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1867 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1868 msg_param.data = (void *)player->album_art;\
1869 msg_param.size = info.size;\
1870 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1871 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1874 gst_buffer_unmap(buffer, &info);\
1875 gst_sample_unref(sample);\
1879 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1881 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1884 gchar *tag_list_str = NULL; \
1885 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1886 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1887 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1888 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1889 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1891 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1892 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1893 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1894 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1895 player->bitrate[track_type] = v_uint; \
1896 player->total_bitrate = 0; \
1897 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1898 player->total_bitrate += player->bitrate[i]; \
1899 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1900 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1901 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1902 player->maximum_bitrate[track_type] = v_uint; \
1903 player->total_maximum_bitrate = 0; \
1904 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1905 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1906 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1907 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1909 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1912 g_free(tag_list_str); \
1917 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1918 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1919 if (date != NULL) {\
1920 string = g_strdup_printf("%d", g_date_get_year(date));\
1921 mm_attrs_set_string_by_name(attribute, playertag, string);\
1922 SECURE_LOGD("metainfo year : %s\n", string);\
1923 MMPLAYER_FREEIF(string);\
1928 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1929 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1930 if (datetime != NULL) {\
1931 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1932 mm_attrs_set_string_by_name(attribute, playertag, string);\
1933 SECURE_LOGD("metainfo year : %s\n", string);\
1934 MMPLAYER_FREEIF(string);\
1935 gst_date_time_unref(datetime);\
1939 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1940 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1942 /* FIXIT : don't know how to store date */\
1948 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1949 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1951 /* FIXIT : don't know how to store date */\
1957 /* function start */
1958 GstTagList* tag_list = NULL;
1960 MMHandleType attrs = 0;
1962 char *string = NULL;
1965 GstDateTime *datetime = NULL;
1967 GstBuffer *buffer = NULL;
1969 MMMessageParamType msg_param = {0, };
1971 /* currently not used. but those are needed for above macro */
1972 //guint64 v_uint64 = 0;
1973 //gdouble v_double = 0;
1975 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1977 attrs = MMPLAYER_GET_ATTRS(player);
1979 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1981 /* get tag list from gst message */
1982 gst_message_parse_tag(msg, &tag_list);
1984 /* store tags to player attributes */
1985 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1986 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1987 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1988 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1989 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1990 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1991 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1992 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1993 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1994 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1995 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1996 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1997 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1998 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1999 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
2000 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
2001 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
2002 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
2003 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
2004 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
2005 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
2006 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
2007 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
2008 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
2009 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
2010 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
2011 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
2012 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
2013 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
2014 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
2015 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
2016 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
2017 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
2018 MMPLAYER_UPDATE_TAG_LOCK(player);
2019 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
2020 MMPLAYER_UPDATE_TAG_UNLOCK(player);
2021 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2022 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2023 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2024 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2025 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2026 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2027 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2028 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2029 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2030 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2031 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2032 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2033 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2035 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2036 if (player->video360_metadata.is_spherical == -1) {
2037 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2038 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2039 player->video360_metadata.is_spherical);
2040 if (player->video360_metadata.is_spherical == 1) {
2041 LOGD("This is spherical content for 360 playback.");
2042 player->is_content_spherical = TRUE;
2044 LOGD("This is not spherical content");
2045 player->is_content_spherical = FALSE;
2048 if (player->video360_metadata.projection_type_string) {
2049 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2050 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2052 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2053 player->is_content_spherical = player->is_video360_enabled = FALSE;
2057 if (player->video360_metadata.stereo_mode_string) {
2058 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2059 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2060 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2061 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2062 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2063 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2065 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2066 player->is_content_spherical = player->is_video360_enabled = FALSE;
2072 if (mmf_attrs_commit(attrs))
2073 LOGE("failed to commit.\n");
2075 gst_tag_list_free(tag_list);
2081 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2083 mm_player_t* player = (mm_player_t*) data;
2087 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2088 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2089 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2090 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2092 * [1] audio and video will be dumped with filesink.
2093 * [2] autoplugging is done by just using pad caps.
2094 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2095 * and the video will be dumped via filesink.
2097 if (player->num_dynamic_pad == 0) {
2098 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2100 if (!__mmplayer_gst_remove_fakesink(player,
2101 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2102 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2103 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2104 * source element are not same. To overcome this situation, this function will called
2105 * several places and several times. Therefore, this is not an error case.
2110 /* create dot before error-return. for debugging */
2111 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2113 player->no_more_pad = TRUE;
2119 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2121 GstElement* parent = NULL;
2123 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2125 /* if we have no fakesink. this meas we are using decodebin which doesn'
2126 t need to add extra fakesink */
2127 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2130 MMPLAYER_FSINK_LOCK(player);
2135 /* get parent of fakesink */
2136 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2138 LOGD("fakesink already removed\n");
2142 gst_element_set_locked_state(fakesink->gst, TRUE);
2144 /* setting the state to NULL never returns async
2145 * so no need to wait for completion of state transiton
2147 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2148 LOGE("fakesink state change failure!\n");
2149 /* FIXIT : should I return here? or try to proceed to next? */
2152 /* remove fakesink from it's parent */
2153 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2154 LOGE("failed to remove fakesink\n");
2156 gst_object_unref(parent);
2161 gst_object_unref(parent);
2163 LOGD("state-holder removed\n");
2165 gst_element_set_locked_state(fakesink->gst, FALSE);
2167 MMPLAYER_FSINK_UNLOCK(player);
2172 gst_element_set_locked_state(fakesink->gst, FALSE);
2174 MMPLAYER_FSINK_UNLOCK(player);
2180 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2182 GstPad *sinkpad = NULL;
2183 GstCaps* caps = NULL;
2184 GstElement* new_element = NULL;
2185 GstStructure* str = NULL;
2186 const gchar* name = NULL;
2188 mm_player_t* player = (mm_player_t*) data;
2192 MMPLAYER_RETURN_IF_FAIL(element && pad);
2193 MMPLAYER_RETURN_IF_FAIL(player &&
2195 player->pipeline->mainbin);
2198 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2199 * num_dynamic_pad will decreased after creating a sinkbin.
2201 player->num_dynamic_pad++;
2202 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2204 caps = gst_pad_query_caps(pad, NULL);
2206 MMPLAYER_CHECK_NULL(caps);
2208 /* clear previous result*/
2209 player->have_dynamic_pad = FALSE;
2211 str = gst_caps_get_structure(caps, 0);
2214 LOGE("cannot get structure from caps.\n");
2218 name = gst_structure_get_name(str);
2220 LOGE("cannot get mimetype from structure.\n");
2224 if (strstr(name, "video")) {
2226 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2228 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2229 if (player->v_stream_caps) {
2230 gst_caps_unref(player->v_stream_caps);
2231 player->v_stream_caps = NULL;
2234 new_element = gst_element_factory_make("fakesink", NULL);
2235 player->num_dynamic_pad--;
2240 /* clear previous result*/
2241 player->have_dynamic_pad = FALSE;
2243 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2244 LOGE("failed to autoplug for caps");
2248 /* check if there's dynamic pad*/
2249 if (player->have_dynamic_pad) {
2250 LOGE("using pad caps assums there's no dynamic pad !\n");
2254 gst_caps_unref(caps);
2259 /* excute new_element if created*/
2261 LOGD("adding new element to pipeline\n");
2263 /* set state to READY before add to bin */
2264 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2266 /* add new element to the pipeline */
2267 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2268 LOGE("failed to add autoplug element to bin\n");
2272 /* get pad from element */
2273 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2275 LOGE("failed to get sinkpad from autoplug element\n");
2280 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2281 LOGE("failed to link autoplug element\n");
2285 gst_object_unref(sinkpad);
2288 /* run. setting PLAYING here since streamming source is live source */
2289 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2293 gst_caps_unref(caps);
2299 STATE_CHANGE_FAILED:
2301 /* FIXIT : take care if new_element has already added to pipeline */
2303 gst_object_unref(GST_OBJECT(new_element));
2306 gst_object_unref(GST_OBJECT(sinkpad));
2309 gst_caps_unref(caps);
2311 /* FIXIT : how to inform this error to MSL ????? */
2312 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2313 * then post an error to application
2317 static GstPadProbeReturn
2318 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2320 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2321 return GST_PAD_PROBE_OK;
2324 static GstPadProbeReturn
2325 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2327 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2328 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2329 mm_player_t* player = (mm_player_t*)data;
2330 GstCaps* caps = NULL;
2331 GstStructure* str = NULL;
2332 const gchar* name = NULL;
2333 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2336 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2337 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2338 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2339 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2340 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2342 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2343 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2347 caps = gst_pad_query_caps(pad, NULL);
2349 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2353 str = gst_caps_get_structure(caps, 0);
2355 LOGE("failed to get structure from caps");
2359 name = gst_structure_get_name(str);
2361 LOGE("failed to get name from str");
2365 if (strstr(name, "audio")) {
2366 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2367 } else if (strstr(name, "video")) {
2368 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2370 /* text track is not supportable */
2371 LOGE("invalid name %s", name);
2375 switch (GST_EVENT_TYPE(event)) {
2378 /* in case of gapless, drop eos event not to send it to sink */
2379 if (player->gapless.reconfigure && !player->msg_posted) {
2380 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2381 ret = GST_PAD_PROBE_DROP;
2385 case GST_EVENT_STREAM_START:
2387 gint64 stop_running_time = 0;
2388 gint64 position_running_time = 0;
2389 gint64 position = 0;
2392 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2393 if ((player->gapless.update_segment[idx] == TRUE) ||
2394 !(player->selector[idx].event_probe_id)) {
2395 /* LOGW("[%d] skip", idx); */
2399 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2401 gst_segment_to_running_time(&player->gapless.segment[idx],
2402 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2403 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2405 gst_segment_to_running_time(&player->gapless.segment[idx],
2406 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2408 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2410 gst_segment_to_running_time(&player->gapless.segment[idx],
2411 GST_FORMAT_TIME, player->duration);
2414 position_running_time =
2415 gst_segment_to_running_time(&player->gapless.segment[idx],
2416 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2418 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2419 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2421 GST_TIME_ARGS(stop_running_time),
2422 GST_TIME_ARGS(position_running_time),
2423 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2424 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2426 position_running_time = MAX(position_running_time, stop_running_time);
2427 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2428 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2429 position_running_time = MAX(0, position_running_time);
2430 position = MAX(position, position_running_time);
2433 if (position != 0) {
2434 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2435 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2436 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2438 player->gapless.start_time[stream_type] += position;
2442 case GST_EVENT_FLUSH_STOP:
2444 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2445 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2446 player->gapless.start_time[stream_type] = 0;
2449 case GST_EVENT_SEGMENT:
2454 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2455 gst_event_copy_segment(event, &segment);
2457 if (segment.format == GST_FORMAT_TIME) {
2458 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2459 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2460 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2461 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2462 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2463 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2465 /* keep the all the segment ev to cover the seeking */
2466 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2467 player->gapless.update_segment[stream_type] = TRUE;
2469 if (!player->gapless.running)
2472 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2474 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2476 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2477 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2478 gst_event_unref(event);
2479 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2485 gdouble proportion = 0.0;
2486 GstClockTimeDiff diff = 0;
2487 GstClockTime timestamp = 0;
2488 gint64 running_time_diff = -1;
2489 GstQOSType type = 0;
2490 GstEvent *tmpev = NULL;
2492 running_time_diff = player->gapless.segment[stream_type].base;
2494 if (running_time_diff <= 0) /* don't need to adjust */
2497 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2498 gst_event_unref(event);
2500 if (timestamp < running_time_diff) {
2501 LOGW("QOS event from previous group");
2502 ret = GST_PAD_PROBE_DROP;
2506 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2507 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2508 stream_type, GST_TIME_ARGS(timestamp),
2509 GST_TIME_ARGS(running_time_diff),
2510 GST_TIME_ARGS(timestamp - running_time_diff));
2512 timestamp -= running_time_diff;
2514 /* That case is invalid for QoS events */
2515 if (diff < 0 && -diff > timestamp) {
2516 LOGW("QOS event from previous group");
2517 ret = GST_PAD_PROBE_DROP;
2521 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2522 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2532 gst_caps_unref(caps);
2537 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2539 mm_player_t* player = NULL;
2540 GstElement* pipeline = NULL;
2541 GstElement* selector = NULL;
2542 GstElement* fakesink = NULL;
2543 GstCaps* caps = NULL;
2544 GstStructure* str = NULL;
2545 const gchar* name = NULL;
2546 GstPad* sinkpad = NULL;
2547 GstPad* srcpad = NULL;
2548 gboolean first_track = FALSE;
2550 enum MainElementID elemId = MMPLAYER_M_NUM;
2551 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2554 player = (mm_player_t*)data;
2556 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2557 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2559 //LOGD("pad-added signal handling\n");
2561 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2563 /* get mimetype from caps */
2564 caps = gst_pad_query_caps(pad, NULL);
2566 LOGE("cannot get caps from pad.\n");
2570 str = gst_caps_get_structure(caps, 0);
2572 LOGE("cannot get structure from caps.\n");
2576 name = gst_structure_get_name(str);
2578 LOGE("cannot get mimetype from structure.\n");
2582 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2583 //LOGD("detected mimetype : %s\n", name);
2585 if (strstr(name, "video")) {
2588 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2589 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2591 /* don't make video because of not required, and not support multiple track */
2592 if (stype == MM_DISPLAY_SURFACE_NULL) {
2593 LOGD("no video sink by null surface");
2595 gchar *caps_str = gst_caps_to_string(caps);
2596 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2597 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2598 player->set_mode.video_zc = TRUE;
2600 MMPLAYER_FREEIF(caps_str);
2602 if (player->v_stream_caps) {
2603 gst_caps_unref(player->v_stream_caps);
2604 player->v_stream_caps = NULL;
2607 LOGD("create fakesink instead of videobin");
2610 fakesink = gst_element_factory_make("fakesink", NULL);
2611 if (fakesink == NULL) {
2612 LOGE("ERROR : fakesink create error\n");
2616 if (player->ini.set_dump_element_flag)
2617 __mmplayer_add_dump_buffer_probe(player, fakesink);
2619 player->video_fakesink = fakesink;
2621 /* store it as it's sink element */
2622 __mmplayer_add_sink(player, player->video_fakesink);
2624 gst_bin_add(GST_BIN(pipeline), fakesink);
2627 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2629 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2630 LOGW("failed to link fakesink\n");
2631 gst_object_unref(GST_OBJECT(fakesink));
2635 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2636 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2637 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2640 if (player->set_mode.media_packet_video_stream) {
2641 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2643 MMPLAYER_SIGNAL_CONNECT(player,
2645 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2647 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2650 MMPLAYER_SIGNAL_CONNECT(player,
2652 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2654 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2658 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2659 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2663 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2664 __mmplayer_gst_decode_callback(elem, pad, player);
2668 LOGD("video selector \n");
2669 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2670 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2672 if (strstr(name, "audio")) {
2673 gint samplerate = 0;
2676 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2677 __mmplayer_gst_decode_callback(elem, pad, player);
2681 LOGD("audio selector \n");
2682 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2683 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2685 gst_structure_get_int(str, "rate", &samplerate);
2686 gst_structure_get_int(str, "channels", &channels);
2688 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2690 fakesink = gst_element_factory_make("fakesink", NULL);
2691 if (fakesink == NULL) {
2692 LOGE("ERROR : fakesink create error\n");
2696 gst_bin_add(GST_BIN(pipeline), fakesink);
2699 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2701 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2702 LOGW("failed to link fakesink\n");
2703 gst_object_unref(GST_OBJECT(fakesink));
2707 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2708 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2709 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2713 } else if (strstr(name, "text")) {
2714 LOGD("text selector \n");
2715 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2716 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2718 LOGE("wrong elem id \n");
2723 selector = player->pipeline->mainbin[elemId].gst;
2724 if (selector == NULL) {
2725 selector = gst_element_factory_make("input-selector", NULL);
2726 LOGD("Creating input-selector\n");
2727 if (selector == NULL) {
2728 LOGE("ERROR : input-selector create error\n");
2731 g_object_set(selector, "sync-streams", TRUE, NULL);
2733 player->pipeline->mainbin[elemId].id = elemId;
2734 player->pipeline->mainbin[elemId].gst = selector;
2737 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2739 srcpad = gst_element_get_static_pad(selector, "src");
2741 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2742 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2743 __mmplayer_gst_selector_blocked, NULL, NULL);
2744 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2745 __mmplayer_gst_selector_event_probe, player, NULL);
2747 gst_element_set_state(selector, GST_STATE_PAUSED);
2748 gst_bin_add(GST_BIN(pipeline), selector);
2750 LOGD("input-selector is already created.\n");
2753 LOGD("Calling request pad with selector %p \n", selector);
2754 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2756 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2758 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2759 LOGW("failed to link selector\n");
2760 gst_object_unref(GST_OBJECT(selector));
2765 LOGD("this is first track --> active track \n");
2766 g_object_set(selector, "active-pad", sinkpad, NULL);
2769 _mmplayer_track_update_info(player, stream_type, sinkpad);
2776 gst_caps_unref(caps);
2779 gst_object_unref(GST_OBJECT(sinkpad));
2784 gst_object_unref(GST_OBJECT(srcpad));
2791 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2793 GstPad* srcpad = NULL;
2794 MMHandleType attrs = 0;
2795 gint active_index = 0;
2797 // [link] input-selector :: textbin
2798 srcpad = gst_element_get_static_pad(text_selector, "src");
2800 LOGE("failed to get srcpad from selector\n");
2804 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2806 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2807 if ((active_index != DEFAULT_TRACK) &&
2808 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2809 LOGW("failed to change text track\n");
2810 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2813 player->no_more_pad = TRUE;
2814 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2816 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2817 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2818 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2819 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2822 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2824 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2825 player->has_closed_caption = TRUE;
2827 attrs = MMPLAYER_GET_ATTRS(player);
2829 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2830 if (mmf_attrs_commit(attrs))
2831 LOGE("failed to commit.\n");
2833 LOGE("cannot get content attribute");
2836 gst_object_unref(GST_OBJECT(srcpad));
2842 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2844 mm_player_t* player = (mm_player_t*)data;
2845 GstElement* selector = NULL;
2846 GstElement* queue = NULL;
2848 GstPad* srcpad = NULL;
2849 GstPad* sinkpad = NULL;
2850 GstCaps* caps = NULL;
2851 gchar* caps_str = NULL;
2854 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2856 caps = gst_pad_get_current_caps(pad);
2857 caps_str = gst_caps_to_string(caps);
2858 LOGD("deinterleave new caps : %s\n", caps_str);
2859 MMPLAYER_FREEIF(caps_str);
2860 gst_caps_unref(caps);
2862 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2863 LOGE("ERROR : queue create error\n");
2867 g_object_set(G_OBJECT(queue),
2868 "max-size-buffers", 10,
2869 "max-size-bytes", 0,
2870 "max-size-time", (guint64)0,
2873 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2876 LOGE("there is no audio channel selector.\n");
2880 srcpad = gst_element_get_static_pad(queue, "src");
2881 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2883 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2885 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2886 LOGW("failed to link deinterleave - selector\n");
2890 gst_element_set_state(queue, GST_STATE_PAUSED);
2891 player->audio_mode.total_track_num++;
2896 gst_object_unref(GST_OBJECT(srcpad));
2901 gst_object_unref(GST_OBJECT(sinkpad));
2910 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2912 mm_player_t* player = NULL;
2913 GstElement* selector = NULL;
2914 GstPad* sinkpad = NULL;
2915 gint active_index = 0;
2916 gchar* change_pad_name = NULL;
2917 GstCaps* caps = NULL; // no need to unref
2918 gint default_audio_ch = 0;
2921 player = (mm_player_t*) data;
2923 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2926 LOGE("there is no audio channel selector.\n");
2930 active_index = player->audio_mode.active_pad_index;
2932 if (active_index != default_audio_ch) {
2933 gint audio_ch = default_audio_ch;
2935 /*To get the new pad from the selector*/
2936 change_pad_name = g_strdup_printf("sink%d", active_index);
2937 if (change_pad_name != NULL) {
2938 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2939 if (sinkpad != NULL) {
2940 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2941 g_object_set(selector, "active-pad", sinkpad, NULL);
2943 audio_ch = active_index;
2945 caps = gst_pad_get_current_caps(sinkpad);
2946 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2948 __mmplayer_set_audio_attrs(player, caps);
2949 gst_caps_unref(caps);
2951 MMPLAYER_FREEIF(change_pad_name);
2954 player->audio_mode.active_pad_index = audio_ch;
2955 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2961 gst_object_unref(sinkpad);
2968 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2970 mm_player_t* player = NULL;
2971 MMPlayerGstElement *mainbin = NULL;
2973 GstElement* tee = NULL;
2974 GstElement* stereo_queue = NULL;
2975 GstElement* mono_queue = NULL;
2976 GstElement* conv = NULL;
2977 GstElement* filter = NULL;
2978 GstElement* deinterleave = NULL;
2979 GstElement* selector = NULL;
2981 GstPad* srcpad = NULL;
2982 GstPad* selector_srcpad = NULL;
2983 GstPad* sinkpad = NULL;
2984 GstCaps* caps = NULL;
2985 gulong block_id = 0;
2990 player = (mm_player_t*) data;
2992 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2993 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2995 mainbin = player->pipeline->mainbin;
2998 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2999 LOGE("ERROR : tee create error\n");
3003 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
3004 mainbin[MMPLAYER_M_A_TEE].gst = tee;
3006 gst_element_set_state(tee, GST_STATE_PAUSED);
3009 srcpad = gst_element_get_request_pad(tee, "src_%u");
3010 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3011 LOGE("ERROR : stereo queue create error\n");
3015 g_object_set(G_OBJECT(stereo_queue),
3016 "max-size-buffers", 10,
3017 "max-size-bytes", 0,
3018 "max-size-time", (guint64)0,
3021 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3022 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3025 gst_object_unref(GST_OBJECT(srcpad));
3029 srcpad = gst_element_get_request_pad(tee, "src_%u");
3031 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3032 LOGE("ERROR : mono queue create error\n");
3036 g_object_set(G_OBJECT(mono_queue),
3037 "max-size-buffers", 10,
3038 "max-size-bytes", 0,
3039 "max-size-time", (guint64)0,
3042 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3043 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3045 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3046 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3049 srcpad = gst_element_get_static_pad(mono_queue, "src");
3050 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3051 LOGE("ERROR : audioconvert create error\n");
3055 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3056 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3060 gst_object_unref(GST_OBJECT(srcpad));
3063 srcpad = gst_element_get_static_pad(conv, "src");
3065 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3066 LOGE("ERROR : capsfilter create error\n");
3070 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3071 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3073 caps = gst_caps_from_string("audio/x-raw-int, "
3074 "width = (int) 16, "
3075 "depth = (int) 16, "
3076 "channels = (int) 2");
3078 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3079 gst_caps_unref(caps);
3081 gst_element_set_state(conv, GST_STATE_PAUSED);
3082 gst_element_set_state(filter, GST_STATE_PAUSED);
3086 gst_object_unref(GST_OBJECT(srcpad));
3089 srcpad = gst_element_get_static_pad(filter, "src");
3091 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3092 LOGE("ERROR : deinterleave create error\n");
3096 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3098 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3099 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3101 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3102 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3104 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3105 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3108 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3109 if (selector == NULL) {
3110 LOGE("ERROR : audio-selector create error\n");
3114 g_object_set(selector, "sync-streams", TRUE, NULL);
3115 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3117 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3118 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3120 selector_srcpad = gst_element_get_static_pad(selector, "src");
3122 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3124 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3125 __mmplayer_gst_selector_blocked, NULL, NULL);
3128 gst_object_unref(GST_OBJECT(srcpad));
3132 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3133 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3135 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3136 LOGW("failed to link queue_stereo - selector\n");
3140 player->audio_mode.total_track_num++;
3142 g_object_set(selector, "active-pad", sinkpad, NULL);
3143 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3144 gst_element_set_state(selector, GST_STATE_PAUSED);
3146 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3150 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3151 if (block_id != 0) {
3152 gst_pad_remove_probe(selector_srcpad, block_id);
3157 gst_object_unref(GST_OBJECT(sinkpad));
3162 gst_object_unref(GST_OBJECT(srcpad));
3166 if (selector_srcpad) {
3167 gst_object_unref(GST_OBJECT(selector_srcpad));
3168 selector_srcpad = NULL;
3176 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3178 mm_player_t* player = NULL;
3179 GstPad* srcpad = NULL;
3180 GstElement* video_selector = NULL;
3181 GstElement* audio_selector = NULL;
3182 GstElement* text_selector = NULL;
3183 MMHandleType attrs = 0;
3184 gint active_index = 0;
3185 gint64 dur_bytes = 0L;
3187 player = (mm_player_t*) data;
3189 LOGD("no-more-pad signal handling\n");
3191 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3192 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3193 LOGW("no need to go more");
3195 if (player->gapless.reconfigure) {
3196 player->gapless.reconfigure = FALSE;
3197 MMPLAYER_PLAYBACK_UNLOCK(player);
3203 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3204 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3205 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3206 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3207 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3209 if (NULL == player->streamer) {
3210 LOGW("invalid state for buffering");
3214 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3215 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3217 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3218 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3220 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3222 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3223 LOGE("fail to get duration.\n");
3225 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3226 * use file information was already set on Q2 when it was created. */
3227 __mm_player_streaming_set_queue2(player->streamer,
3228 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3229 TRUE, /* use_buffering */
3231 init_buffering_time,
3232 1.0, /* low percent */
3233 player->ini.http_buffering_limit, /* high percent */
3234 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
3236 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3239 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3240 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3241 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3242 if (video_selector) {
3243 // [link] input-selector :: videobin
3244 srcpad = gst_element_get_static_pad(video_selector, "src");
3246 LOGE("failed to get srcpad from video selector\n");
3250 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3251 if (!text_selector && !audio_selector)
3252 player->no_more_pad = TRUE;
3254 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3256 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3257 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3258 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3259 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3263 if (audio_selector) {
3264 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3265 if ((active_index != DEFAULT_TRACK) &&
3266 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3267 LOGW("failed to change audio track\n");
3268 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3271 // [link] input-selector :: audiobin
3272 srcpad = gst_element_get_static_pad(audio_selector, "src");
3274 LOGE("failed to get srcpad from selector\n");
3278 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3280 player->no_more_pad = TRUE;
3282 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3283 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3284 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3285 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3286 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3289 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3291 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3293 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3294 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3295 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3296 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3300 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3302 attrs = MMPLAYER_GET_ATTRS(player);
3304 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3305 if (mmf_attrs_commit(attrs))
3306 LOGE("failed to commit.\n");
3308 LOGE("cannot get content attribute");
3310 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3311 LOGD("There is no audio track : remove audiobin");
3313 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3314 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3316 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3317 MMPLAYER_FREEIF(player->pipeline->audiobin);
3320 if (player->num_dynamic_pad == 0)
3321 __mmplayer_pipeline_complete(NULL, player);
3324 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3326 __mmplayer_handle_text_decode_path(player, text_selector);
3333 gst_object_unref(GST_OBJECT(srcpad));
3337 if (player->gapless.reconfigure) {
3338 player->gapless.reconfigure = FALSE;
3339 MMPLAYER_PLAYBACK_UNLOCK(player);
3344 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3346 mm_player_t* player = NULL;
3347 MMHandleType attrs = 0;
3348 GstElement* pipeline = NULL;
3349 GstCaps* caps = NULL;
3350 gchar* caps_str = NULL;
3351 GstStructure* str = NULL;
3352 const gchar* name = NULL;
3353 GstPad* sinkpad = NULL;
3354 GstElement* sinkbin = NULL;
3355 gboolean reusing = FALSE;
3356 GstElement *text_selector = NULL;
3359 player = (mm_player_t*) data;
3361 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3362 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3364 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3366 attrs = MMPLAYER_GET_ATTRS(player);
3368 LOGE("cannot get content attribute\n");
3372 /* get mimetype from caps */
3373 caps = gst_pad_query_caps(pad, NULL);
3375 LOGE("cannot get caps from pad.\n");
3378 caps_str = gst_caps_to_string(caps);
3380 str = gst_caps_get_structure(caps, 0);
3382 LOGE("cannot get structure from caps.\n");
3386 name = gst_structure_get_name(str);
3388 LOGE("cannot get mimetype from structure.\n");
3392 //LOGD("detected mimetype : %s\n", name);
3394 if (strstr(name, "audio")) {
3395 if (player->pipeline->audiobin == NULL) {
3396 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3397 LOGE("failed to create audiobin. continuing without audio\n");
3401 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3402 LOGD("creating audiosink bin success\n");
3405 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3406 LOGD("reusing audiobin\n");
3407 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3410 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3411 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3413 player->audiosink_linked = 1;
3415 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3417 LOGE("failed to get pad from sinkbin\n");
3420 } else if (strstr(name, "video")) {
3421 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3422 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3423 player->set_mode.video_zc = TRUE;
3425 if (player->pipeline->videobin == NULL) {
3426 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3427 /* get video surface type */
3428 int surface_type = 0;
3429 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3430 LOGD("display_surface_type(%d)\n", surface_type);
3432 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3433 LOGD("not make videobin because it dose not want\n");
3437 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3438 /* mark video overlay for acquire */
3439 if (player->video_overlay_resource == NULL) {
3440 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3441 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3442 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3443 &player->video_overlay_resource)
3444 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3445 LOGE("could not mark video_overlay resource for acquire\n");
3451 player->interrupted_by_resource = FALSE;
3452 /* acquire resources for video overlay */
3453 if (mm_resource_manager_commit(player->resource_manager) !=
3454 MM_RESOURCE_MANAGER_ERROR_NONE) {
3455 LOGE("could not acquire resources for video playing\n");
3459 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3460 LOGE("failed to create videobin. continuing without video\n");
3464 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3465 LOGD("creating videosink bin success\n");
3468 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3469 LOGD("re-using videobin\n");
3470 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3473 player->videosink_linked = 1;
3475 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3477 LOGE("failed to get pad from sinkbin\n");
3480 } else if (strstr(name, "text")) {
3481 if (player->pipeline->textbin == NULL) {
3482 MMPlayerGstElement* mainbin = NULL;
3484 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3485 LOGE("failed to create text sink bin. continuing without text\n");
3489 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3490 LOGD("creating textsink bin success\n");
3492 /* FIXIT : track number shouldn't be hardcoded */
3493 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3495 player->textsink_linked = 1;
3496 LOGI("player->textsink_linked set to 1\n");
3498 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3500 LOGE("failed to get pad from sinkbin\n");
3504 mainbin = player->pipeline->mainbin;
3506 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3507 /* input selector */
3508 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3509 if (!text_selector) {
3510 LOGE("failed to create subtitle input selector element\n");
3513 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3515 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3516 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3519 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3520 LOGE("failed to set state(READY) to sinkbin\n");
3524 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3525 LOGW("failed to add subtitle input selector\n");
3529 LOGD("created element input-selector");
3532 LOGD("already having subtitle input selector");
3533 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3536 if (!player->textsink_linked) {
3537 LOGD("re-using textbin\n");
3540 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3542 player->textsink_linked = 1;
3543 LOGI("player->textsink_linked set to 1\n");
3545 LOGD("ignoring internal subtutle since external subtitle is available");
3548 LOGW("unknown type of elementary stream!ignoring it...\n");
3555 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3556 LOGE("failed to set state(READY) to sinkbin\n");
3560 /* Added for multi audio support to avoid adding audio bin again*/
3562 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3563 LOGE("failed to add sinkbin to pipeline\n");
3569 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3570 LOGE("failed to get pad from sinkbin\n");
3576 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3577 LOGE("failed to set state(PAUSED) to sinkbin\n");
3581 if (text_selector) {
3582 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3583 LOGE("failed to set state(PAUSED) to sinkbin\n");
3589 gst_object_unref(sinkpad);
3593 LOGD("[handle: %p] linking sink bin success", player);
3595 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3596 * streaming task. if the task blocked, then buffer will not flow to the next element
3597 *(autoplugging element). so this is special hack for streaming. please try to remove it
3599 /* dec stream count. we can remove fakesink if it's zero */
3600 if (player->num_dynamic_pad)
3601 player->num_dynamic_pad--;
3603 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3605 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3606 __mmplayer_pipeline_complete(NULL, player);
3610 MMPLAYER_FREEIF(caps_str);
3613 gst_caps_unref(caps);
3616 gst_object_unref(GST_OBJECT(sinkpad));
3618 /* flusing out new attributes */
3619 if (mmf_attrs_commit(attrs))
3620 LOGE("failed to comit attributes\n");
3626 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3628 int pro_value = 0; // in the case of expection, default will be returned.
3629 int dest_angle = rotation_angle;
3630 int rotation_type = -1;
3632 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3633 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3634 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3636 if (rotation_angle >= 360)
3637 dest_angle = rotation_angle - 360;
3639 /* chech if supported or not */
3640 if (dest_angle % 90) {
3641 LOGD("not supported rotation angle = %d", rotation_angle);
3647 * custom_convert - none (B)
3648 * videoflip - none (C)
3650 if (player->set_mode.video_zc) {
3651 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3652 rotation_type = ROTATION_USING_CUSTOM;
3654 rotation_type = ROTATION_USING_SINK;
3656 int surface_type = 0;
3657 rotation_type = ROTATION_USING_FLIP;
3659 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3660 LOGD("check display surface type attribute: %d", surface_type);
3662 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3663 rotation_type = ROTATION_USING_SINK;
3665 rotation_type = ROTATION_USING_FLIP; //C
3667 LOGD("using %d type for rotation", rotation_type);
3670 /* get property value for setting */
3671 switch (rotation_type) {
3672 case ROTATION_USING_SINK: // tizenwlsink
3674 switch (dest_angle) {
3678 pro_value = 3; // clockwise 90
3684 pro_value = 1; // counter-clockwise 90
3689 case ROTATION_USING_CUSTOM:
3691 gchar *ename = NULL;
3692 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3694 if (g_strrstr(ename, "fimcconvert")) {
3695 switch (dest_angle) {
3699 pro_value = 90; // clockwise 90
3705 pro_value = 270; // counter-clockwise 90
3711 case ROTATION_USING_FLIP: // videoflip
3713 switch (dest_angle) {
3717 pro_value = 1; // clockwise 90
3723 pro_value = 3; // counter-clockwise 90
3730 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3738 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3740 /* check video sinkbin is created */
3741 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3743 player->pipeline->videobin &&
3744 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3745 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3746 MM_ERROR_PLAYER_NOT_INITIALIZED);
3748 return MM_ERROR_NONE;
3752 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3754 int rotation_value = 0;
3755 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3759 /* check video sinkbin is created */
3760 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3763 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3765 /* get rotation value to set */
3766 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3767 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3768 LOGD("set video param : rotate %d", rotation_value);
3772 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3774 MMHandleType attrs = 0;
3778 /* check video sinkbin is created */
3779 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3782 attrs = MMPLAYER_GET_ATTRS(player);
3783 MMPLAYER_RETURN_IF_FAIL(attrs);
3785 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3786 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3787 LOGD("set video param : visible %d", visible);
3791 __mmplayer_video_param_set_display_method(mm_player_t* player)
3793 MMHandleType attrs = 0;
3794 int display_method = 0;
3797 /* check video sinkbin is created */
3798 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3801 attrs = MMPLAYER_GET_ATTRS(player);
3802 MMPLAYER_RETURN_IF_FAIL(attrs);
3804 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3805 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3806 LOGD("set video param : method %d", display_method);
3810 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3812 MMHandleType attrs = 0;
3813 void *handle = NULL;
3815 int wl_window_x = 0;
3816 int wl_window_y = 0;
3817 int wl_window_width = 0;
3818 int wl_window_height = 0;
3821 /* check video sinkbin is created */
3822 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3825 attrs = MMPLAYER_GET_ATTRS(player);
3826 MMPLAYER_RETURN_IF_FAIL(attrs);
3828 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3831 /*It should be set after setting window*/
3832 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3833 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3834 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3835 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3837 /* After setting window handle, set render rectangle */
3838 gst_video_overlay_set_render_rectangle(
3839 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3840 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3841 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3842 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3847 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3849 MMHandleType attrs = 0;
3850 void *handle = NULL;
3852 /* check video sinkbin is created */
3853 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3856 attrs = MMPLAYER_GET_ATTRS(player);
3857 MMPLAYER_RETURN_IF_FAIL(attrs);
3859 /* common case if using overlay surface */
3860 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3863 /* default is using wl_surface_id */
3864 unsigned int wl_surface_id = 0;
3865 wl_surface_id = *(int*)handle;
3866 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3867 gst_video_overlay_set_wl_window_wl_surface_id(
3868 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3871 /* FIXIT : is it error case? */
3872 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3877 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3879 bool update_all_param = FALSE;
3882 /* check video sinkbin is created */
3883 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3884 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3886 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3887 LOGE("can not find tizenwlsink");
3888 return MM_ERROR_PLAYER_INTERNAL;
3891 LOGD("param_name : %s", param_name);
3892 if (!g_strcmp0(param_name, "update_all_param"))
3893 update_all_param = TRUE;
3895 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3896 __mmplayer_video_param_set_display_overlay(player);
3897 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3898 __mmplayer_video_param_set_display_method(player);
3899 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3900 __mmplayer_video_param_set_render_rectangle(player);
3901 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3902 __mmplayer_video_param_set_display_visible(player);
3903 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3904 __mmplayer_video_param_set_display_rotation(player);
3906 return MM_ERROR_NONE;
3910 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3912 MMHandleType attrs = 0;
3913 int surface_type = 0;
3914 int ret = MM_ERROR_NONE;
3918 /* check video sinkbin is created */
3919 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3920 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3922 attrs = MMPLAYER_GET_ATTRS(player);
3924 LOGE("cannot get content attribute");
3925 return MM_ERROR_PLAYER_INTERNAL;
3927 LOGD("param_name : %s", param_name);
3929 /* update display surface */
3930 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3931 LOGD("check display surface type attribute: %d", surface_type);
3933 /* configuring display */
3934 switch (surface_type) {
3935 case MM_DISPLAY_SURFACE_OVERLAY:
3937 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3938 if (ret != MM_ERROR_NONE)
3946 return MM_ERROR_NONE;
3950 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3952 gboolean disable_overlay = FALSE;
3953 mm_player_t* player = (mm_player_t*) hplayer;
3954 int ret = MM_ERROR_NONE;
3957 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3958 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3959 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3960 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3962 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3963 LOGW("Display control is not supported");
3964 return MM_ERROR_PLAYER_INTERNAL;
3967 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3969 if (audio_only == (bool)disable_overlay) {
3970 LOGE("It's the same with current setting: (%d)", audio_only);
3971 return MM_ERROR_NONE;
3975 LOGE("disable overlay");
3976 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3978 /* release overlay resource */
3979 if (player->video_overlay_resource != NULL) {
3980 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3981 player->video_overlay_resource);
3982 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3983 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3986 player->video_overlay_resource = NULL;
3989 ret = mm_resource_manager_commit(player->resource_manager);
3990 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3991 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3995 /* mark video overlay for acquire */
3996 if (player->video_overlay_resource == NULL) {
3997 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3998 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3999 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
4000 &player->video_overlay_resource);
4001 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4002 LOGE("could not prepare for video_overlay resource\n");
4007 player->interrupted_by_resource = FALSE;
4008 /* acquire resources for video overlay */
4009 ret = mm_resource_manager_commit(player->resource_manager);
4010 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
4011 LOGE("could not acquire resources for video playing\n");
4015 LOGD("enable overlay");
4016 __mmplayer_video_param_set_display_overlay(player);
4017 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4022 return MM_ERROR_NONE;
4026 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4028 mm_player_t* player = (mm_player_t*) hplayer;
4029 gboolean disable_overlay = FALSE;
4033 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4034 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4035 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4036 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4037 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4039 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4040 LOGW("Display control is not supported");
4041 return MM_ERROR_PLAYER_INTERNAL;
4044 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4046 *paudio_only = (bool)(disable_overlay);
4048 LOGD("audio_only : %d", *paudio_only);
4052 return MM_ERROR_NONE;
4056 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4058 GList* bucket = element_bucket;
4059 MMPlayerGstElement* element = NULL;
4060 MMPlayerGstElement* prv_element = NULL;
4061 gint successful_link_count = 0;
4065 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4067 prv_element = (MMPlayerGstElement*)bucket->data;
4068 bucket = bucket->next;
4070 for (; bucket; bucket = bucket->next) {
4071 element = (MMPlayerGstElement*)bucket->data;
4073 if (element && element->gst) {
4074 /* If next element is audio appsrc then make a separate audio pipeline */
4075 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4076 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4077 prv_element = element;
4081 if (prv_element && prv_element->gst) {
4082 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4083 LOGD("linking [%s] to [%s] success\n",
4084 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4085 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4086 successful_link_count++;
4088 LOGD("linking [%s] to [%s] failed\n",
4089 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4090 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4096 prv_element = element;
4101 return successful_link_count;
4105 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4107 GList* bucket = element_bucket;
4108 MMPlayerGstElement* element = NULL;
4109 int successful_add_count = 0;
4113 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4114 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4116 for (; bucket; bucket = bucket->next) {
4117 element = (MMPlayerGstElement*)bucket->data;
4119 if (element && element->gst) {
4120 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4121 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4122 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4123 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4126 successful_add_count++;
4132 return successful_add_count;
4135 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4137 mm_player_t* player = (mm_player_t*) data;
4138 GstCaps *caps = NULL;
4139 GstStructure *str = NULL;
4144 MMPLAYER_RETURN_IF_FAIL(pad)
4145 MMPLAYER_RETURN_IF_FAIL(unused)
4146 MMPLAYER_RETURN_IF_FAIL(data)
4148 caps = gst_pad_get_current_caps(pad);
4152 str = gst_caps_get_structure(caps, 0);
4156 name = gst_structure_get_name(str);
4160 LOGD("name = %s\n", name);
4162 if (strstr(name, "audio")) {
4163 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4165 if (player->audio_stream_changed_cb) {
4166 LOGE("call the audio stream changed cb\n");
4167 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4169 } else if (strstr(name, "video")) {
4170 if ((name = gst_structure_get_string(str, "format")))
4171 player->set_mode.video_zc = name[0] == 'S';
4173 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4175 if (player->video_stream_changed_cb) {
4176 LOGE("call the video stream changed cb\n");
4177 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4184 gst_caps_unref(caps);
4194 * This function is to create audio pipeline for playing.
4196 * @param player [in] handle of player
4198 * @return This function returns zero on success.
4200 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4202 /* macro for code readability. just for sinkbin-creation functions */
4203 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4205 x_bin[x_id].id = x_id;\
4206 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4207 if (!x_bin[x_id].gst) {\
4208 LOGE("failed to create %s \n", x_factory);\
4211 if (x_player->ini.set_dump_element_flag)\
4212 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4215 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4219 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4224 MMPLAYER_RETURN_IF_FAIL(player);
4226 if (player->audio_stream_buff_list) {
4227 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4228 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4231 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4232 __mmplayer_audio_stream_send_data(player, tmp);
4235 g_free(tmp->pcm_data);
4239 g_list_free(player->audio_stream_buff_list);
4240 player->audio_stream_buff_list = NULL;
4247 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4249 MMPlayerAudioStreamDataType audio_stream = { 0, };
4252 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4254 audio_stream.bitrate = a_buffer->bitrate;
4255 audio_stream.channel = a_buffer->channel;
4256 audio_stream.depth = a_buffer->depth;
4257 audio_stream.is_little_endian = a_buffer->is_little_endian;
4258 audio_stream.channel_mask = a_buffer->channel_mask;
4259 audio_stream.data_size = a_buffer->data_size;
4260 audio_stream.data = a_buffer->pcm_data;
4262 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4263 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4269 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4271 mm_player_t* player = (mm_player_t*) data;
4276 gint endianness = 0;
4277 guint64 channel_mask = 0;
4278 void *a_data = NULL;
4280 mm_player_audio_stream_buff_t *a_buffer = NULL;
4281 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4285 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4287 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4288 a_data = mapinfo.data;
4289 a_size = mapinfo.size;
4291 GstCaps *caps = gst_pad_get_current_caps(pad);
4292 GstStructure *structure = gst_caps_get_structure(caps, 0);
4294 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4295 gst_structure_get_int(structure, "rate", &rate);
4296 gst_structure_get_int(structure, "channels", &channel);
4297 gst_structure_get_int(structure, "depth", &depth);
4298 gst_structure_get_int(structure, "endianness", &endianness);
4299 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4300 gst_caps_unref(GST_CAPS(caps));
4302 /* In case of the sync is false, use buffer list. *
4303 * The num of buffer list depends on the num of audio channels */
4304 if (player->audio_stream_buff_list) {
4305 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4306 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4308 if (channel_mask == tmp->channel_mask) {
4309 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4310 if (tmp->data_size + a_size < tmp->buff_size) {
4311 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4312 tmp->data_size += a_size;
4314 /* send data to client */
4315 __mmplayer_audio_stream_send_data(player, tmp);
4317 if (a_size > tmp->buff_size) {
4318 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4319 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4320 if (tmp->pcm_data == NULL) {
4321 LOGE("failed to realloc data.");
4324 tmp->buff_size = a_size;
4326 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4327 memcpy(tmp->pcm_data, a_data, a_size);
4328 tmp->data_size = a_size;
4333 LOGE("data is empty in list.");
4339 /* create new audio stream data */
4340 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4341 if (a_buffer == NULL) {
4342 LOGE("failed to alloc data.");
4345 a_buffer->bitrate = rate;
4346 a_buffer->channel = channel;
4347 a_buffer->depth = depth;
4348 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4349 a_buffer->channel_mask = channel_mask;
4350 a_buffer->data_size = a_size;
4352 if (!player->audio_stream_sink_sync) {
4353 /* If sync is FALSE, use buffer list to reduce the IPC. */
4354 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4355 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4356 if (a_buffer->pcm_data == NULL) {
4357 LOGE("failed to alloc data.");
4361 memcpy(a_buffer->pcm_data, a_data, a_size);
4362 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4363 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4365 /* If sync is TRUE, send data directly. */
4366 a_buffer->pcm_data = a_data;
4367 __mmplayer_audio_stream_send_data(player, a_buffer);
4372 gst_buffer_unmap(buffer, &mapinfo);
4377 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4379 mm_player_t* player = (mm_player_t*)data;
4380 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4381 GstPad* sinkpad = NULL;
4382 GstElement *queue = NULL, *sink = NULL;
4385 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4387 queue = gst_element_factory_make("queue", NULL);
4388 if (queue == NULL) {
4389 LOGD("fail make queue\n");
4393 sink = gst_element_factory_make("fakesink", NULL);
4395 LOGD("fail make fakesink\n");
4399 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4401 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4402 LOGW("failed to link queue & sink\n");
4406 sinkpad = gst_element_get_static_pad(queue, "sink");
4408 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4409 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4413 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4415 gst_object_unref(sinkpad);
4416 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4417 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4419 gst_element_set_state(sink, GST_STATE_PAUSED);
4420 gst_element_set_state(queue, GST_STATE_PAUSED);
4422 MMPLAYER_SIGNAL_CONNECT(player,
4424 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4426 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4433 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4435 gst_object_unref(GST_OBJECT(queue));
4439 gst_object_unref(GST_OBJECT(sink));
4443 gst_object_unref(GST_OBJECT(sinkpad));
4450 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4452 #define MAX_PROPS_LEN 128
4453 gint latency_mode = 0;
4454 gchar *stream_type = NULL;
4455 gchar *latency = NULL;
4457 gchar stream_props[MAX_PROPS_LEN] = {0,};
4458 GstStructure *props = NULL;
4461 * It should be set after player creation through attribute.
4462 * But, it can not be changed during playing.
4465 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4466 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4469 LOGE("stream_type is null.\n");
4471 if (player->sound.focus_id)
4472 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4473 stream_type, stream_id, player->sound.focus_id);
4475 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4476 stream_type, stream_id);
4477 props = gst_structure_from_string(stream_props, NULL);
4478 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4479 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4480 stream_type, stream_id, player->sound.focus_id, stream_props);
4481 gst_structure_free(props);
4484 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4486 switch (latency_mode) {
4487 case AUDIO_LATENCY_MODE_LOW:
4488 latency = g_strndup("low", 3);
4490 case AUDIO_LATENCY_MODE_MID:
4491 latency = g_strndup("mid", 3);
4493 case AUDIO_LATENCY_MODE_HIGH:
4494 latency = g_strndup("high", 4);
4498 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4502 LOGD("audiosink property - latency=%s \n", latency);
4510 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4512 MMPlayerGstElement* first_element = NULL;
4513 MMPlayerGstElement* audiobin = NULL;
4514 MMHandleType attrs = 0;
4516 GstPad *ghostpad = NULL;
4517 GList* element_bucket = NULL;
4518 gboolean link_audio_sink_now = TRUE;
4524 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4527 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4529 LOGE("failed to allocate memory for audiobin\n");
4530 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4533 attrs = MMPLAYER_GET_ATTRS(player);
4536 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4537 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4538 if (!audiobin[MMPLAYER_A_BIN].gst) {
4539 LOGE("failed to create audiobin\n");
4544 player->pipeline->audiobin = audiobin;
4546 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4548 /* Adding audiotp plugin for reverse trickplay feature */
4549 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4552 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4554 /* replaygain volume */
4555 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4556 if (player->sound.rg_enable)
4557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4559 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4562 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4564 if (player->set_mode.pcm_extraction) {
4565 // pcm extraction only and no sound output
4566 if (player->audio_stream_render_cb_ex) {
4567 char *caps_str = NULL;
4568 GstCaps* caps = NULL;
4569 gchar *format = NULL;
4572 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4574 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4576 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4578 caps = gst_caps_new_simple("audio/x-raw",
4579 "format", G_TYPE_STRING, format,
4580 "rate", G_TYPE_INT, player->pcm_samplerate,
4581 "channels", G_TYPE_INT, player->pcm_channel,
4583 caps_str = gst_caps_to_string(caps);
4584 LOGD("new caps : %s\n", caps_str);
4586 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4589 gst_caps_unref(caps);
4590 MMPLAYER_FREEIF(caps_str);
4592 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4594 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4595 /* raw pad handling signal */
4596 MMPLAYER_SIGNAL_CONNECT(player,
4597 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4598 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4599 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4601 int dst_samplerate = 0;
4602 int dst_channels = 0;
4604 char *caps_str = NULL;
4605 GstCaps* caps = NULL;
4607 /* get conf. values */
4608 mm_attrs_multiple_get(player->attrs,
4610 "pcm_extraction_samplerate", &dst_samplerate,
4611 "pcm_extraction_channels", &dst_channels,
4612 "pcm_extraction_depth", &dst_depth,
4616 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4617 caps = gst_caps_new_simple("audio/x-raw",
4618 "rate", G_TYPE_INT, dst_samplerate,
4619 "channels", G_TYPE_INT, dst_channels,
4620 "depth", G_TYPE_INT, dst_depth,
4622 caps_str = gst_caps_to_string(caps);
4623 LOGD("new caps : %s\n", caps_str);
4625 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4628 gst_caps_unref(caps);
4629 MMPLAYER_FREEIF(caps_str);
4632 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4639 //GstCaps* caps = NULL;
4642 /* for logical volume control */
4643 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4644 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4646 if (player->sound.mute) {
4647 LOGD("mute enabled\n");
4648 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4654 caps = gst_caps_from_string("audio/x-raw-int, "
4655 "endianness = (int) LITTLE_ENDIAN, "
4656 "signed = (boolean) true, "
4657 "width = (int) 16, "
4658 "depth = (int) 16");
4659 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4660 gst_caps_unref(caps);
4663 /* check if multi-channels */
4664 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4665 GstPad *srcpad = NULL;
4666 GstCaps *caps = NULL;
4668 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4669 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4670 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4671 GstStructure *str = gst_caps_get_structure(caps, 0);
4673 gst_structure_get_int(str, "channels", &channels);
4674 gst_caps_unref(caps);
4676 gst_object_unref(srcpad);
4680 /* audio effect element. if audio effect is enabled */
4681 if ((strcmp(player->ini.audioeffect_element, ""))
4683 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4686 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4688 if ((!player->bypass_audio_effect)
4689 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4690 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4691 if (!_mmplayer_audio_effect_custom_apply(player))
4692 LOGI("apply audio effect(custom) setting success\n");
4696 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4697 && (player->set_mode.rich_audio))
4698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4701 /* create audio sink */
4702 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4703 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4704 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4706 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4707 if (player->is_360_feature_enabled &&
4708 player->is_content_spherical &&
4710 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4711 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4712 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4714 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4719 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4721 gst_caps_unref(acaps);
4723 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4724 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4725 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4728 player->is_openal_plugin_used = TRUE;
4730 if (player->video360_yaw_radians <= M_PI &&
4731 player->video360_yaw_radians >= -M_PI &&
4732 player->video360_pitch_radians <= M_PI_2 &&
4733 player->video360_pitch_radians >= -M_PI_2) {
4734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4735 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4736 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4737 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4738 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4739 "source-orientation-y", player->video360_metadata.init_view_heading,
4740 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4743 if (player->is_360_feature_enabled && player->is_content_spherical)
4744 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4745 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4749 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4750 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4753 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4754 (player->videodec_linked && player->ini.use_system_clock)) {
4755 LOGD("system clock will be used.\n");
4756 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4759 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4760 __mmplayer_gst_set_audiosink_property(player, attrs);
4763 if (audiobin[MMPLAYER_A_SINK].gst) {
4764 GstPad *sink_pad = NULL;
4765 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4766 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4767 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4768 gst_object_unref(GST_OBJECT(sink_pad));
4771 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4773 /* adding created elements to bin */
4774 LOGD("adding created elements to bin\n");
4775 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4776 LOGE("failed to add elements\n");
4780 /* linking elements in the bucket by added order. */
4781 LOGD("Linking elements in the bucket by added order.\n");
4782 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4783 LOGE("failed to link elements\n");
4787 /* get first element's sinkpad for creating ghostpad */
4788 first_element = (MMPlayerGstElement *)element_bucket->data;
4789 if (!first_element) {
4790 LOGE("failed to get first elem\n");
4794 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4796 LOGE("failed to get pad from first element of audiobin\n");
4800 ghostpad = gst_ghost_pad_new("sink", pad);
4802 LOGE("failed to create ghostpad\n");
4806 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4807 LOGE("failed to add ghostpad to audiobin\n");
4811 gst_object_unref(pad);
4813 g_list_free(element_bucket);
4816 return MM_ERROR_NONE;
4820 LOGD("ERROR : releasing audiobin\n");
4823 gst_object_unref(GST_OBJECT(pad));
4826 gst_object_unref(GST_OBJECT(ghostpad));
4829 g_list_free(element_bucket);
4831 /* release element which are not added to bin */
4832 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4833 /* NOTE : skip bin */
4834 if (audiobin[i].gst) {
4835 GstObject* parent = NULL;
4836 parent = gst_element_get_parent(audiobin[i].gst);
4839 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4840 audiobin[i].gst = NULL;
4842 gst_object_unref(GST_OBJECT(parent));
4846 /* release audiobin with it's childs */
4847 if (audiobin[MMPLAYER_A_BIN].gst)
4848 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4850 MMPLAYER_FREEIF(audiobin);
4852 player->pipeline->audiobin = NULL;
4854 return MM_ERROR_PLAYER_INTERNAL;
4857 static GstPadProbeReturn
4858 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4860 mm_player_t* player = (mm_player_t*) u_data;
4861 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4862 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4864 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4866 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4867 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4869 return GST_PAD_PROBE_OK;
4872 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4874 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4877 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4879 int ret = MM_ERROR_NONE;
4881 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4882 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4884 MMPLAYER_VIDEO_BO_LOCK(player);
4886 if (player->video_bo_list) {
4887 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4888 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4889 if (tmp && tmp->bo == bo) {
4891 LOGD("release bo %p", bo);
4892 tbm_bo_unref(tmp->bo);
4893 MMPLAYER_VIDEO_BO_UNLOCK(player);
4894 MMPLAYER_VIDEO_BO_SIGNAL(player);
4899 /* hw codec is running or the list was reset for DRC. */
4900 LOGW("there is no bo list.");
4902 MMPLAYER_VIDEO_BO_UNLOCK(player);
4904 LOGW("failed to find bo %p", bo);
4909 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4914 MMPLAYER_RETURN_IF_FAIL(player);
4916 MMPLAYER_VIDEO_BO_LOCK(player);
4917 if (player->video_bo_list) {
4918 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4919 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4920 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4923 tbm_bo_unref(tmp->bo);
4927 g_list_free(player->video_bo_list);
4928 player->video_bo_list = NULL;
4930 player->video_bo_size = 0;
4931 MMPLAYER_VIDEO_BO_UNLOCK(player);
4938 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4941 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4942 gboolean ret = TRUE;
4944 /* check DRC, if it is, destroy the prev bo list to create again */
4945 if (player->video_bo_size != size) {
4946 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4947 __mmplayer_video_stream_destroy_bo_list(player);
4948 player->video_bo_size = size;
4951 MMPLAYER_VIDEO_BO_LOCK(player);
4953 if ((!player->video_bo_list) ||
4954 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4956 /* create bo list */
4958 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4960 if (player->video_bo_list) {
4961 /* if bo list did not created all, try it again. */
4962 idx = g_list_length(player->video_bo_list);
4963 LOGD("bo list exist(len: %d)", idx);
4966 for (; idx < player->ini.num_of_video_bo; idx++) {
4967 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4969 LOGE("Fail to alloc bo_info.");
4972 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4974 LOGE("Fail to tbm_bo_alloc.");
4978 bo_info->using = FALSE;
4979 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4982 /* update video num buffers */
4983 player->video_num_buffers = idx;
4984 if (idx == player->ini.num_of_video_bo)
4985 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4988 MMPLAYER_VIDEO_BO_UNLOCK(player);
4992 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4996 /* get bo from list*/
4997 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4998 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4999 if (tmp && (tmp->using == FALSE)) {
5000 LOGD("found bo %p to use", tmp->bo);
5002 MMPLAYER_VIDEO_BO_UNLOCK(player);
5003 return tbm_bo_ref(tmp->bo);
5007 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
5008 MMPLAYER_VIDEO_BO_UNLOCK(player);
5012 if (player->ini.video_bo_timeout <= 0) {
5013 MMPLAYER_VIDEO_BO_WAIT(player);
5015 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
5016 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5023 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5025 mm_player_t* player = (mm_player_t*)data;
5027 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5029 /* send prerolled pkt */
5030 player->video_stream_prerolled = FALSE;
5032 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5034 /* not to send prerolled pkt again */
5035 player->video_stream_prerolled = TRUE;
5039 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5041 mm_player_t* player = (mm_player_t*)data;
5042 GstCaps *caps = NULL;
5043 MMPlayerVideoStreamDataType *stream = NULL;
5044 MMVideoBuffer *video_buffer = NULL;
5045 GstMemory *dataBlock = NULL;
5046 GstMemory *metaBlock = NULL;
5047 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5048 GstStructure *structure = NULL;
5049 const gchar *string_format = NULL;
5050 unsigned int fourcc = 0;
5053 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5055 if (player->video_stream_prerolled) {
5056 player->video_stream_prerolled = FALSE;
5057 LOGD("skip the prerolled pkt not to send it again");
5061 caps = gst_pad_get_current_caps(pad);
5063 LOGE("Caps is NULL.");
5067 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5069 /* clear stream data structure */
5070 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5072 LOGE("failed to alloc mem for video data");
5076 structure = gst_caps_get_structure(caps, 0);
5077 gst_structure_get_int(structure, "width", &(stream->width));
5078 gst_structure_get_int(structure, "height", &(stream->height));
5079 string_format = gst_structure_get_string(structure, "format");
5081 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5082 stream->format = util_get_pixtype(fourcc);
5083 gst_caps_unref(caps);
5086 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5089 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5090 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5093 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5094 LOGE("Wrong condition!!");
5098 /* set size and timestamp */
5099 dataBlock = gst_buffer_peek_memory(buffer, 0);
5100 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5101 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5103 /* check zero-copy */
5104 if (player->set_mode.video_zc &&
5105 player->set_mode.media_packet_video_stream &&
5106 gst_buffer_n_memory(buffer) > 1) {
5107 metaBlock = gst_buffer_peek_memory(buffer, 1);
5108 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5109 video_buffer = (MMVideoBuffer *)mapinfo.data;
5112 if (video_buffer) { /* hw codec */
5114 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5117 /* copy pointer of tbm bo, stride, elevation */
5118 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5119 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5123 LOGE("Not support video buffer format");
5126 memcpy(stream->stride, video_buffer->stride_width,
5127 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5128 memcpy(stream->elevation, video_buffer->stride_height,
5129 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5131 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5132 stream->internal_buffer = gst_buffer_ref(buffer);
5133 } else { /* sw codec */
5137 int ret = TBM_SURFACE_ERROR_NONE;
5138 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5139 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5141 unsigned char *src = NULL;
5142 unsigned char *dest = NULL;
5143 tbm_bo_handle thandle;
5144 tbm_surface_h surface;
5145 tbm_surface_info_s info;
5148 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5150 LOGE("fail to gst_memory_map");
5155 if (stream->format == MM_PIXEL_FORMAT_I420) {
5156 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5158 ret = tbm_surface_get_info(surface, &info);
5160 if (ret != TBM_SURFACE_ERROR_NONE) {
5161 tbm_surface_destroy(surface);
5164 tbm_surface_destroy(surface);
5166 src_stride[0] = GST_ROUND_UP_4(stream->width);
5167 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5168 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5169 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5170 stream->stride[0] = info.planes[0].stride;
5171 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5172 stream->stride[1] = info.planes[1].stride;
5173 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5174 stream->stride[2] = info.planes[2].stride;
5175 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5176 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5177 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5178 stream->stride[0] = stream->width * 4;
5179 stream->elevation[0] = stream->height;
5180 size = stream->stride[0] * stream->height;
5182 LOGE("Not support format %d", stream->format);
5186 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5187 if (!stream->bo[0]) {
5188 LOGE("Fail to tbm_bo_alloc!!");
5192 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5193 if (thandle.ptr && mapinfo.data) {
5194 if (stream->format == MM_PIXEL_FORMAT_I420) {
5195 for (i = 0; i < 3; i++) {
5196 src = mapinfo.data + src_offset[i];
5197 dest = thandle.ptr + info.planes[i].offset;
5200 for (j = 0; j < stream->height>>k; j++) {
5201 memcpy(dest, src, stream->width>>k);
5202 src += src_stride[i];
5203 dest += stream->stride[i];
5206 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5207 memcpy(thandle.ptr, mapinfo.data, size);
5209 LOGE("Not support format %d", stream->format);
5213 LOGE("data pointer is wrong. dest : %p, src : %p",
5214 thandle.ptr, mapinfo.data);
5217 tbm_bo_unmap(stream->bo[0]);
5220 if (player->video_stream_cb) { /* This has been already checked at the entry */
5221 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5222 LOGE("failed to send video stream data.");
5228 gst_memory_unmap(metaBlock, &mapinfo);
5230 gst_memory_unmap(dataBlock, &mapinfo);
5235 LOGE("release video stream resource.");
5238 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5240 tbm_bo_unref(stream->bo[i]);
5242 gst_memory_unmap(metaBlock, &mapinfo);
5244 /* unref gst buffer */
5245 if (stream->internal_buffer)
5246 gst_buffer_unref(stream->internal_buffer);
5247 } else if (dataBlock) {
5249 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5250 gst_memory_unmap(dataBlock, &mapinfo);
5258 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5260 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5261 GList* element_bucket = NULL;
5263 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5267 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5268 LOGD("do not need to add video filters.");
5269 return MM_ERROR_NONE;
5272 /* in case of sw codec except 360 playback,
5273 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5274 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5275 LOGD("using video converter: %s", video_csc);
5277 /* set video rotator */
5278 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5280 *bucket = element_bucket;
5282 return MM_ERROR_NONE;
5284 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5285 g_list_free(element_bucket);
5289 return MM_ERROR_PLAYER_INTERNAL;
5293 * This function is to create video pipeline.
5295 * @param player [in] handle of player
5296 * caps [in] src caps of decoder
5297 * surface_type [in] surface type for video rendering
5299 * @return This function returns zero on success.
5301 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5305 * - video overlay surface(arm/x86) : tizenwlsink
5308 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5312 GList*element_bucket = NULL;
5313 MMPlayerGstElement* first_element = NULL;
5314 MMPlayerGstElement* videobin = NULL;
5315 gchar *videosink_element = NULL;
5319 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5322 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5324 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5326 player->pipeline->videobin = videobin;
5328 attrs = MMPLAYER_GET_ATTRS(player);
5330 LOGE("cannot get content attribute");
5331 return MM_ERROR_PLAYER_INTERNAL;
5335 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5336 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5337 if (!videobin[MMPLAYER_V_BIN].gst) {
5338 LOGE("failed to create videobin");
5342 int enable_video_decoded_cb = 0;
5343 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5345 if (player->is_360_feature_enabled && player->is_content_spherical) {
5346 LOGD("video360 elem will be added.");
5348 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5349 "video-360", TRUE, player);
5351 /* Set spatial media metadata and/or user settings to the element.
5353 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5354 "projection-type", player->video360_metadata.projection_type, NULL);
5356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5357 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5359 if (player->video360_metadata.full_pano_width_pixels &&
5360 player->video360_metadata.full_pano_height_pixels &&
5361 player->video360_metadata.cropped_area_image_width &&
5362 player->video360_metadata.cropped_area_image_height) {
5363 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5364 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5365 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5366 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5367 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5368 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5369 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5373 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5374 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5375 "horizontal-fov", player->video360_horizontal_fov,
5376 "vertical-fov", player->video360_vertical_fov, NULL);
5379 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5380 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5381 "zoom", 1.0f / player->video360_zoom, NULL);
5384 if (player->video360_yaw_radians <= M_PI &&
5385 player->video360_yaw_radians >= -M_PI &&
5386 player->video360_pitch_radians <= M_PI_2 &&
5387 player->video360_pitch_radians >= -M_PI_2) {
5388 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5389 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5390 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5391 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5392 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5393 "pose-yaw", player->video360_metadata.init_view_heading,
5394 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5397 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5398 "passthrough", !player->is_video360_enabled, NULL);
5401 /* set video sink */
5402 switch (surface_type) {
5403 case MM_DISPLAY_SURFACE_OVERLAY:
5404 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5406 if (strlen(player->ini.videosink_element_overlay) > 0)
5407 videosink_element = player->ini.videosink_element_overlay;
5411 case MM_DISPLAY_SURFACE_NULL:
5412 if (strlen(player->ini.videosink_element_fake) > 0)
5413 videosink_element = player->ini.videosink_element_fake;
5417 case MM_DISPLAY_SURFACE_REMOTE:
5418 if (strlen(player->ini.videosink_element_fake) > 0)
5419 videosink_element = player->ini.videosink_element_fake;
5424 LOGE("unidentified surface type");
5427 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5429 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5431 /* additional setting for sink plug-in */
5432 switch (surface_type) {
5433 case MM_DISPLAY_SURFACE_OVERLAY:
5435 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5437 LOGD("selected videosink name: %s", videosink_element);
5439 /* support shard memory with S/W codec on HawkP */
5440 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5441 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5442 "use-tbm", use_tbm, NULL);
5448 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5451 LOGD("disable last-sample");
5452 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5456 if (player->set_mode.media_packet_video_stream) {
5458 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5460 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5462 MMPLAYER_SIGNAL_CONNECT(player,
5463 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5464 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5466 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5469 MMPLAYER_SIGNAL_CONNECT(player,
5470 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5471 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5473 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5478 case MM_DISPLAY_SURFACE_REMOTE:
5480 if (player->set_mode.media_packet_video_stream) {
5481 LOGE("add data probe at videosink");
5482 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5483 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5485 MMPLAYER_SIGNAL_CONNECT(player,
5486 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5487 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5489 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5492 MMPLAYER_SIGNAL_CONNECT(player,
5493 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5494 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5496 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5501 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5504 LOGD("disable last-sample");
5505 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5515 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5518 if (videobin[MMPLAYER_V_SINK].gst) {
5519 GstPad *sink_pad = NULL;
5520 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5522 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5523 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5524 gst_object_unref(GST_OBJECT(sink_pad));
5526 LOGW("failed to get sink pad from videosink\n");
5529 /* store it as it's sink element */
5530 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5532 /* adding created elements to bin */
5533 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5534 LOGE("failed to add elements\n");
5538 /* Linking elements in the bucket by added order */
5539 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5540 LOGE("failed to link elements\n");
5544 /* get first element's sinkpad for creating ghostpad */
5546 first_element = (MMPlayerGstElement *)element_bucket->data;
5547 if (!first_element) {
5548 LOGE("failed to get first element from bucket\n");
5552 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5554 LOGE("failed to get pad from first element\n");
5558 /* create ghostpad */
5559 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5560 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5561 LOGE("failed to add ghostpad to videobin\n");
5564 gst_object_unref(pad);
5566 /* done. free allocated variables */
5568 g_list_free(element_bucket);
5572 return MM_ERROR_NONE;
5575 LOGE("ERROR : releasing videobin\n");
5577 g_list_free(element_bucket);
5580 gst_object_unref(GST_OBJECT(pad));
5582 /* release videobin with it's childs */
5583 if (videobin[MMPLAYER_V_BIN].gst)
5584 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5587 MMPLAYER_FREEIF(videobin);
5589 player->pipeline->videobin = NULL;
5591 return MM_ERROR_PLAYER_INTERNAL;
5594 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5596 GList *element_bucket = NULL;
5597 MMPlayerGstElement *textbin = player->pipeline->textbin;
5599 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5600 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5601 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5602 "signal-handoffs", FALSE,
5605 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5606 MMPLAYER_SIGNAL_CONNECT(player,
5607 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5608 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5610 G_CALLBACK(__mmplayer_update_subtitle),
5613 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5614 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5615 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5617 if (!player->play_subtitle) {
5618 LOGD("add textbin sink as sink element of whole pipeline.\n");
5619 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5622 /* adding created elements to bin */
5623 LOGD("adding created elements to bin\n");
5624 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5625 LOGE("failed to add elements\n");
5629 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5630 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5631 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5633 /* linking elements in the bucket by added order. */
5634 LOGD("Linking elements in the bucket by added order.\n");
5635 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5636 LOGE("failed to link elements\n");
5640 /* done. free allocated variables */
5641 g_list_free(element_bucket);
5643 if (textbin[MMPLAYER_T_QUEUE].gst) {
5645 GstPad *ghostpad = NULL;
5647 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5649 LOGE("failed to get sink pad of text queue");
5653 ghostpad = gst_ghost_pad_new("text_sink", pad);
5654 gst_object_unref(pad);
5657 LOGE("failed to create ghostpad of textbin\n");
5661 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5662 LOGE("failed to add ghostpad to textbin\n");
5663 gst_object_unref(ghostpad);
5668 return MM_ERROR_NONE;
5671 g_list_free(element_bucket);
5673 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5674 LOGE("remove textbin sink from sink list");
5675 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5678 /* release element at __mmplayer_gst_create_text_sink_bin */
5679 return MM_ERROR_PLAYER_INTERNAL;
5682 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5684 MMPlayerGstElement *textbin = NULL;
5685 GList *element_bucket = NULL;
5686 int surface_type = 0;
5691 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5694 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5696 LOGE("failed to allocate memory for textbin\n");
5697 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5701 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5702 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5703 if (!textbin[MMPLAYER_T_BIN].gst) {
5704 LOGE("failed to create textbin\n");
5709 player->pipeline->textbin = textbin;
5712 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5713 LOGD("surface type for subtitle : %d", surface_type);
5714 switch (surface_type) {
5715 case MM_DISPLAY_SURFACE_OVERLAY:
5716 case MM_DISPLAY_SURFACE_NULL:
5717 case MM_DISPLAY_SURFACE_REMOTE:
5718 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5719 LOGE("failed to make plain text elements\n");
5730 return MM_ERROR_NONE;
5734 LOGD("ERROR : releasing textbin\n");
5736 g_list_free(element_bucket);
5738 /* release signal */
5739 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5741 /* release element which are not added to bin */
5742 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5743 /* NOTE : skip bin */
5744 if (textbin[i].gst) {
5745 GstObject* parent = NULL;
5746 parent = gst_element_get_parent(textbin[i].gst);
5749 gst_object_unref(GST_OBJECT(textbin[i].gst));
5750 textbin[i].gst = NULL;
5752 gst_object_unref(GST_OBJECT(parent));
5757 /* release textbin with it's childs */
5758 if (textbin[MMPLAYER_T_BIN].gst)
5759 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5761 MMPLAYER_FREEIF(player->pipeline->textbin);
5762 player->pipeline->textbin = NULL;
5765 return MM_ERROR_PLAYER_INTERNAL;
5770 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5772 MMPlayerGstElement* mainbin = NULL;
5773 MMPlayerGstElement* textbin = NULL;
5774 MMHandleType attrs = 0;
5775 GstElement *subsrc = NULL;
5776 GstElement *subparse = NULL;
5777 gchar *subtitle_uri = NULL;
5778 const gchar *charset = NULL;
5784 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5786 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5788 mainbin = player->pipeline->mainbin;
5790 attrs = MMPLAYER_GET_ATTRS(player);
5792 LOGE("cannot get content attribute\n");
5793 return MM_ERROR_PLAYER_INTERNAL;
5796 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5797 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5798 LOGE("subtitle uri is not proper filepath.\n");
5799 return MM_ERROR_PLAYER_INVALID_URI;
5802 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5803 LOGE("failed to get storage info of subtitle path");
5804 return MM_ERROR_PLAYER_INVALID_URI;
5807 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5809 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5810 player->subtitle_language_list = NULL;
5811 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5813 /* create the subtitle source */
5814 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5816 LOGE("failed to create filesrc element\n");
5819 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5821 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5822 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5824 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5825 LOGW("failed to add queue\n");
5826 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5827 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5828 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5833 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5835 LOGE("failed to create subparse element\n");
5839 charset = util_get_charset(subtitle_uri);
5841 LOGD("detected charset is %s\n", charset);
5842 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5845 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5846 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5848 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5849 LOGW("failed to add subparse\n");
5850 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5851 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5852 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5856 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5857 LOGW("failed to link subsrc and subparse\n");
5861 player->play_subtitle = TRUE;
5862 player->adjust_subtitle_pos = 0;
5864 LOGD("play subtitle using subtitle file\n");
5866 if (player->pipeline->textbin == NULL) {
5867 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5868 LOGE("failed to create text sink bin. continuing without text\n");
5872 textbin = player->pipeline->textbin;
5874 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5875 LOGW("failed to add textbin\n");
5877 /* release signal */
5878 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5880 /* release textbin with it's childs */
5881 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5882 MMPLAYER_FREEIF(player->pipeline->textbin);
5883 player->pipeline->textbin = textbin = NULL;
5887 LOGD("link text input selector and textbin ghost pad");
5889 player->textsink_linked = 1;
5890 player->external_text_idx = 0;
5891 LOGI("player->textsink_linked set to 1\n");
5893 textbin = player->pipeline->textbin;
5894 LOGD("text bin has been created. reuse it.");
5895 player->external_text_idx = 1;
5898 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5899 LOGW("failed to link subparse and textbin\n");
5903 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5905 LOGE("failed to get sink pad from textsink to probe data");
5909 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5910 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5912 gst_object_unref(pad);
5915 /* create dot. for debugging */
5916 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5919 return MM_ERROR_NONE;
5922 /* release text pipeline resource */
5923 player->textsink_linked = 0;
5925 /* release signal */
5926 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5928 if (player->pipeline->textbin) {
5929 LOGE("remove textbin");
5931 /* release textbin with it's childs */
5932 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5933 MMPLAYER_FREEIF(player->pipeline->textbin);
5934 player->pipeline->textbin = NULL;
5938 /* release subtitle elem */
5939 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5940 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5942 return MM_ERROR_PLAYER_INTERNAL;
5946 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5948 mm_player_t* player = (mm_player_t*) data;
5949 MMMessageParamType msg = {0, };
5950 GstClockTime duration = 0;
5951 gpointer text = NULL;
5952 guint text_size = 0;
5953 gboolean ret = TRUE;
5954 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5958 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5959 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5961 if (player->is_subtitle_force_drop) {
5962 LOGW("subtitle is dropped forcedly.");
5966 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5967 text = mapinfo.data;
5968 text_size = mapinfo.size;
5969 duration = GST_BUFFER_DURATION(buffer);
5971 if (player->set_mode.subtitle_off) {
5972 LOGD("subtitle is OFF.\n");
5976 if (!text || (text_size == 0)) {
5977 LOGD("There is no subtitle to be displayed.\n");
5981 msg.data = (void *) text;
5982 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5984 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5986 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5987 gst_buffer_unmap(buffer, &mapinfo);
5994 static GstPadProbeReturn
5995 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5997 mm_player_t *player = (mm_player_t *) u_data;
5998 GstClockTime cur_timestamp = 0;
5999 gint64 adjusted_timestamp = 0;
6000 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
6002 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6004 if (player->set_mode.subtitle_off) {
6005 LOGD("subtitle is OFF.\n");
6009 if (player->adjust_subtitle_pos == 0) {
6010 LOGD("nothing to do");
6014 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
6015 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
6017 if (adjusted_timestamp < 0) {
6018 LOGD("adjusted_timestamp under zero");
6023 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6024 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6025 GST_TIME_ARGS(cur_timestamp),
6026 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6028 return GST_PAD_PROBE_OK;
6030 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6034 /* check player and subtitlebin are created */
6035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6036 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6038 if (position == 0) {
6039 LOGD("nothing to do\n");
6041 return MM_ERROR_NONE;
6045 case MM_PLAYER_POS_FORMAT_TIME:
6047 /* check current postion */
6048 player->adjust_subtitle_pos = position;
6050 LOGD("save adjust_subtitle_pos in player") ;
6056 LOGW("invalid format.\n");
6058 return MM_ERROR_INVALID_ARGUMENT;
6064 return MM_ERROR_NONE;
6068 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6070 GstElement *appsrc = element;
6071 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6072 GstBuffer *buffer = NULL;
6073 GstFlowReturn ret = GST_FLOW_OK;
6076 MMPLAYER_RETURN_IF_FAIL(element);
6077 MMPLAYER_RETURN_IF_FAIL(buf);
6079 buffer = gst_buffer_new();
6081 if (buf->offset >= buf->len) {
6082 LOGD("call eos appsrc\n");
6083 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6087 if (buf->len - buf->offset < size)
6088 len = buf->len - buf->offset;
6090 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6091 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6092 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6094 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6095 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6101 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6103 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6105 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6107 buf->offset = (int)size;
6112 static GstBusSyncReply
6113 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6115 mm_player_t *player = (mm_player_t *)data;
6116 GstBusSyncReply reply = GST_BUS_DROP;
6118 if (!(player->pipeline && player->pipeline->mainbin)) {
6119 LOGE("player pipeline handle is null");
6120 return GST_BUS_PASS;
6123 if (!__mmplayer_check_useful_message(player, message)) {
6124 gst_message_unref(message);
6125 return GST_BUS_DROP;
6128 switch (GST_MESSAGE_TYPE(message)) {
6129 case GST_MESSAGE_STATE_CHANGED:
6130 /* post directly for fast launch */
6131 if (player->sync_handler) {
6132 __mmplayer_gst_callback(message, player);
6133 reply = GST_BUS_DROP;
6135 reply = GST_BUS_PASS;
6137 case GST_MESSAGE_TAG:
6138 __mmplayer_gst_extract_tag_from_msg(player, message);
6142 GstTagList *tags = NULL;
6144 gst_message_parse_tag(message, &tags);
6146 LOGE("TAGS received from element \"%s\".\n",
6147 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6149 gst_tag_list_foreach(tags, print_tag, NULL);
6150 gst_tag_list_free(tags);
6158 case GST_MESSAGE_DURATION_CHANGED:
6159 __mmplayer_gst_handle_duration(player, message);
6161 case GST_MESSAGE_ASYNC_DONE:
6162 /* NOTE:Don't call gst_callback directly
6163 * because previous frame can be showed even though this message is received for seek.
6166 reply = GST_BUS_PASS;
6170 if (reply == GST_BUS_DROP)
6171 gst_message_unref(message);
6177 __mmplayer_gst_create_decoder(mm_player_t *player,
6178 MMPlayerTrackType track,
6180 enum MainElementID elemId,
6183 gboolean ret = TRUE;
6184 GstPad *sinkpad = NULL;
6188 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6190 player->pipeline->mainbin, FALSE);
6191 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6192 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6193 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6195 GstElement *decodebin = NULL;
6196 GstCaps *dec_caps = NULL;
6198 /* create decodebin */
6199 decodebin = gst_element_factory_make("decodebin", name);
6202 LOGE("error : fail to create decodebin for %d decoder\n", track);
6207 /* raw pad handling signal */
6208 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6209 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6211 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6212 before looking for any elements that can handle that stream.*/
6213 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6214 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6216 /* This signal is emitted when a element is added to the bin.*/
6217 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6218 G_CALLBACK(__mmplayer_gst_element_added), player);
6220 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6221 LOGE("failed to add new decodebin\n");
6226 dec_caps = gst_pad_query_caps(srcpad, NULL);
6228 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6229 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6230 gst_caps_unref(dec_caps);
6233 player->pipeline->mainbin[elemId].id = elemId;
6234 player->pipeline->mainbin[elemId].gst = decodebin;
6236 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6238 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6239 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6240 gst_object_unref(GST_OBJECT(decodebin));
6243 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6244 LOGE("failed to sync second level decodebin state with parent\n");
6246 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6250 gst_object_unref(GST_OBJECT(sinkpad));
6259 * This function is to create audio or video pipeline for playing.
6261 * @param player [in] handle of player
6263 * @return This function returns zero on success.
6268 __mmplayer_gst_create_pipeline(mm_player_t* player)
6271 MMPlayerGstElement *mainbin = NULL;
6272 MMHandleType attrs = 0;
6273 GstElement* element = NULL;
6274 GstElement* elem_src_audio = NULL;
6275 GstElement* elem_src_subtitle = NULL;
6276 GstElement* es_video_queue = NULL;
6277 GstElement* es_audio_queue = NULL;
6278 GstElement* es_subtitle_queue = NULL;
6279 GList* element_bucket = NULL;
6280 gboolean need_state_holder = TRUE;
6282 #ifdef SW_CODEC_ONLY
6283 int surface_type = 0;
6287 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6289 /* get profile attribute */
6290 attrs = MMPLAYER_GET_ATTRS(player);
6292 LOGE("cannot get content attribute\n");
6296 /* create pipeline handles */
6297 if (player->pipeline) {
6298 LOGW("pipeline should be released before create new one\n");
6302 player->video360_metadata.is_spherical = -1;
6303 player->is_openal_plugin_used = FALSE;
6305 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6306 if (player->pipeline == NULL)
6309 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6311 /* create mainbin */
6312 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6313 if (mainbin == NULL)
6316 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6318 /* create pipeline */
6319 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6320 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6321 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6322 LOGE("failed to create pipeline\n");
6325 player->demux_pad_index = 0;
6326 player->subtitle_language_list = NULL;
6328 player->is_subtitle_force_drop = FALSE;
6329 player->last_multiwin_status = FALSE;
6331 _mmplayer_track_initialize(player);
6332 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6334 /* create source element */
6335 switch (player->profile.uri_type) {
6336 /* rtsp streamming */
6337 case MM_PLAYER_URI_TYPE_URL_RTSP:
6341 element = gst_element_factory_make("rtspsrc", "rtsp source");
6344 LOGE("failed to create streaming source element\n");
6352 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6354 SECURE_LOGD("user_agent : %s\n", user_agent);
6356 /* setting property to streaming source */
6357 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6359 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6361 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6362 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6363 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6364 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6369 case MM_PLAYER_URI_TYPE_URL_HTTP:
6371 gchar *user_agent, *cookies, **cookie_list;
6372 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6373 user_agent = cookies = NULL;
6375 gint mode = MM_PLAYER_PD_MODE_NONE;
6377 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6379 player->pd_mode = mode;
6381 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6383 if (!MMPLAYER_IS_HTTP_PD(player)) {
6384 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6386 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6389 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6392 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6393 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6395 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6396 LOGD("get timeout from ini\n");
6397 http_timeout = player->ini.http_timeout;
6401 SECURE_LOGD("location : %s\n", player->profile.uri);
6402 SECURE_LOGD("cookies : %s\n", cookies);
6403 SECURE_LOGD("user_agent : %s\n", user_agent);
6404 LOGD("timeout : %d\n", http_timeout);
6406 /* setting property to streaming source */
6407 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6408 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6409 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6411 /* parsing cookies */
6412 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6413 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6414 g_strfreev(cookie_list);
6417 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6419 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6420 LOGW("it's dash. and it's still experimental feature.");
6422 // progressive download
6423 gchar* location = NULL;
6425 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6428 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6430 MMPLAYER_FREEIF(player->pd_file_save_path);
6432 LOGD("PD Location : %s\n", path);
6435 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6436 LOGE("failed to get storage info");
6439 player->pd_file_save_path = g_strdup(path);
6441 LOGE("can't find pd location so, it should be set \n");
6446 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6448 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6452 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6453 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6455 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6456 g_object_get(element, "location", &location, NULL);
6457 LOGD("PD_LOCATION [%s].\n", location);
6465 case MM_PLAYER_URI_TYPE_FILE:
6467 LOGD("using filesrc for 'file://' handler.\n");
6468 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6469 LOGE("failed to get storage info");
6473 element = gst_element_factory_make("filesrc", "source");
6475 LOGE("failed to create filesrc\n");
6479 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6483 case MM_PLAYER_URI_TYPE_SS:
6485 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6486 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6488 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6492 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6493 LOGD("get timeout from ini\n");
6494 http_timeout = player->ini.http_timeout;
6497 /* setting property to streaming source */
6498 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6499 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6502 case MM_PLAYER_URI_TYPE_MS_BUFF:
6504 LOGD("MS buff src is selected\n");
6506 if (player->v_stream_caps) {
6507 element = gst_element_factory_make("appsrc", "video_appsrc");
6509 LOGF("failed to create video app source element[appsrc].\n");
6513 if (player->a_stream_caps) {
6514 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6515 if (!elem_src_audio) {
6516 LOGF("failed to create audio app source element[appsrc].\n");
6520 } else if (player->a_stream_caps) {
6521 /* no video, only audio pipeline*/
6522 element = gst_element_factory_make("appsrc", "audio_appsrc");
6524 LOGF("failed to create audio app source element[appsrc].\n");
6529 if (player->s_stream_caps) {
6530 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6531 if (!elem_src_subtitle) {
6532 LOGF("failed to create subtitle app source element[appsrc].\n");
6537 LOGD("setting app sources properties.\n");
6538 LOGD("location : %s\n", player->profile.uri);
6540 if (player->v_stream_caps && element) {
6541 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6542 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6543 "caps", player->v_stream_caps, NULL);
6545 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6546 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6547 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6548 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6550 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6551 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6552 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6553 G_CALLBACK(__gst_seek_video_data), player);
6555 if (player->a_stream_caps && elem_src_audio) {
6556 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6557 "caps", player->a_stream_caps, NULL);
6559 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6560 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6561 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6562 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6564 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6565 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6566 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6567 G_CALLBACK(__gst_seek_audio_data), player);
6569 } else if (player->a_stream_caps && element) {
6570 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6571 "caps", player->a_stream_caps, NULL);
6573 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6574 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6575 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6576 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6578 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6579 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6580 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6581 G_CALLBACK(__gst_seek_audio_data), player);
6584 if (player->s_stream_caps && elem_src_subtitle) {
6585 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6586 "caps", player->s_stream_caps, NULL);
6588 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6589 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6590 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6591 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6593 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6595 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6596 G_CALLBACK(__gst_seek_subtitle_data), player);
6599 if (player->v_stream_caps && element) {
6600 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6601 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6602 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6603 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6605 if (player->a_stream_caps && elem_src_audio) {
6606 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6607 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6608 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6609 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6611 } else if (player->a_stream_caps && element) {
6612 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6613 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6614 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6615 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6618 if (player->s_stream_caps && elem_src_subtitle)
6619 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6620 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6622 need_state_holder = FALSE;
6624 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6625 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6626 LOGE("failed to commit\n");
6630 case MM_PLAYER_URI_TYPE_MEM:
6632 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6634 LOGD("mem src is selected\n");
6636 element = gst_element_factory_make("appsrc", "mem-source");
6638 LOGE("failed to create appsrc element\n");
6642 g_object_set(element, "stream-type", stream_type, NULL);
6643 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6644 g_object_set(element, "blocksize", (guint64)20480, NULL);
6646 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6647 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6648 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6649 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6652 case MM_PLAYER_URI_TYPE_URL:
6655 case MM_PLAYER_URI_TYPE_TEMP:
6658 case MM_PLAYER_URI_TYPE_NONE:
6663 /* check source element is OK */
6665 LOGE("no source element was created.\n");
6669 /* take source element */
6670 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6671 mainbin[MMPLAYER_M_SRC].gst = element;
6672 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6674 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6675 player->streamer = __mm_player_streaming_create();
6676 __mm_player_streaming_initialize(player->streamer);
6679 if (MMPLAYER_IS_HTTP_PD(player)) {
6680 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6682 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6683 element = gst_element_factory_make("queue2", "queue2");
6685 LOGE("failed to create http streaming buffer element\n");
6690 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6691 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6692 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6694 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6696 player->streamer->is_pd_mode = TRUE;
6698 __mm_player_streaming_set_queue2(player->streamer,
6701 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6704 player->ini.http_buffering_limit,
6705 MUXED_BUFFER_TYPE_MEM_QUEUE,
6709 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6710 if (player->v_stream_caps) {
6711 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6712 if (!es_video_queue) {
6713 LOGE("create es_video_queue for es player failed\n");
6716 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6717 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6718 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6719 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6721 /* Adding audio appsrc to bucket */
6722 if (player->a_stream_caps && elem_src_audio) {
6723 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6724 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6725 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6727 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6728 if (!es_audio_queue) {
6729 LOGE("create es_audio_queue for es player failed\n");
6732 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6734 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6735 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6736 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6738 } else if (player->a_stream_caps) {
6739 /* Only audio stream, no video */
6740 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6741 if (!es_audio_queue) {
6742 LOGE("create es_audio_queue for es player failed\n");
6745 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6746 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6747 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6750 if (player->s_stream_caps && elem_src_subtitle) {
6751 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6752 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6753 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6755 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6756 if (!es_subtitle_queue) {
6757 LOGE("create es_subtitle_queue for es player failed\n");
6760 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6761 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6762 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6766 /* create autoplugging element if src element is not a rtsp src */
6767 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6768 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6770 enum MainElementID elemId = MMPLAYER_M_NUM;
6772 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6773 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6774 elemId = MMPLAYER_M_AUTOPLUG;
6775 element = __mmplayer_create_decodebin(player);
6777 /* default size of mq in decodebin is 2M
6778 * but it can cause blocking issue during seeking depends on content. */
6779 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6781 need_state_holder = FALSE;
6783 elemId = MMPLAYER_M_TYPEFIND;
6784 element = gst_element_factory_make("typefind", "typefinder");
6785 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6786 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6789 /* check autoplug element is OK */
6791 LOGE("can not create element(%d)\n", elemId);
6795 mainbin[elemId].id = elemId;
6796 mainbin[elemId].gst = element;
6798 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6801 /* add elements to pipeline */
6802 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6803 LOGE("Failed to add elements to pipeline\n");
6808 /* linking elements in the bucket by added order. */
6809 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6810 LOGE("Failed to link some elements\n");
6815 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6816 if (need_state_holder) {
6818 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6819 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6821 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6822 LOGE("fakesink element could not be created\n");
6825 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6827 /* take ownership of fakesink. we are reusing it */
6828 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6831 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6832 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6833 LOGE("failed to add fakesink to bin\n");
6838 /* now we have completed mainbin. take it */
6839 player->pipeline->mainbin = mainbin;
6841 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6842 GstPad *srcpad = NULL;
6844 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6845 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6847 __mmplayer_gst_create_decoder(player,
6848 MM_PLAYER_TRACK_TYPE_VIDEO,
6850 MMPLAYER_M_AUTOPLUG_V_DEC,
6853 gst_object_unref(GST_OBJECT(srcpad));
6858 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6859 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6861 __mmplayer_gst_create_decoder(player,
6862 MM_PLAYER_TRACK_TYPE_AUDIO,
6864 MMPLAYER_M_AUTOPLUG_A_DEC,
6867 gst_object_unref(GST_OBJECT(srcpad));
6872 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6873 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6876 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6877 if (__mmplayer_check_subtitle(player)) {
6878 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6879 LOGE("fail to create text pipeline");
6882 /* connect bus callback */
6883 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6885 LOGE("cannot get bus from pipeline.\n");
6889 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6891 player->context.thread_default = g_main_context_get_thread_default();
6893 if (player->context.thread_default == NULL) {
6894 player->context.thread_default = g_main_context_default();
6895 LOGD("thread-default context is the global default context");
6897 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6899 /* set sync handler to get tag synchronously */
6900 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6903 gst_object_unref(GST_OBJECT(bus));
6904 g_list_free(element_bucket);
6906 /* create gst bus_msb_cb thread */
6907 g_mutex_init(&player->bus_msg_thread_mutex);
6908 g_cond_init(&player->bus_msg_thread_cond);
6909 player->bus_msg_thread_exit = FALSE;
6910 player->bus_msg_thread =
6911 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6912 if (!player->bus_msg_thread) {
6913 LOGE("failed to create gst BUS msg thread");
6914 g_mutex_clear(&player->bus_msg_thread_mutex);
6915 g_cond_clear(&player->bus_msg_thread_cond);
6921 return MM_ERROR_NONE;
6924 __mmplayer_gst_destroy_pipeline(player);
6925 g_list_free(element_bucket);
6928 /* release element which are not added to bin */
6929 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6930 /* NOTE : skip pipeline */
6931 if (mainbin[i].gst) {
6932 GstObject* parent = NULL;
6933 parent = gst_element_get_parent(mainbin[i].gst);
6936 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6937 mainbin[i].gst = NULL;
6939 gst_object_unref(GST_OBJECT(parent));
6943 /* release pipeline with it's childs */
6944 if (mainbin[MMPLAYER_M_PIPE].gst)
6945 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6947 MMPLAYER_FREEIF(mainbin);
6950 MMPLAYER_FREEIF(player->pipeline);
6951 return MM_ERROR_PLAYER_INTERNAL;
6955 __mmplayer_reset_gapless_state(mm_player_t* player)
6958 MMPLAYER_RETURN_IF_FAIL(player
6960 && player->pipeline->audiobin
6961 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6963 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6970 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6973 int ret = MM_ERROR_NONE;
6977 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6979 /* cleanup stuffs */
6980 MMPLAYER_FREEIF(player->type);
6981 player->have_dynamic_pad = FALSE;
6982 player->no_more_pad = FALSE;
6983 player->num_dynamic_pad = 0;
6984 player->demux_pad_index = 0;
6985 player->use_deinterleave = FALSE;
6986 player->max_audio_channels = 0;
6987 player->video_share_api_delta = 0;
6988 player->video_share_clock_delta = 0;
6989 player->video_hub_download_mode = 0;
6991 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6992 player->subtitle_language_list = NULL;
6993 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6995 __mmplayer_reset_gapless_state(player);
6997 if (player->streamer) {
6998 __mm_player_streaming_deinitialize(player->streamer);
6999 __mm_player_streaming_destroy(player->streamer);
7000 player->streamer = NULL;
7003 /* cleanup unlinked mime type */
7004 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7005 MMPLAYER_FREEIF(player->unlinked_video_mime);
7006 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7008 /* cleanup running stuffs */
7009 __mmplayer_cancel_eos_timer(player);
7011 /* cleanup gst stuffs */
7012 if (player->pipeline) {
7013 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7014 GstTagList* tag_list = player->pipeline->tag_list;
7016 /* first we need to disconnect all signal hander */
7017 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7020 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7021 MMPlayerGstElement* videobin = player->pipeline->videobin;
7022 MMPlayerGstElement* textbin = player->pipeline->textbin;
7023 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7024 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7025 gst_object_unref(bus);
7027 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7028 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7029 if (ret != MM_ERROR_NONE) {
7030 LOGE("fail to change state to NULL\n");
7031 return MM_ERROR_PLAYER_INTERNAL;
7034 LOGW("succeeded in chaning state to NULL\n");
7036 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7039 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7040 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7042 /* free avsysaudiosink
7043 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7044 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7046 MMPLAYER_FREEIF(audiobin);
7047 MMPLAYER_FREEIF(videobin);
7048 MMPLAYER_FREEIF(textbin);
7049 MMPLAYER_FREEIF(mainbin);
7053 gst_tag_list_free(tag_list);
7055 MMPLAYER_FREEIF(player->pipeline);
7057 MMPLAYER_FREEIF(player->album_art);
7059 if (player->v_stream_caps) {
7060 gst_caps_unref(player->v_stream_caps);
7061 player->v_stream_caps = NULL;
7063 if (player->a_stream_caps) {
7064 gst_caps_unref(player->a_stream_caps);
7065 player->a_stream_caps = NULL;
7068 if (player->s_stream_caps) {
7069 gst_caps_unref(player->s_stream_caps);
7070 player->s_stream_caps = NULL;
7072 _mmplayer_track_destroy(player);
7074 if (player->sink_elements)
7075 g_list_free(player->sink_elements);
7076 player->sink_elements = NULL;
7078 if (player->bufmgr) {
7079 tbm_bufmgr_deinit(player->bufmgr);
7080 player->bufmgr = NULL;
7083 LOGW("finished destroy pipeline\n");
7090 static int __gst_realize(mm_player_t* player)
7093 int ret = MM_ERROR_NONE;
7097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7099 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7101 ret = __mmplayer_gst_create_pipeline(player);
7103 LOGE("failed to create pipeline\n");
7107 /* set pipeline state to READY */
7108 /* NOTE : state change to READY must be performed sync. */
7109 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7110 ret = __mmplayer_gst_set_state(player,
7111 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7113 if (ret != MM_ERROR_NONE) {
7114 /* return error if failed to set state */
7115 LOGE("failed to set READY state");
7119 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7121 /* create dot before error-return. for debugging */
7122 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7129 static int __gst_unrealize(mm_player_t* player)
7131 int ret = MM_ERROR_NONE;
7135 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7137 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7138 MMPLAYER_PRINT_STATE(player);
7140 /* release miscellaneous information */
7141 __mmplayer_release_misc(player);
7143 /* destroy pipeline */
7144 ret = __mmplayer_gst_destroy_pipeline(player);
7145 if (ret != MM_ERROR_NONE) {
7146 LOGE("failed to destory pipeline\n");
7150 /* release miscellaneous information.
7151 these info needs to be released after pipeline is destroyed. */
7152 __mmplayer_release_misc_post(player);
7154 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7161 static int __gst_pending_seek(mm_player_t* player)
7163 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7164 int ret = MM_ERROR_NONE;
7168 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7170 if (!player->pending_seek.is_pending) {
7171 LOGD("pending seek is not reserved. nothing to do.\n");
7175 /* check player state if player could pending seek or not. */
7176 current_state = MMPLAYER_CURRENT_STATE(player);
7178 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7179 LOGW("try to pending seek in %s state, try next time. \n",
7180 MMPLAYER_STATE_GET_NAME(current_state));
7184 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7186 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7188 if (MM_ERROR_NONE != ret)
7189 LOGE("failed to seek pending postion. just keep staying current position.\n");
7191 player->pending_seek.is_pending = FALSE;
7198 static int __gst_start(mm_player_t* player)
7200 gboolean sound_extraction = 0;
7201 int ret = MM_ERROR_NONE;
7202 gboolean async = FALSE;
7206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7208 /* get sound_extraction property */
7209 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7211 /* NOTE : if SetPosition was called before Start. do it now */
7212 /* streaming doesn't support it. so it should be always sync */
7213 /* !!create one more api to check if there is pending seek rather than checking variables */
7214 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7215 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7216 ret = __gst_pause(player, FALSE);
7217 if (ret != MM_ERROR_NONE) {
7218 LOGE("failed to set state to PAUSED for pending seek\n");
7222 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7224 if (sound_extraction) {
7225 LOGD("setting pcm extraction\n");
7227 ret = __mmplayer_set_pcm_extraction(player);
7228 if (MM_ERROR_NONE != ret) {
7229 LOGW("failed to set pcm extraction\n");
7233 if (MM_ERROR_NONE != __gst_pending_seek(player))
7234 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7238 LOGD("current state before doing transition");
7239 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7240 MMPLAYER_PRINT_STATE(player);
7242 /* set pipeline state to PLAYING */
7243 if (player->es_player_push_mode)
7245 /* set pipeline state to PLAYING */
7246 ret = __mmplayer_gst_set_state(player,
7247 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7249 if (ret == MM_ERROR_NONE) {
7250 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7252 LOGE("failed to set state to PLAYING");
7256 /* generating debug info before returning error */
7257 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7264 static int __gst_stop(mm_player_t* player)
7266 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7267 MMHandleType attrs = 0;
7268 gboolean rewind = FALSE;
7270 int ret = MM_ERROR_NONE;
7271 gboolean async = FALSE;
7275 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7276 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7278 LOGD("current state before doing transition");
7279 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7280 MMPLAYER_PRINT_STATE(player);
7282 attrs = MMPLAYER_GET_ATTRS(player);
7284 LOGE("cannot get content attribute\n");
7285 return MM_ERROR_PLAYER_INTERNAL;
7288 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7289 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7291 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7292 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7295 if (player->es_player_push_mode)
7298 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7300 /* return if set_state has failed */
7301 if (ret != MM_ERROR_NONE) {
7302 LOGE("failed to set state.\n");
7308 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7309 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7310 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7311 LOGW("failed to rewind\n");
7312 ret = MM_ERROR_PLAYER_SEEK;
7317 player->sent_bos = FALSE;
7319 if (player->es_player_push_mode) //for cloudgame
7322 /* wait for seek to complete */
7323 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7324 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7325 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7327 LOGE("fail to stop player.\n");
7328 ret = MM_ERROR_PLAYER_INTERNAL;
7329 __mmplayer_dump_pipeline_state(player);
7332 /* generate dot file if enabled */
7333 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7340 int __gst_pause(mm_player_t* player, gboolean async)
7342 int ret = MM_ERROR_NONE;
7346 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7347 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7349 LOGD("current state before doing transition");
7350 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7351 MMPLAYER_PRINT_STATE(player);
7353 /* set pipeline status to PAUSED */
7354 ret = __mmplayer_gst_set_state(player,
7355 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7357 if (FALSE == async) {
7358 if (ret != MM_ERROR_NONE) {
7359 GstMessage *msg = NULL;
7360 GTimer *timer = NULL;
7361 gdouble MAX_TIMEOUT_SEC = 3;
7363 LOGE("failed to set state to PAUSED");
7365 if (player->msg_posted) {
7366 LOGE("error msg is already posted.");
7370 timer = g_timer_new();
7371 g_timer_start(timer);
7373 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7376 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7378 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7379 GError *error = NULL;
7381 /* parse error code */
7382 gst_message_parse_error(msg, &error, NULL);
7384 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7385 /* Note : the streaming error from the streaming source is handled
7386 * using __mmplayer_handle_streaming_error.
7388 __mmplayer_handle_streaming_error(player, msg);
7391 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7393 if (error->domain == GST_STREAM_ERROR)
7394 ret = __gst_handle_stream_error(player, error, msg);
7395 else if (error->domain == GST_RESOURCE_ERROR)
7396 ret = __gst_handle_resource_error(player, error->code, NULL);
7397 else if (error->domain == GST_LIBRARY_ERROR)
7398 ret = __gst_handle_library_error(player, error->code);
7399 else if (error->domain == GST_CORE_ERROR)
7400 ret = __gst_handle_core_error(player, error->code);
7402 g_error_free(error);
7404 player->msg_posted = TRUE;
7406 gst_message_unref(msg);
7408 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7410 gst_object_unref(bus);
7411 g_timer_stop(timer);
7412 g_timer_destroy(timer);
7416 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7417 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7419 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7421 } else if (ret == MM_ERROR_NONE) {
7423 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7427 /* generate dot file before returning error */
7428 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7435 int __gst_resume(mm_player_t* player, gboolean async)
7437 int ret = MM_ERROR_NONE;
7442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7443 MM_ERROR_PLAYER_NOT_INITIALIZED);
7445 LOGD("current state before doing transition");
7446 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7447 MMPLAYER_PRINT_STATE(player);
7449 /* generate dot file before returning error */
7450 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7453 LOGD("do async state transition to PLAYING.\n");
7455 /* set pipeline state to PLAYING */
7456 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7458 ret = __mmplayer_gst_set_state(player,
7459 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7460 if (ret != MM_ERROR_NONE) {
7461 LOGE("failed to set state to PLAYING\n");
7464 if (async == FALSE) {
7465 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7466 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7467 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7471 /* generate dot file before returning error */
7472 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7480 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7482 gint64 dur_nsec = 0;
7483 gint64 pos_nsec = 0;
7484 gboolean ret = TRUE;
7485 gboolean accurated = FALSE;
7486 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7489 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7490 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7492 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7493 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7496 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7497 /* check duration */
7498 /* NOTE : duration cannot be zero except live streaming.
7499 * Since some element could have some timing problemn with quering duration, try again.
7501 if (player->duration == 0) {
7502 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7503 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7504 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7505 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7506 player->pending_seek.is_pending = TRUE;
7507 player->pending_seek.format = format;
7508 player->pending_seek.pos = position;
7509 player->seek_state = MMPLAYER_SEEK_NONE;
7510 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7511 return MM_ERROR_NONE;
7516 player->duration = dur_nsec;
7519 LOGD("playback rate: %f\n", player->playback_rate);
7521 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7523 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7525 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7529 case MM_PLAYER_POS_FORMAT_TIME:
7531 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7532 GstQuery *query = NULL;
7533 gboolean seekable = FALSE;
7535 /* check position is valid or not */
7536 if (position > player->duration)
7539 query = gst_query_new_seeking(GST_FORMAT_TIME);
7540 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7541 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7542 gst_query_unref(query);
7545 LOGW("non-seekable content");
7546 player->seek_state = MMPLAYER_SEEK_NONE;
7547 return MM_ERROR_PLAYER_NO_OP;
7550 LOGW("failed to get seeking query");
7551 gst_query_unref(query); /* keep seeking operation */
7554 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7556 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7557 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7558 This causes problem is position calculation during normal pause resume scenarios also.
7559 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7560 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7561 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7562 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7563 LOGW("getting current position failed in seek\n");
7565 player->last_position = pos_nsec;
7566 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7569 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7570 LOGD("not completed seek");
7571 return MM_ERROR_PLAYER_DOING_SEEK;
7575 if (!internal_called)
7576 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7578 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7579 gint64 cur_time = 0;
7581 /* get current position */
7582 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7585 GstEvent *event = gst_event_new_seek(1.0,
7587 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7588 GST_SEEK_TYPE_SET, cur_time,
7589 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7591 __gst_send_event_to_sink(player, event);
7593 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7594 __gst_pause(player, FALSE);
7597 pos_nsec = position;
7599 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7600 that's why set position through property. */
7601 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7602 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7603 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7604 (!player->videodec_linked) && (!player->audiodec_linked)) {
7606 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7607 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7608 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7609 player->seek_state = MMPLAYER_SEEK_NONE;
7610 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7612 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7613 GST_FORMAT_TIME, seek_flags,
7614 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7618 LOGE("failed to set position.");
7624 case MM_PLAYER_POS_FORMAT_PERCENT:
7626 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7628 if (player->seek_state != MMPLAYER_SEEK_NONE) {
7629 LOGD("not completed seek");
7630 return MM_ERROR_PLAYER_DOING_SEEK;
7633 if (!internal_called)
7634 player->seek_state = MMPLAYER_SEEK_IN_PROGRESS;
7636 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7637 pos_nsec = (gint64)((position * player->duration) / 100);
7638 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7639 GST_FORMAT_TIME, seek_flags,
7640 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7642 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7652 /* NOTE : store last seeking point to overcome some bad operation
7653 * (returning zero when getting current position) of some elements
7655 player->last_position = pos_nsec;
7657 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7658 if (player->playback_rate > 1.0)
7659 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7661 if ((!internal_called) &&
7662 (player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7663 LOGD("buffering should be reset after seeking");
7664 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7665 player->streamer->buffering_percent = 100; /* after seeking, new per can be non-zero. */
7669 return MM_ERROR_NONE;
7672 player->pending_seek.is_pending = TRUE;
7673 player->pending_seek.format = format;
7674 player->pending_seek.pos = position;
7676 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7677 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7678 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7679 player->pending_seek.pos);
7681 return MM_ERROR_NONE;
7684 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7685 return MM_ERROR_INVALID_ARGUMENT;
7688 player->seek_state = MMPLAYER_SEEK_NONE;
7689 return MM_ERROR_PLAYER_SEEK;
7692 #define TRICKPLAY_OFFSET GST_MSECOND
7695 __gst_get_position(mm_player_t* player, int format, gint64* position)
7697 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7698 gint64 pos_nsec = 0;
7699 gboolean ret = TRUE;
7701 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7702 MM_ERROR_PLAYER_NOT_INITIALIZED);
7704 current_state = MMPLAYER_CURRENT_STATE(player);
7706 /* NOTE : query position except paused state to overcome some bad operation
7707 * please refer to below comments in details
7709 if (current_state != MM_PLAYER_STATE_PAUSED)
7710 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7712 /* NOTE : get last point to overcome some bad operation of some elements
7713 *(returning zero when getting current position in paused state
7714 * and when failed to get postion during seeking
7716 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7717 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7719 if (player->playback_rate < 0.0)
7720 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7722 pos_nsec = player->last_position;
7725 pos_nsec = player->last_position;
7727 player->last_position = pos_nsec;
7729 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7732 if (player->duration > 0 && pos_nsec > player->duration)
7733 pos_nsec = player->duration;
7735 player->last_position = pos_nsec;
7739 case MM_PLAYER_POS_FORMAT_TIME:
7740 *position = pos_nsec;
7743 case MM_PLAYER_POS_FORMAT_PERCENT:
7745 if (player->duration <= 0) {
7746 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7749 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7750 *position = (gint64)(pos_nsec * 100 / player->duration);
7755 return MM_ERROR_PLAYER_INTERNAL;
7758 return MM_ERROR_NONE;
7762 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7764 #define STREAMING_IS_FINISHED 0
7765 #define BUFFERING_MAX_PER 100
7766 #define DEFAULT_PER_VALUE -1
7767 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7769 MMPlayerGstElement *mainbin = NULL;
7770 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7771 gint64 buffered_total = 0;
7772 gint64 position = 0;
7773 gint buffered_sec = -1;
7774 GstBufferingMode mode = GST_BUFFERING_STREAM;
7775 gint64 content_size_time = player->duration;
7776 guint64 content_size_bytes = player->http_content_size;
7778 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7780 player->pipeline->mainbin,
7781 MM_ERROR_PLAYER_NOT_INITIALIZED);
7783 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7788 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7789 /* and rtsp is not ready yet. */
7790 LOGW("it's only used for http streaming case.\n");
7791 return MM_ERROR_PLAYER_NO_OP;
7794 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7795 LOGW("Time format is not supported yet.\n");
7796 return MM_ERROR_INVALID_ARGUMENT;
7799 if (content_size_time <= 0 || content_size_bytes <= 0) {
7800 LOGW("there is no content size.");
7801 return MM_ERROR_NONE;
7804 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7805 LOGW("fail to get current position.");
7806 return MM_ERROR_NONE;
7809 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7810 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7812 mainbin = player->pipeline->mainbin;
7813 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7815 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7816 GstQuery *query = NULL;
7817 gint byte_in_rate = 0, byte_out_rate = 0;
7818 gint64 estimated_total = 0;
7820 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7821 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7822 LOGW("fail to get buffering query from queue2");
7824 gst_query_unref(query);
7825 return MM_ERROR_NONE;
7828 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7829 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7831 if (mode == GST_BUFFERING_STREAM) {
7832 /* using only queue in case of push mode(ts / mp3) */
7833 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7834 GST_FORMAT_BYTES, &buffered_total)) {
7835 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7836 stop_per = 100 * buffered_total / content_size_bytes;
7839 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7841 guint num_of_ranges = 0;
7842 gint64 start_byte = 0, stop_byte = 0;
7844 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7845 if (estimated_total != STREAMING_IS_FINISHED) {
7846 /* buffered size info from queue2 */
7847 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7848 for (idx = 0; idx < num_of_ranges; idx++) {
7849 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7850 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7852 buffered_total += (stop_byte - start_byte);
7855 stop_per = BUFFERING_MAX_PER;
7857 gst_query_unref(query);
7860 if (stop_per == DEFAULT_PER_VALUE) {
7861 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7863 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7865 /* buffered size info from multiqueue */
7866 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7867 guint curr_size_bytes = 0;
7868 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7869 "curr-size-bytes", &curr_size_bytes, NULL);
7870 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7871 buffered_total += curr_size_bytes;
7874 if (avg_byterate > 0)
7875 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7876 else if (player->total_maximum_bitrate > 0)
7877 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7878 else if (player->total_bitrate > 0)
7879 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7881 if (buffered_sec >= 0)
7882 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7886 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7887 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7889 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7890 buffered_total, buffered_sec, *start_pos, *stop_pos);
7892 return MM_ERROR_NONE;
7896 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7901 LOGW("set_message_callback is called with invalid player handle\n");
7902 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7905 player->msg_cb = callback;
7906 player->msg_cb_param = user_param;
7908 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7912 return MM_ERROR_NONE;
7915 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7917 int ret = MM_ERROR_PLAYER_INVALID_URI;
7922 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7923 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7924 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7926 memset(data, 0, sizeof(MMPlayerParseProfile));
7928 if ((path = strstr(uri, "es_buff://"))) {
7930 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7931 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7932 ret = MM_ERROR_NONE;
7934 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7936 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7937 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7938 ret = MM_ERROR_NONE;
7940 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7943 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7944 tmp = g_ascii_strdown(uri, strlen(uri));
7946 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7947 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7949 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7951 ret = MM_ERROR_NONE;
7954 } else if ((path = strstr(uri, "rtspu://"))) {
7956 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7957 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7958 ret = MM_ERROR_NONE;
7960 } else if ((path = strstr(uri, "rtspr://"))) {
7961 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7962 char *separater = strstr(path, "*");
7966 char *urgent = separater + strlen("*");
7968 if ((urgent_len = strlen(urgent))) {
7969 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7970 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7971 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7972 ret = MM_ERROR_NONE;
7975 } else if ((path = strstr(uri, "mms://"))) {
7977 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7978 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7979 ret = MM_ERROR_NONE;
7981 } else if ((path = strstr(uri, "mem://"))) {
7984 char *buffer = NULL;
7985 char *seperator = strchr(path, ',');
7986 char ext[100] = {0,}, size[100] = {0,};
7989 if ((buffer = strstr(path, "ext="))) {
7990 buffer += strlen("ext=");
7992 if (strlen(buffer)) {
7993 strncpy(ext, buffer, 99);
7995 if ((seperator = strchr(ext, ','))
7996 || (seperator = strchr(ext, ' '))
7997 || (seperator = strchr(ext, '\0'))) {
7998 seperator[0] = '\0';
8003 if ((buffer = strstr(path, "size="))) {
8004 buffer += strlen("size=");
8006 if (strlen(buffer) > 0) {
8007 strncpy(size, buffer, 99);
8009 if ((seperator = strchr(size, ','))
8010 || (seperator = strchr(size, ' '))
8011 || (seperator = strchr(size, '\0'))) {
8012 seperator[0] = '\0';
8015 mem_size = atoi(size);
8020 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8021 if (mem_size && param) {
8022 if (data->input_mem.buf)
8023 free(data->input_mem.buf);
8024 data->input_mem.buf = malloc(mem_size);
8026 if (data->input_mem.buf) {
8027 memcpy(data->input_mem.buf, param, mem_size);
8028 data->input_mem.len = mem_size;
8029 ret = MM_ERROR_NONE;
8031 LOGE("failed to alloc mem %d", mem_size);
8032 ret = MM_ERROR_PLAYER_INTERNAL;
8035 data->input_mem.offset = 0;
8036 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8040 gchar *location = NULL;
8043 if ((path = strstr(uri, "file://"))) {
8045 location = g_filename_from_uri(uri, NULL, &err);
8047 if (!location || (err != NULL)) {
8048 LOGE("Invalid URI '%s' for filesrc: %s", path,
8049 (err != NULL) ? err->message : "unknown error");
8051 if (err) g_error_free(err);
8052 if (location) g_free(location);
8054 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8058 LOGD("path from uri: %s", location);
8061 path = (location != NULL) ? (location) : ((char*)uri);
8062 int file_stat = MM_ERROR_NONE;
8064 file_stat = util_exist_file_path(path);
8066 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8067 if (file_stat == MM_ERROR_NONE) {
8068 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8070 if (util_is_sdp_file(path)) {
8071 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8072 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8074 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8076 ret = MM_ERROR_NONE;
8077 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8078 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8080 LOGE("invalid uri, could not play..\n");
8081 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8084 if (location) g_free(location);
8088 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8089 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8090 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8091 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8093 /* dump parse result */
8094 SECURE_LOGW("incomming uri : %s\n", uri);
8095 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8096 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8104 __mmplayer_can_do_interrupt(mm_player_t *player)
8106 if (!player || !player->pipeline || !player->attrs) {
8107 LOGW("not initialized");
8111 if (player->set_mode.pcm_extraction) {
8112 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8116 /* check if seeking */
8117 if (player->seek_state != MMPLAYER_SEEK_NONE) {
8118 MMMessageParamType msg_param;
8119 memset(&msg_param, 0, sizeof(MMMessageParamType));
8120 msg_param.code = MM_ERROR_PLAYER_SEEK;
8121 player->seek_state = MMPLAYER_SEEK_NONE;
8122 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8126 /* check other thread */
8127 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8128 LOGW("locked already, cmd state : %d", player->cmd);
8130 /* check application command */
8131 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8132 LOGW("playing.. should wait cmd lock then, will be interrupted");
8134 /* lock will be released at mrp_resource_release_cb() */
8135 MMPLAYER_CMD_LOCK(player);
8138 LOGW("nothing to do");
8141 LOGW("can interrupt immediately");
8145 FAILED: /* with CMD UNLOCKED */
8148 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8153 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8156 mm_player_t *player = NULL;
8160 if (user_data == NULL) {
8161 LOGE("- user_data is null\n");
8164 player = (mm_player_t *)user_data;
8166 /* do something to release resource here.
8167 * player stop and interrupt forwarding */
8168 if (!__mmplayer_can_do_interrupt(player)) {
8169 LOGW("no need to interrupt, so leave");
8171 MMMessageParamType msg = {0, };
8174 player->interrupted_by_resource = TRUE;
8176 /* get last play position */
8177 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8178 LOGW("failed to get play position.");
8180 msg.union_type = MM_MSG_UNION_TIME;
8181 msg.time.elapsed = pos;
8182 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8184 LOGD("video resource conflict so, resource will be freed by unrealizing");
8185 if (_mmplayer_unrealize((MMHandleType)player))
8186 LOGW("failed to unrealize");
8188 /* lock is called in __mmplayer_can_do_interrupt() */
8189 MMPLAYER_CMD_UNLOCK(player);
8192 if (res == player->video_overlay_resource)
8193 player->video_overlay_resource = FALSE;
8195 player->video_decoder_resource = FALSE;
8203 _mmplayer_create_player(MMHandleType handle)
8205 int ret = MM_ERROR_PLAYER_INTERNAL;
8206 bool enabled = false;
8208 mm_player_t* player = MM_PLAYER_CAST(handle);
8212 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8214 /* initialize player state */
8215 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8216 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8217 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8218 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8220 /* check current state */
8221 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8223 /* construct attributes */
8224 player->attrs = _mmplayer_construct_attribute(handle);
8226 if (!player->attrs) {
8227 LOGE("Failed to construct attributes\n");
8231 /* initialize gstreamer with configured parameter */
8232 if (!__mmplayer_init_gstreamer(player)) {
8233 LOGE("Initializing gstreamer failed\n");
8234 _mmplayer_deconstruct_attribute(handle);
8238 /* create lock. note that g_tread_init() has already called in gst_init() */
8239 g_mutex_init(&player->fsink_lock);
8241 /* create update tag lock */
8242 g_mutex_init(&player->update_tag_lock);
8244 /* create next play mutex */
8245 g_mutex_init(&player->next_play_thread_mutex);
8247 /* create next play cond */
8248 g_cond_init(&player->next_play_thread_cond);
8250 /* create next play thread */
8251 player->next_play_thread =
8252 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8253 if (!player->next_play_thread) {
8254 LOGE("failed to create next play thread");
8255 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8256 g_mutex_clear(&player->next_play_thread_mutex);
8257 g_cond_clear(&player->next_play_thread_cond);
8261 player->bus_msg_q = g_queue_new();
8262 if (!player->bus_msg_q) {
8263 LOGE("failed to create queue for bus_msg");
8264 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8268 ret = _mmplayer_initialize_video_capture(player);
8269 if (ret != MM_ERROR_NONE) {
8270 LOGE("failed to initialize video capture\n");
8274 /* initialize resource manager */
8275 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8276 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8277 &player->resource_manager)) {
8278 LOGE("failed to initialize resource manager\n");
8282 if (MMPLAYER_IS_HTTP_PD(player)) {
8283 player->pd_downloader = NULL;
8284 player->pd_file_save_path = NULL;
8287 /* create video bo lock and cond */
8288 g_mutex_init(&player->video_bo_mutex);
8289 g_cond_init(&player->video_bo_cond);
8291 /* create media stream callback mutex */
8292 g_mutex_init(&player->media_stream_cb_lock);
8294 /* create subtitle info lock and cond */
8295 g_mutex_init(&player->subtitle_info_mutex);
8296 g_cond_init(&player->subtitle_info_cond);
8298 player->streaming_type = STREAMING_SERVICE_NONE;
8300 /* give default value of audio effect setting */
8301 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8302 player->sound.rg_enable = false;
8303 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8305 player->play_subtitle = FALSE;
8306 player->use_deinterleave = FALSE;
8307 player->max_audio_channels = 0;
8308 player->video_share_api_delta = 0;
8309 player->video_share_clock_delta = 0;
8310 player->has_closed_caption = FALSE;
8311 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8312 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8313 player->pending_resume = FALSE;
8314 if (player->ini.dump_element_keyword[0][0] == '\0')
8315 player->ini.set_dump_element_flag = FALSE;
8317 player->ini.set_dump_element_flag = TRUE;
8319 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8320 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8321 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8323 /* Set video360 settings to their defaults for just-created player.
8326 player->is_360_feature_enabled = FALSE;
8327 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8328 LOGI("spherical feature info: %d", enabled);
8330 player->is_360_feature_enabled = TRUE;
8332 LOGE("failed to get spherical feature info");
8335 player->is_content_spherical = FALSE;
8336 player->is_video360_enabled = TRUE;
8337 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8338 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8339 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8340 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8341 player->video360_zoom = 1.0f;
8342 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8343 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8345 /* set player state to null */
8346 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8347 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8349 return MM_ERROR_NONE;
8353 g_mutex_clear(&player->fsink_lock);
8355 /* free update tag lock */
8356 g_mutex_clear(&player->update_tag_lock);
8358 g_queue_free(player->bus_msg_q);
8360 /* free next play thread */
8361 if (player->next_play_thread) {
8362 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8363 player->next_play_thread_exit = TRUE;
8364 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8365 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8367 g_thread_join(player->next_play_thread);
8368 player->next_play_thread = NULL;
8370 g_mutex_clear(&player->next_play_thread_mutex);
8371 g_cond_clear(&player->next_play_thread_cond);
8374 /* release attributes */
8375 _mmplayer_deconstruct_attribute(handle);
8383 __mmplayer_init_gstreamer(mm_player_t* player)
8385 static gboolean initialized = FALSE;
8386 static const int max_argc = 50;
8388 gchar** argv = NULL;
8389 gchar** argv2 = NULL;
8395 LOGD("gstreamer already initialized.\n");
8400 argc = malloc(sizeof(int));
8401 argv = malloc(sizeof(gchar*) * max_argc);
8402 argv2 = malloc(sizeof(gchar*) * max_argc);
8404 if (!argc || !argv || !argv2)
8407 memset(argv, 0, sizeof(gchar*) * max_argc);
8408 memset(argv2, 0, sizeof(gchar*) * max_argc);
8412 argv[0] = g_strdup("mmplayer");
8415 for (i = 0; i < 5; i++) {
8416 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8417 if (strlen(player->ini.gst_param[i]) > 0) {
8418 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8423 /* we would not do fork for scanning plugins */
8424 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8427 /* check disable registry scan */
8428 if (player->ini.skip_rescan) {
8429 argv[*argc] = g_strdup("--gst-disable-registry-update");
8433 /* check disable segtrap */
8434 if (player->ini.disable_segtrap) {
8435 argv[*argc] = g_strdup("--gst-disable-segtrap");
8439 LOGD("initializing gstreamer with following parameter\n");
8440 LOGD("argc : %d\n", *argc);
8443 for (i = 0; i < arg_count; i++) {
8445 LOGD("argv[%d] : %s\n", i, argv2[i]);
8448 /* initializing gstreamer */
8449 if (!gst_init_check(argc, &argv, &err)) {
8450 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8457 for (i = 0; i < arg_count; i++) {
8458 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8459 MMPLAYER_FREEIF(argv2[i]);
8462 MMPLAYER_FREEIF(argv);
8463 MMPLAYER_FREEIF(argv2);
8464 MMPLAYER_FREEIF(argc);
8474 for (i = 0; i < arg_count; i++) {
8475 LOGD("free[%d] : %s\n", i, argv2[i]);
8476 MMPLAYER_FREEIF(argv2[i]);
8479 MMPLAYER_FREEIF(argv);
8480 MMPLAYER_FREEIF(argv2);
8481 MMPLAYER_FREEIF(argc);
8487 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8491 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8492 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8493 MMPLAYER_FREEIF(player->pd_file_save_path);
8496 return MM_ERROR_NONE;
8500 __mmplayer_check_async_state_transition(mm_player_t* player)
8502 GstState element_state = GST_STATE_VOID_PENDING;
8503 GstState element_pending_state = GST_STATE_VOID_PENDING;
8504 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8505 GstElement * element = NULL;
8506 gboolean async = FALSE;
8508 /* check player handle */
8509 MMPLAYER_RETURN_IF_FAIL(player &&
8511 player->pipeline->mainbin &&
8512 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8515 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8517 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8518 LOGD("don't need to check the pipeline state");
8522 MMPLAYER_PRINT_STATE(player);
8524 /* wait for state transition */
8525 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8526 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8528 if (ret == GST_STATE_CHANGE_FAILURE) {
8529 LOGE(" [%s] state : %s pending : %s \n",
8530 GST_ELEMENT_NAME(element),
8531 gst_element_state_get_name(element_state),
8532 gst_element_state_get_name(element_pending_state));
8534 /* dump state of all element */
8535 __mmplayer_dump_pipeline_state(player);
8540 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8545 _mmplayer_destroy(MMHandleType handle)
8547 mm_player_t* player = MM_PLAYER_CAST(handle);
8551 /* check player handle */
8552 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554 /* destroy can called at anytime */
8555 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8557 /* check async state transition */
8558 __mmplayer_check_async_state_transition(player);
8560 __mmplayer_destroy_streaming_ext(player);
8562 /* release next play thread */
8563 if (player->next_play_thread) {
8564 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8565 player->next_play_thread_exit = TRUE;
8566 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8567 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8569 LOGD("waitting for next play thread exit\n");
8570 g_thread_join(player->next_play_thread);
8571 g_mutex_clear(&player->next_play_thread_mutex);
8572 g_cond_clear(&player->next_play_thread_cond);
8573 LOGD("next play thread released\n");
8576 _mmplayer_release_video_capture(player);
8578 /* de-initialize resource manager */
8579 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8580 player->resource_manager))
8581 LOGE("failed to deinitialize resource manager\n");
8583 /* release pipeline */
8584 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8585 LOGE("failed to destory pipeline\n");
8586 return MM_ERROR_PLAYER_INTERNAL;
8589 g_queue_free(player->bus_msg_q);
8591 /* release subtitle info lock and cond */
8592 g_mutex_clear(&player->subtitle_info_mutex);
8593 g_cond_clear(&player->subtitle_info_cond);
8595 __mmplayer_release_dump_list(player->dump_list);
8597 /* release miscellaneous information */
8598 __mmplayer_release_misc(player);
8600 /* release miscellaneous information.
8601 these info needs to be released after pipeline is destroyed. */
8602 __mmplayer_release_misc_post(player);
8604 /* release attributes */
8605 _mmplayer_deconstruct_attribute(handle);
8608 g_mutex_clear(&player->fsink_lock);
8611 g_mutex_clear(&player->update_tag_lock);
8613 /* release video bo lock and cond */
8614 g_mutex_clear(&player->video_bo_mutex);
8615 g_cond_clear(&player->video_bo_cond);
8617 /* release media stream callback lock */
8618 g_mutex_clear(&player->media_stream_cb_lock);
8622 return MM_ERROR_NONE;
8626 __mmplayer_realize_streaming_ext(mm_player_t* player)
8628 int ret = MM_ERROR_NONE;
8631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8633 if (MMPLAYER_IS_HTTP_PD(player)) {
8634 gboolean bret = FALSE;
8636 player->pd_downloader = _mmplayer_create_pd_downloader();
8637 if (!player->pd_downloader) {
8638 LOGE("Unable to create PD Downloader...");
8639 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8642 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8644 if (FALSE == bret) {
8645 LOGE("Unable to create PD Downloader...");
8646 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8655 _mmplayer_realize(MMHandleType hplayer)
8657 mm_player_t* player = (mm_player_t*)hplayer;
8660 MMHandleType attrs = 0;
8661 int ret = MM_ERROR_NONE;
8665 /* check player handle */
8666 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8668 /* check current state */
8669 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8671 attrs = MMPLAYER_GET_ATTRS(player);
8673 LOGE("fail to get attributes.\n");
8674 return MM_ERROR_PLAYER_INTERNAL;
8676 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8677 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8679 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8680 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8682 if (ret != MM_ERROR_NONE) {
8683 LOGE("failed to parse profile\n");
8688 if (uri && (strstr(uri, "es_buff://"))) {
8689 if (strstr(uri, "es_buff://push_mode"))
8690 player->es_player_push_mode = TRUE;
8692 player->es_player_push_mode = FALSE;
8695 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8696 LOGW("mms protocol is not supported format.\n");
8697 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8700 if (MMPLAYER_IS_STREAMING(player))
8701 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8703 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8705 player->smooth_streaming = FALSE;
8706 player->videodec_linked = 0;
8707 player->videosink_linked = 0;
8708 player->audiodec_linked = 0;
8709 player->audiosink_linked = 0;
8710 player->textsink_linked = 0;
8711 player->is_external_subtitle_present = FALSE;
8712 player->is_external_subtitle_added_now = FALSE;
8713 /* set the subtitle ON default */
8714 player->is_subtitle_off = FALSE;
8716 /* realize pipeline */
8717 ret = __gst_realize(player);
8718 if (ret != MM_ERROR_NONE)
8719 LOGE("fail to realize the player.\n");
8721 ret = __mmplayer_realize_streaming_ext(player);
8723 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8731 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8734 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736 /* destroy can called at anytime */
8737 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8738 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8741 return MM_ERROR_NONE;
8745 _mmplayer_unrealize(MMHandleType hplayer)
8747 mm_player_t* player = (mm_player_t*)hplayer;
8748 int ret = MM_ERROR_NONE;
8752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8754 MMPLAYER_CMD_UNLOCK(player);
8755 /* destroy the gst bus msg thread which is created during realize.
8756 this funct have to be called before getting cmd lock. */
8757 _mmplayer_bus_msg_thread_destroy(player);
8758 MMPLAYER_CMD_LOCK(player);
8760 /* check current state */
8761 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8763 /* check async state transition */
8764 __mmplayer_check_async_state_transition(player);
8766 __mmplayer_unrealize_streaming_ext(player);
8768 /* unrealize pipeline */
8769 ret = __gst_unrealize(player);
8771 /* set asm stop if success */
8772 if (MM_ERROR_NONE == ret) {
8773 if (!player->interrupted_by_resource) {
8774 if (player->video_decoder_resource != NULL) {
8775 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8776 player->video_decoder_resource);
8777 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8778 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8780 player->video_decoder_resource = NULL;
8783 if (player->video_overlay_resource != NULL) {
8784 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8785 player->video_overlay_resource);
8786 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8787 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8789 player->video_overlay_resource = NULL;
8792 ret = mm_resource_manager_commit(player->resource_manager);
8793 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8794 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8797 LOGE("failed and don't change asm state to stop");
8805 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8807 mm_player_t* player = (mm_player_t*)hplayer;
8809 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8811 return __gst_set_message_callback(player, callback, user_param);
8815 _mmplayer_get_state(MMHandleType hplayer, int* state)
8817 mm_player_t *player = (mm_player_t*)hplayer;
8819 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8821 *state = MMPLAYER_CURRENT_STATE(player);
8823 return MM_ERROR_NONE;
8828 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8830 mm_player_t* player = (mm_player_t*) hplayer;
8831 GstElement* vol_element = NULL;
8836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8838 LOGD("volume [L]=%f:[R]=%f\n",
8839 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8841 /* invalid factor range or not */
8842 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8843 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8844 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8845 return MM_ERROR_INVALID_ARGUMENT;
8849 /* not support to set other value into each channel */
8850 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8851 return MM_ERROR_INVALID_ARGUMENT;
8853 /* Save volume to handle. Currently the first array element will be saved. */
8854 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8856 /* check pipeline handle */
8857 if (!player->pipeline || !player->pipeline->audiobin) {
8858 LOGD("audiobin is not created yet\n");
8859 LOGD("but, current stored volume will be set when it's created.\n");
8861 /* NOTE : stored volume will be used in create_audiobin
8862 * returning MM_ERROR_NONE here makes application to able to
8863 * set volume at anytime.
8865 return MM_ERROR_NONE;
8868 /* setting volume to volume element */
8869 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8872 LOGD("volume is set [%f]\n", player->sound.volume);
8873 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8878 return MM_ERROR_NONE;
8883 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8885 mm_player_t* player = (mm_player_t*) hplayer;
8890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8891 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8893 /* returning stored volume */
8894 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8895 volume->level[i] = player->sound.volume;
8899 return MM_ERROR_NONE;
8903 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8905 mm_player_t* player = (mm_player_t*) hplayer;
8906 GstElement* vol_element = NULL;
8910 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8912 /* mute value shoud 0 or 1 */
8913 if (mute != 0 && mute != 1) {
8914 LOGE("bad mute value\n");
8916 /* FIXIT : definitly, we need _BAD_PARAM error code */
8917 return MM_ERROR_INVALID_ARGUMENT;
8920 player->sound.mute = mute;
8922 /* just hold mute value if pipeline is not ready */
8923 if (!player->pipeline || !player->pipeline->audiobin) {
8924 LOGD("pipeline is not ready. holding mute value\n");
8925 return MM_ERROR_NONE;
8928 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8930 /* NOTE : volume will only created when the bt is enabled */
8932 LOGD("mute : %d\n", mute);
8933 g_object_set(vol_element, "mute", mute, NULL);
8935 LOGD("volume elemnet is not created. using volume in audiosink\n");
8939 return MM_ERROR_NONE;
8943 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8945 mm_player_t* player = (mm_player_t*) hplayer;
8949 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8950 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8952 /* just hold mute value if pipeline is not ready */
8953 if (!player->pipeline || !player->pipeline->audiobin) {
8954 LOGD("pipeline is not ready. returning stored value\n");
8955 *pmute = player->sound.mute;
8956 return MM_ERROR_NONE;
8959 *pmute = player->sound.mute;
8963 return MM_ERROR_NONE;
8967 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8969 mm_player_t* player = (mm_player_t*) hplayer;
8973 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8975 player->video_stream_changed_cb = callback;
8976 player->video_stream_changed_cb_user_param = user_param;
8977 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8981 return MM_ERROR_NONE;
8985 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8987 mm_player_t* player = (mm_player_t*) hplayer;
8991 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8993 player->audio_stream_changed_cb = callback;
8994 player->audio_stream_changed_cb_user_param = user_param;
8995 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8999 return MM_ERROR_NONE;
9003 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9005 mm_player_t* player = (mm_player_t*) hplayer;
9009 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9011 player->audio_stream_render_cb_ex = callback;
9012 player->audio_stream_cb_user_param = user_param;
9013 player->audio_stream_sink_sync = sync;
9014 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);
9018 return MM_ERROR_NONE;
9022 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9024 mm_player_t* player = (mm_player_t*) hplayer;
9028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9030 if (callback && !player->bufmgr)
9031 player->bufmgr = tbm_bufmgr_init(-1);
9033 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9034 player->video_stream_cb = callback;
9035 player->video_stream_cb_user_param = user_param;
9037 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9041 return MM_ERROR_NONE;
9045 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9047 mm_player_t* player = (mm_player_t*) hplayer;
9051 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9053 player->audio_stream_cb = callback;
9054 player->audio_stream_cb_user_param = user_param;
9055 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9059 return MM_ERROR_NONE;
9063 __mmplayer_start_streaming_ext(mm_player_t *player)
9065 gint ret = MM_ERROR_NONE;
9068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9070 if (MMPLAYER_IS_HTTP_PD(player)) {
9071 if (!player->pd_downloader) {
9072 ret = __mmplayer_realize_streaming_ext(player);
9074 if (ret != MM_ERROR_NONE) {
9075 LOGE("failed to realize streaming ext\n");
9080 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9081 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9083 LOGE("ERROR while starting PD...\n");
9084 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9086 ret = MM_ERROR_NONE;
9095 _mmplayer_start(MMHandleType hplayer)
9097 mm_player_t* player = (mm_player_t*) hplayer;
9098 gint ret = MM_ERROR_NONE;
9102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9104 /* check current state */
9105 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9107 /* NOTE : we should check and create pipeline again if not created as we destroy
9108 * whole pipeline when stopping in streamming playback
9110 if (!player->pipeline) {
9111 ret = __gst_realize(player);
9112 if (MM_ERROR_NONE != ret) {
9113 LOGE("failed to realize before starting. only in streamming\n");
9119 ret = __mmplayer_start_streaming_ext(player);
9120 if (ret != MM_ERROR_NONE) {
9121 LOGE("failed to start streaming ext 0x%X", ret);
9125 /* start pipeline */
9126 ret = __gst_start(player);
9127 if (ret != MM_ERROR_NONE)
9128 LOGE("failed to start player.\n");
9135 /* NOTE: post "not supported codec message" to application
9136 * when one codec is not found during AUTOPLUGGING in MSL.
9137 * So, it's separated with error of __mmplayer_gst_callback().
9138 * And, if any codec is not found, don't send message here.
9139 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9142 __mmplayer_handle_missed_plugin(mm_player_t* player)
9144 MMMessageParamType msg_param;
9145 memset(&msg_param, 0, sizeof(MMMessageParamType));
9146 gboolean post_msg_direct = FALSE;
9150 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9152 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9153 player->not_supported_codec, player->can_support_codec);
9155 if (player->not_found_demuxer) {
9156 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9157 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9159 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9160 MMPLAYER_FREEIF(msg_param.data);
9162 return MM_ERROR_NONE;
9165 if (player->not_supported_codec) {
9166 if (player->can_support_codec) {
9167 // There is one codec to play
9168 post_msg_direct = TRUE;
9170 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9171 post_msg_direct = TRUE;
9174 if (post_msg_direct) {
9175 MMMessageParamType msg_param;
9176 memset(&msg_param, 0, sizeof(MMMessageParamType));
9178 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9179 LOGW("not found AUDIO codec, posting error code to application.\n");
9181 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9182 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9183 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9184 LOGW("not found VIDEO codec, posting error code to application.\n");
9186 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9187 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9190 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9192 MMPLAYER_FREEIF(msg_param.data);
9194 return MM_ERROR_NONE;
9196 // no any supported codec case
9197 LOGW("not found any codec, posting error code to application.\n");
9199 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9200 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9201 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9203 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9204 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9207 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9209 MMPLAYER_FREEIF(msg_param.data);
9215 return MM_ERROR_NONE;
9218 static void __mmplayer_check_pipeline(mm_player_t* player)
9220 GstState element_state = GST_STATE_VOID_PENDING;
9221 GstState element_pending_state = GST_STATE_VOID_PENDING;
9223 int ret = MM_ERROR_NONE;
9225 if (player->gapless.reconfigure) {
9226 LOGW("pipeline is under construction.\n");
9228 MMPLAYER_PLAYBACK_LOCK(player);
9229 MMPLAYER_PLAYBACK_UNLOCK(player);
9231 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9233 /* wait for state transition */
9234 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9236 if (ret == GST_STATE_CHANGE_FAILURE)
9237 LOGE("failed to change pipeline state within %d sec\n", timeout);
9241 /* NOTE : it should be able to call 'stop' anytime*/
9243 _mmplayer_stop(MMHandleType hplayer)
9245 mm_player_t* player = (mm_player_t*)hplayer;
9246 int ret = MM_ERROR_NONE;
9250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9252 /* check current state */
9253 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9255 /* check pipline building state */
9256 __mmplayer_check_pipeline(player);
9257 __mmplayer_reset_gapless_state(player);
9259 /* NOTE : application should not wait for EOS after calling STOP */
9260 __mmplayer_cancel_eos_timer(player);
9262 __mmplayer_unrealize_streaming_ext(player);
9265 player->seek_state = MMPLAYER_SEEK_NONE;
9268 ret = __gst_stop(player);
9270 if (ret != MM_ERROR_NONE)
9271 LOGE("failed to stop player.\n");
9279 _mmplayer_pause(MMHandleType hplayer)
9281 mm_player_t* player = (mm_player_t*)hplayer;
9282 gint64 pos_nsec = 0;
9283 gboolean async = FALSE;
9284 gint ret = MM_ERROR_NONE;
9288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9290 /* check current state */
9291 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9293 /* check pipline building state */
9294 __mmplayer_check_pipeline(player);
9296 switch (MMPLAYER_CURRENT_STATE(player)) {
9297 case MM_PLAYER_STATE_READY:
9299 /* check prepare async or not.
9300 * In the case of streaming playback, it's recommned to avoid blocking wait.
9302 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9303 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9305 /* Changing back sync of rtspsrc to async */
9306 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9307 LOGD("async prepare working mode for rtsp");
9313 case MM_PLAYER_STATE_PLAYING:
9315 /* NOTE : store current point to overcome some bad operation
9316 *(returning zero when getting current position in paused state) of some
9319 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9320 LOGW("getting current position failed in paused\n");
9322 player->last_position = pos_nsec;
9324 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9325 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9326 This causes problem is position calculation during normal pause resume scenarios also.
9327 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9328 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9329 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9330 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9336 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9337 LOGD("doing async pause in case of ms buff src");
9341 /* pause pipeline */
9342 ret = __gst_pause(player, async);
9344 if (ret != MM_ERROR_NONE)
9345 LOGE("failed to pause player. ret : 0x%x\n", ret);
9347 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9348 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9349 LOGE("failed to update display_rotation");
9358 _mmplayer_resume(MMHandleType hplayer)
9360 mm_player_t* player = (mm_player_t*)hplayer;
9361 int ret = MM_ERROR_NONE;
9362 gboolean async = FALSE;
9366 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9368 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9369 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
9370 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
9374 /* Changing back sync mode rtspsrc to async */
9375 LOGD("async resume for rtsp case");
9379 /* check current state */
9380 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9382 ret = __gst_resume(player, async);
9383 if (ret != MM_ERROR_NONE)
9384 LOGE("failed to resume player.\n");
9386 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9387 LOGD("force resume even during buffering");
9388 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9397 __mmplayer_set_pcm_extraction(mm_player_t* player)
9399 gint64 start_nsec = 0;
9400 gint64 end_nsec = 0;
9401 gint64 dur_nsec = 0;
9402 gint64 dur_msec = 0;
9403 int required_start = 0;
9404 int required_end = 0;
9409 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9411 mm_attrs_multiple_get(player->attrs,
9413 "pcm_extraction_start_msec", &required_start,
9414 "pcm_extraction_end_msec", &required_end,
9417 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9419 if (required_start == 0 && required_end == 0) {
9420 LOGD("extracting entire stream");
9421 return MM_ERROR_NONE;
9422 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9423 LOGD("invalid range for pcm extraction");
9424 return MM_ERROR_INVALID_ARGUMENT;
9428 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9430 LOGE("failed to get duration");
9431 return MM_ERROR_PLAYER_INTERNAL;
9433 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9435 if (dur_msec < required_end) {
9437 LOGD("invalid end pos for pcm extraction");
9438 return MM_ERROR_INVALID_ARGUMENT;
9441 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9442 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9444 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9447 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9448 GST_SEEK_TYPE_SET, start_nsec,
9449 GST_SEEK_TYPE_SET, end_nsec))) {
9450 LOGE("failed to seek for pcm extraction\n");
9452 return MM_ERROR_PLAYER_SEEK;
9455 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9459 return MM_ERROR_NONE;
9463 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9465 mm_player_t* player = (mm_player_t*)hplayer;
9466 gint64 pos_nsec = 0;
9467 int ret = MM_ERROR_NONE;
9469 signed long long start = 0, stop = 0;
9470 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9473 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9474 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9476 /* The sound of video is not supported under 0.0 and over 2.0. */
9477 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9478 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9481 _mmplayer_set_mute(hplayer, mute);
9483 if (player->playback_rate == rate)
9484 return MM_ERROR_NONE;
9486 /* If the position is reached at start potion during fast backward, EOS is posted.
9487 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9489 player->playback_rate = rate;
9491 current_state = MMPLAYER_CURRENT_STATE(player);
9493 if (current_state != MM_PLAYER_STATE_PAUSED)
9494 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9496 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9498 if ((current_state == MM_PLAYER_STATE_PAUSED)
9499 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9500 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9501 pos_nsec = player->last_position;
9506 stop = GST_CLOCK_TIME_NONE;
9508 start = GST_CLOCK_TIME_NONE;
9512 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9513 player->playback_rate,
9515 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9516 GST_SEEK_TYPE_SET, start,
9517 GST_SEEK_TYPE_SET, stop)) {
9518 LOGE("failed to set speed playback\n");
9519 return MM_ERROR_PLAYER_SEEK;
9522 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9526 return MM_ERROR_NONE;;
9530 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9532 mm_player_t* player = (mm_player_t*)hplayer;
9533 int ret = MM_ERROR_NONE;
9537 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9539 /* check pipline building state */
9540 __mmplayer_check_pipeline(player);
9542 ret = __gst_set_position(player, format, position, FALSE);
9550 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9552 mm_player_t* player = (mm_player_t*)hplayer;
9553 int ret = MM_ERROR_NONE;
9555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9557 ret = __gst_get_position(player, format, position);
9563 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9565 mm_player_t* player = (mm_player_t*)hplayer;
9566 int ret = MM_ERROR_NONE;
9568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9569 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9571 *duration = player->duration;
9576 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9578 mm_player_t* player = (mm_player_t*)hplayer;
9579 int ret = MM_ERROR_NONE;
9581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9583 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9589 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9591 mm_player_t* player = (mm_player_t*)hplayer;
9592 int ret = MM_ERROR_NONE;
9596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9598 ret = __gst_adjust_subtitle_position(player, format, position);
9606 __mmplayer_is_midi_type(gchar* str_caps)
9608 if ((g_strrstr(str_caps, "audio/midi")) ||
9609 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9610 (g_strrstr(str_caps, "application/x-smaf")) ||
9611 (g_strrstr(str_caps, "audio/x-imelody")) ||
9612 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9613 (g_strrstr(str_caps, "audio/xmf")) ||
9614 (g_strrstr(str_caps, "audio/mxmf"))) {
9623 __mmplayer_is_only_mp3_type(gchar *str_caps)
9625 if (g_strrstr(str_caps, "application/x-id3") ||
9626 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9632 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9634 GstStructure* caps_structure = NULL;
9635 gint samplerate = 0;
9639 MMPLAYER_RETURN_IF_FAIL(player && caps);
9641 caps_structure = gst_caps_get_structure(caps, 0);
9643 /* set stream information */
9644 gst_structure_get_int(caps_structure, "rate", &samplerate);
9645 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9647 gst_structure_get_int(caps_structure, "channels", &channels);
9648 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9650 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9654 __mmplayer_update_content_type_info(mm_player_t* player)
9657 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9659 if (__mmplayer_is_midi_type(player->type)) {
9660 player->bypass_audio_effect = TRUE;
9661 } else if (g_strrstr(player->type, "application/x-hls")) {
9662 /* If it can't know exact type when it parses uri because of redirection case,
9663 * it will be fixed by typefinder or when doing autoplugging.
9665 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9666 if (player->streamer) {
9667 player->streamer->is_adaptive_streaming = TRUE;
9668 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9669 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9671 } else if (g_strrstr(player->type, "application/dash+xml")) {
9672 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9673 if (player->streamer) {
9674 player->streamer->is_adaptive_streaming = TRUE;
9675 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9679 LOGD("uri type : %d", player->profile.uri_type);
9684 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9685 GstCaps *caps, gpointer data)
9687 mm_player_t* player = (mm_player_t*)data;
9692 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9694 /* store type string */
9695 MMPLAYER_FREEIF(player->type);
9696 player->type = gst_caps_to_string(caps);
9698 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9699 player, player->type, probability, gst_caps_get_size(caps));
9702 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9703 (g_strrstr(player->type, "audio/x-raw-int"))) {
9704 LOGE("not support media format\n");
9706 if (player->msg_posted == FALSE) {
9707 MMMessageParamType msg_param;
9708 memset(&msg_param, 0, sizeof(MMMessageParamType));
9710 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9711 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9713 /* don't post more if one was sent already */
9714 player->msg_posted = TRUE;
9719 __mmplayer_update_content_type_info(player);
9721 pad = gst_element_get_static_pad(tf, "src");
9723 LOGE("fail to get typefind src pad.\n");
9727 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9728 gboolean async = FALSE;
9729 LOGE("failed to autoplug %s\n", player->type);
9731 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9733 if (async && player->msg_posted == FALSE)
9734 __mmplayer_handle_missed_plugin(player);
9740 gst_object_unref(GST_OBJECT(pad));
9748 __mmplayer_create_decodebin(mm_player_t* player)
9750 GstElement *decodebin = NULL;
9754 /* create decodebin */
9755 decodebin = gst_element_factory_make("decodebin", NULL);
9758 LOGE("fail to create decodebin\n");
9762 /* raw pad handling signal */
9763 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9764 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9766 /* no-more-pad pad handling signal */
9767 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9768 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9770 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9771 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9773 /* This signal is emitted when a pad for which there is no further possible
9774 decoding is added to the decodebin.*/
9775 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9776 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9778 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9779 before looking for any elements that can handle that stream.*/
9780 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9781 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9783 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9784 before looking for any elements that can handle that stream.*/
9785 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9786 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9788 /* This signal is emitted once decodebin has finished decoding all the data.*/
9789 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9790 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9792 /* This signal is emitted when a element is added to the bin.*/
9793 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9794 G_CALLBACK(__mmplayer_gst_element_added), player);
9801 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9803 MMPlayerGstElement* mainbin = NULL;
9804 GstElement* decodebin = NULL;
9805 GstElement* queue2 = NULL;
9806 GstPad* sinkpad = NULL;
9807 GstPad* qsrcpad = NULL;
9808 gint64 dur_bytes = 0L;
9810 guint max_buffer_size_bytes = 0;
9811 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9814 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9816 mainbin = player->pipeline->mainbin;
9818 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9819 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9820 LOGD("creating http streaming buffering queue(queue2)\n");
9822 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9823 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9825 queue2 = gst_element_factory_make("queue2", "queue2");
9827 LOGE("failed to create buffering queue element\n");
9831 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9832 LOGE("failed to add buffering queue\n");
9836 sinkpad = gst_element_get_static_pad(queue2, "sink");
9837 qsrcpad = gst_element_get_static_pad(queue2, "src");
9839 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9840 LOGE("failed to link buffering queue");
9844 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9845 LOGE("fail to get duration");
9847 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9849 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9851 if (dur_bytes > 0) {
9852 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9853 type = MUXED_BUFFER_TYPE_FILE;
9855 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9856 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9862 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9863 * skip the pull mode(file or ring buffering) setting. */
9864 if (!g_strrstr(player->type, "video/mpegts")) {
9865 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9866 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9868 __mm_player_streaming_set_queue2(player->streamer,
9871 max_buffer_size_bytes,
9872 player->ini.http_buffering_time,
9873 1.0, /* no meaning */
9874 player->ini.http_buffering_limit, /* no meaning */
9876 player->http_file_buffering_path,
9877 (guint64)dur_bytes);
9880 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9881 LOGE("failed to sync queue2 state with parent\n");
9887 gst_object_unref(GST_OBJECT(sinkpad));
9889 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9890 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9894 /* create decodebin */
9895 decodebin = __mmplayer_create_decodebin(player);
9898 LOGE("can not create autoplug element\n");
9902 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9903 LOGE("failed to add decodebin\n");
9907 /* to force caps on the decodebin element and avoid reparsing stuff by
9908 * typefind. It also avoids a deadlock in the way typefind activates pads in
9909 * the state change */
9910 g_object_set(decodebin, "sink-caps", caps, NULL);
9912 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9914 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9915 LOGE("failed to link decodebin\n");
9919 gst_object_unref(GST_OBJECT(sinkpad));
9921 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9922 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9924 /* set decodebin property about buffer in streaming playback. *
9925 * in case of HLS/DASH, it does not need to have big buffer *
9926 * because it is kind of adaptive streaming. */
9927 if (!MMPLAYER_IS_HTTP_PD(player) &&
9928 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9929 gdouble high_percent = 0.0;
9931 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9932 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9934 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9935 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9937 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9938 "high-percent", (gint)high_percent,
9939 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9940 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9941 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9942 "max-size-buffers", 0, NULL); // disable or automatic
9945 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9946 LOGE("failed to sync decodebin state with parent\n");
9957 gst_object_unref(GST_OBJECT(sinkpad));
9960 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9961 * You need to explicitly set elements to the NULL state before
9962 * dropping the final reference, to allow them to clean up.
9964 gst_element_set_state(queue2, GST_STATE_NULL);
9966 /* And, it still has a parent "player".
9967 * You need to let the parent manage the object instead of unreffing the object directly.
9969 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9970 gst_object_unref(queue2);
9975 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9976 * You need to explicitly set elements to the NULL state before
9977 * dropping the final reference, to allow them to clean up.
9979 gst_element_set_state(decodebin, GST_STATE_NULL);
9981 /* And, it still has a parent "player".
9982 * You need to let the parent manage the object instead of unreffing the object directly.
9985 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9986 gst_object_unref(decodebin);
9994 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9998 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9999 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
10001 LOGD("class : %s, mime : %s \n", factory_class, mime);
10003 /* add missing plugin */
10004 /* NOTE : msl should check missing plugin for image mime type.
10005 * Some motion jpeg clips can have playable audio track.
10006 * So, msl have to play audio after displaying popup written video format not supported.
10008 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10009 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10010 LOGD("not found demuxer\n");
10011 player->not_found_demuxer = TRUE;
10012 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10018 if (!g_strrstr(factory_class, "Demuxer")) {
10019 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10020 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10021 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10023 /* check that clip have multi tracks or not */
10024 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10025 LOGD("video plugin is already linked\n");
10027 LOGW("add VIDEO to missing plugin\n");
10028 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10029 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10031 } else if (g_str_has_prefix(mime, "audio")) {
10032 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10033 LOGD("audio plugin is already linked\n");
10035 LOGW("add AUDIO to missing plugin\n");
10036 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10037 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10045 return MM_ERROR_NONE;
10050 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10052 mm_player_t* player = (mm_player_t*)data;
10056 MMPLAYER_RETURN_IF_FAIL(player);
10058 /* remove fakesink. */
10059 if (!__mmplayer_gst_remove_fakesink(player,
10060 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10061 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10062 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10063 * source element are not same. To overcome this situation, this function will called
10064 * several places and several times. Therefore, this is not an error case.
10069 LOGD("[handle: %p] pipeline has completely constructed", player);
10071 if ((player->ini.async_start) &&
10072 (player->msg_posted == FALSE) &&
10073 (player->cmd >= MMPLAYER_COMMAND_START))
10074 __mmplayer_handle_missed_plugin(player);
10076 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10080 __mmplayer_verify_next_play_path(mm_player_t *player)
10082 MMHandleType attrs = 0;
10083 MMPlayerParseProfile profile;
10084 gint uri_idx = 0, check_cnt = 0;
10086 gint mode = MM_PLAYER_PD_MODE_NONE;
10090 guint num_of_list = 0;
10091 static int profile_tv = -1;
10095 LOGD("checking for gapless play");
10097 if (player->pipeline->textbin) {
10098 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10102 attrs = MMPLAYER_GET_ATTRS(player);
10104 LOGE("fail to get attributes.\n");
10108 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10110 if (__builtin_expect(profile_tv == -1, 0)) {
10112 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10113 switch (*profileName) {
10123 /* gapless playback is not supported in case of video at TV profile. */
10124 if (profile_tv && video) {
10125 LOGW("not support video gapless playback");
10129 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10130 if (mode == TRUE) {
10136 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10137 LOGE("can not get play count\n");
10139 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10140 LOGE("can not get gapless mode\n");
10142 if (video && !gapless) {
10143 LOGW("not enabled video gapless playback");
10147 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10151 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10155 num_of_list = g_list_length(player->uri_info.uri_list);
10157 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10159 if (num_of_list == 0) {
10160 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10161 LOGE("can not get profile_uri\n");
10166 LOGE("uri list is empty.\n");
10170 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10171 LOGD("add original path : %s ", uri);
10177 uri_idx = player->uri_info.uri_idx;
10182 if (check_cnt > num_of_list) {
10183 LOGE("there is no valid uri.");
10187 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10189 if (uri_idx < num_of_list-1) {
10192 if ((count <= 1) && (count != -1)) {
10193 LOGD("no repeat.");
10195 } else if (count > 1) {
10196 /* decrease play count */
10197 /* we succeeded to rewind. update play count and then wait for next EOS */
10200 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10202 /* commit attribute */
10203 if (mmf_attrs_commit(attrs))
10204 LOGE("failed to commit attribute\n");
10207 /* count < 0 : repeat continually */
10211 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10212 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10215 LOGW("next uri does not exist\n");
10219 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10220 LOGE("failed to parse profile\n");
10224 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10225 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10226 LOGW("uri type is not supported(%d).", profile.uri_type);
10233 player->uri_info.uri_idx = uri_idx;
10234 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10236 if (mmf_attrs_commit(player->attrs)) {
10237 LOGE("failed to commit.\n");
10241 LOGD("next uri %s(%d)\n", uri, uri_idx);
10247 LOGE("unable to play next path. EOS will be posted soon.\n");
10252 __mmplayer_initialize_next_play(mm_player_t *player)
10258 player->smooth_streaming = FALSE;
10259 player->videodec_linked = 0;
10260 player->audiodec_linked = 0;
10261 player->videosink_linked = 0;
10262 player->audiosink_linked = 0;
10263 player->textsink_linked = 0;
10264 player->is_external_subtitle_present = FALSE;
10265 player->is_external_subtitle_added_now = FALSE;
10266 player->not_supported_codec = MISSING_PLUGIN_NONE;
10267 player->can_support_codec = FOUND_PLUGIN_NONE;
10268 player->pending_seek.is_pending = FALSE;
10269 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10270 player->pending_seek.pos = 0;
10271 player->msg_posted = FALSE;
10272 player->has_many_types = FALSE;
10273 player->no_more_pad = FALSE;
10274 player->not_found_demuxer = 0;
10275 player->seek_state = MMPLAYER_SEEK_NONE;
10276 player->max_audio_channels = 0;
10277 player->is_subtitle_force_drop = FALSE;
10278 player->play_subtitle = FALSE;
10279 player->adjust_subtitle_pos = 0;
10281 player->total_bitrate = 0;
10282 player->total_maximum_bitrate = 0;
10284 _mmplayer_track_initialize(player);
10285 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10287 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10288 player->bitrate[i] = 0;
10289 player->maximum_bitrate[i] = 0;
10292 if (player->v_stream_caps) {
10293 gst_caps_unref(player->v_stream_caps);
10294 player->v_stream_caps = NULL;
10297 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10299 /* clean found parsers */
10300 if (player->parsers) {
10301 GList *parsers = player->parsers;
10302 for (; parsers; parsers = g_list_next(parsers)) {
10303 gchar *name = parsers->data;
10304 MMPLAYER_FREEIF(name);
10306 g_list_free(player->parsers);
10307 player->parsers = NULL;
10310 /* clean found audio decoders */
10311 if (player->audio_decoders) {
10312 GList *a_dec = player->audio_decoders;
10313 for (; a_dec; a_dec = g_list_next(a_dec)) {
10314 gchar *name = a_dec->data;
10315 MMPLAYER_FREEIF(name);
10317 g_list_free(player->audio_decoders);
10318 player->audio_decoders = NULL;
10325 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10327 MMPlayerGstElement *mainbin = NULL;
10328 MMMessageParamType msg_param = {0,};
10329 GstElement *element = NULL;
10330 MMHandleType attrs = 0;
10332 enum MainElementID elemId = MMPLAYER_M_NUM;
10336 if ((player == NULL) ||
10337 (player->pipeline == NULL) ||
10338 (player->pipeline->mainbin == NULL)) {
10339 LOGE("player is null.\n");
10343 mainbin = player->pipeline->mainbin;
10344 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10346 attrs = MMPLAYER_GET_ATTRS(player);
10348 LOGE("fail to get attributes.\n");
10352 /* Initialize Player values */
10353 __mmplayer_initialize_next_play(player);
10355 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10357 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10358 LOGE("failed to parse profile\n");
10359 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10363 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10364 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10365 LOGE("it's dash or hls. not support.");
10366 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10371 switch (player->profile.uri_type) {
10373 case MM_PLAYER_URI_TYPE_FILE:
10375 LOGD("using filesrc for 'file://' handler.\n");
10376 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10377 LOGE("failed to get storage info");
10381 element = gst_element_factory_make("filesrc", "source");
10384 LOGE("failed to create filesrc\n");
10388 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10391 case MM_PLAYER_URI_TYPE_URL_HTTP:
10393 gchar *user_agent, *cookies, **cookie_list;
10394 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10395 user_agent = cookies = NULL;
10396 cookie_list = NULL;
10398 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10400 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10403 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10405 /* get attribute */
10406 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10407 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10409 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10410 LOGD("get timeout from ini\n");
10411 http_timeout = player->ini.http_timeout;
10414 /* get attribute */
10415 SECURE_LOGD("location : %s\n", player->profile.uri);
10416 SECURE_LOGD("cookies : %s\n", cookies);
10417 SECURE_LOGD("user_agent : %s\n", user_agent);
10418 LOGD("timeout : %d\n", http_timeout);
10420 /* setting property to streaming source */
10421 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10422 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10423 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10425 /* parsing cookies */
10426 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10427 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10429 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10433 LOGE("not support uri type %d\n", player->profile.uri_type);
10438 LOGE("no source element was created.\n");
10442 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10443 LOGE("failed to add source element to pipeline\n");
10444 gst_object_unref(GST_OBJECT(element));
10449 /* take source element */
10450 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10451 mainbin[MMPLAYER_M_SRC].gst = element;
10455 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10456 if (player->streamer == NULL) {
10457 player->streamer = __mm_player_streaming_create();
10458 __mm_player_streaming_initialize(player->streamer);
10461 elemId = MMPLAYER_M_TYPEFIND;
10462 element = gst_element_factory_make("typefind", "typefinder");
10463 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10464 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10466 elemId = MMPLAYER_M_AUTOPLUG;
10467 element = __mmplayer_create_decodebin(player);
10470 /* check autoplug element is OK */
10472 LOGE("can not create element(%d)\n", elemId);
10476 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10477 LOGE("failed to add sinkbin to pipeline\n");
10478 gst_object_unref(GST_OBJECT(element));
10483 mainbin[elemId].id = elemId;
10484 mainbin[elemId].gst = element;
10486 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10487 LOGE("Failed to link src - autoplug(or typefind)\n");
10491 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10492 LOGE("Failed to change state of src element\n");
10496 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10497 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10498 LOGE("Failed to change state of decodebin\n");
10502 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10503 LOGE("Failed to change state of src element\n");
10508 player->gapless.stream_changed = TRUE;
10509 player->gapless.running = TRUE;
10515 MMPLAYER_PLAYBACK_UNLOCK(player);
10517 if (!player->msg_posted) {
10518 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10519 player->msg_posted = TRUE;
10526 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10528 mm_player_selector_t *selector = &player->selector[type];
10529 MMPlayerGstElement *sinkbin = NULL;
10530 enum MainElementID selectorId = MMPLAYER_M_NUM;
10531 enum MainElementID sinkId = MMPLAYER_M_NUM;
10532 GstPad *srcpad = NULL;
10533 GstPad *sinkpad = NULL;
10534 gboolean send_notice = FALSE;
10537 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10539 LOGD("type %d", type);
10542 case MM_PLAYER_TRACK_TYPE_AUDIO:
10543 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10544 sinkId = MMPLAYER_A_BIN;
10545 sinkbin = player->pipeline->audiobin;
10547 case MM_PLAYER_TRACK_TYPE_VIDEO:
10548 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10549 sinkId = MMPLAYER_V_BIN;
10550 sinkbin = player->pipeline->videobin;
10551 send_notice = TRUE;
10553 case MM_PLAYER_TRACK_TYPE_TEXT:
10554 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10555 sinkId = MMPLAYER_T_BIN;
10556 sinkbin = player->pipeline->textbin;
10559 LOGE("requested type is not supportable");
10564 if (player->pipeline->mainbin[selectorId].gst) {
10567 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10569 if (selector->event_probe_id != 0)
10570 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10571 selector->event_probe_id = 0;
10573 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10574 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10576 if (srcpad && sinkpad) {
10577 /* after getting drained signal there is no data flows, so no need to do pad_block */
10578 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10579 gst_pad_unlink(srcpad, sinkpad);
10581 /* send custom event to sink pad to handle it at video sink */
10583 LOGD("send custom event to sinkpad");
10584 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10585 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10586 gst_pad_send_event(sinkpad, event);
10590 gst_object_unref(sinkpad);
10593 gst_object_unref(srcpad);
10596 LOGD("selector release");
10598 /* release and unref requests pad from the selector */
10599 for (n = 0; n < selector->channels->len; n++) {
10600 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10601 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10603 g_ptr_array_set_size(selector->channels, 0);
10605 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10606 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10608 player->pipeline->mainbin[selectorId].gst = NULL;
10616 __mmplayer_deactivate_old_path(mm_player_t *player)
10619 MMPLAYER_RETURN_IF_FAIL(player);
10621 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10622 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10623 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10624 LOGE("deactivate selector error");
10628 _mmplayer_track_destroy(player);
10629 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10631 if (player->streamer) {
10632 __mm_player_streaming_deinitialize(player->streamer);
10633 __mm_player_streaming_destroy(player->streamer);
10634 player->streamer = NULL;
10637 MMPLAYER_PLAYBACK_LOCK(player);
10638 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10645 if (!player->msg_posted) {
10646 MMMessageParamType msg = {0,};
10649 msg.code = MM_ERROR_PLAYER_INTERNAL;
10650 LOGE("next_uri_play> deactivate error");
10652 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10653 player->msg_posted = TRUE;
10658 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10660 int result = MM_ERROR_NONE;
10661 mm_player_t* player = (mm_player_t*) hplayer;
10664 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10667 player->http_file_buffering_path = (gchar*)file_path;
10668 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10674 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10676 int result = MM_ERROR_NONE;
10677 mm_player_t* player = (mm_player_t*) hplayer;
10680 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10682 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10683 if (mmf_attrs_commit(player->attrs)) {
10684 LOGE("failed to commit the original uri.\n");
10685 result = MM_ERROR_PLAYER_INTERNAL;
10687 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10688 LOGE("failed to add the original uri in the uri list.\n");
10695 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10697 mm_player_t* player = (mm_player_t*) hplayer;
10698 guint num_of_list = 0;
10702 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10703 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10705 if (player->pipeline && player->pipeline->textbin) {
10706 LOGE("subtitle path is enabled.\n");
10707 return MM_ERROR_PLAYER_INVALID_STATE;
10710 num_of_list = g_list_length(player->uri_info.uri_list);
10712 if (is_first_path == TRUE) {
10713 if (num_of_list == 0) {
10714 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10715 LOGD("add original path : %s", uri);
10717 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10718 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10720 LOGD("change original path : %s", uri);
10723 MMHandleType attrs = 0;
10724 attrs = MMPLAYER_GET_ATTRS(player);
10726 if (num_of_list == 0) {
10727 char *original_uri = NULL;
10730 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10732 if (!original_uri) {
10733 LOGE("there is no original uri.");
10734 return MM_ERROR_PLAYER_INVALID_STATE;
10737 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10738 player->uri_info.uri_idx = 0;
10740 LOGD("add original path at first : %s(%d)", original_uri);
10744 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10745 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10749 return MM_ERROR_NONE;
10752 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10754 mm_player_t* player = (mm_player_t*) hplayer;
10755 char *next_uri = NULL;
10756 guint num_of_list = 0;
10759 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10761 num_of_list = g_list_length(player->uri_info.uri_list);
10763 if (num_of_list > 0) {
10764 gint uri_idx = player->uri_info.uri_idx;
10766 if (uri_idx < num_of_list-1)
10771 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10772 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10774 *uri = g_strdup(next_uri);
10778 return MM_ERROR_NONE;
10782 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10783 GstCaps *caps, gpointer data)
10785 mm_player_t* player = (mm_player_t*)data;
10786 const gchar* klass = NULL;
10787 const gchar* mime = NULL;
10788 gchar* caps_str = NULL;
10790 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10791 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10792 caps_str = gst_caps_to_string(caps);
10794 LOGW("unknown type of caps : %s from %s",
10795 caps_str, GST_ELEMENT_NAME(elem));
10797 MMPLAYER_FREEIF(caps_str);
10799 /* There is no available codec. */
10800 __mmplayer_check_not_supported_codec(player, klass, mime);
10804 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10805 GstCaps * caps, gpointer data)
10807 mm_player_t* player = (mm_player_t*)data;
10808 const char* mime = NULL;
10809 gboolean ret = TRUE;
10811 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10812 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10814 if (g_str_has_prefix(mime, "audio")) {
10815 GstStructure* caps_structure = NULL;
10816 gint samplerate = 0;
10818 gchar *caps_str = NULL;
10820 caps_structure = gst_caps_get_structure(caps, 0);
10821 gst_structure_get_int(caps_structure, "rate", &samplerate);
10822 gst_structure_get_int(caps_structure, "channels", &channels);
10824 if ((channels > 0 && samplerate == 0)) {
10825 LOGD("exclude audio...");
10829 caps_str = gst_caps_to_string(caps);
10830 /* set it directly because not sent by TAG */
10831 if (g_strrstr(caps_str, "mobile-xmf"))
10832 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10833 MMPLAYER_FREEIF(caps_str);
10834 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10835 MMMessageParamType msg_param;
10836 memset(&msg_param, 0, sizeof(MMMessageParamType));
10837 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10838 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10839 LOGD("video file is not supported on this device");
10841 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10842 LOGD("already video linked");
10845 LOGD("found new stream");
10852 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10854 int ret = MM_ERROR_NONE;
10856 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10858 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10859 GstStructure* str = NULL;
10861 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10863 LOGD("audio codec type: %d", codec_type);
10864 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10865 /* sw codec will be skipped */
10866 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10867 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10868 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10869 ret = MM_ERROR_PLAYER_INTERNAL;
10873 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10874 /* hw codec will be skipped */
10875 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10876 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10877 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10878 ret = MM_ERROR_PLAYER_INTERNAL;
10883 str = gst_caps_get_structure(caps, 0);
10885 gst_structure_get_int(str, "channels", &channels);
10887 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10888 if (player->max_audio_channels < channels)
10889 player->max_audio_channels = channels;
10891 /* set stream information */
10892 if (!player->audiodec_linked)
10893 __mmplayer_set_audio_attrs(player, caps);
10895 /* update codec info */
10896 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10897 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10898 player->audiodec_linked = 1;
10900 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10902 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10904 LOGD("video codec type: %d", codec_type);
10905 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10906 /* sw codec is skipped */
10907 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10908 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10909 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10910 ret = MM_ERROR_PLAYER_INTERNAL;
10914 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10915 /* hw codec is skipped */
10916 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10917 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10918 ret = MM_ERROR_PLAYER_INTERNAL;
10923 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10924 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10926 /* mark video decoder for acquire */
10927 if (player->video_decoder_resource == NULL) {
10928 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10929 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10930 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10931 &player->video_decoder_resource)
10932 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10933 LOGE("could not mark video_decoder resource for acquire");
10934 ret = MM_ERROR_PLAYER_INTERNAL;
10938 LOGW("video decoder resource is already acquired, skip it.");
10939 ret = MM_ERROR_PLAYER_INTERNAL;
10943 player->interrupted_by_resource = FALSE;
10944 /* acquire resources for video playing */
10945 if (mm_resource_manager_commit(player->resource_manager)
10946 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10947 LOGE("could not acquire resources for video decoding\n");
10948 ret = MM_ERROR_PLAYER_INTERNAL;
10953 /* update codec info */
10954 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10955 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10956 player->videodec_linked = 1;
10964 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10965 GstCaps* caps, GstElementFactory* factory, gpointer data)
10967 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10968 We are defining our own and will be removed when it actually exposed */
10970 GST_AUTOPLUG_SELECT_TRY,
10971 GST_AUTOPLUG_SELECT_EXPOSE,
10972 GST_AUTOPLUG_SELECT_SKIP
10973 } GstAutoplugSelectResult;
10975 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10976 mm_player_t* player = (mm_player_t*)data;
10978 gchar* factory_name = NULL;
10979 gchar* caps_str = NULL;
10980 const gchar* klass = NULL;
10983 factory_name = GST_OBJECT_NAME(factory);
10984 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10985 caps_str = gst_caps_to_string(caps);
10987 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10989 /* store type string */
10990 if (player->type == NULL) {
10991 player->type = gst_caps_to_string(caps);
10992 __mmplayer_update_content_type_info(player);
10995 /* filtering exclude keyword */
10996 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10997 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10998 LOGW("skipping [%s] by exculde keyword [%s]\n",
10999 factory_name, player->ini.exclude_element_keyword[idx]);
11001 result = GST_AUTOPLUG_SELECT_SKIP;
11006 /* exclude webm format */
11007 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11008 * because webm format is not supportable.
11009 * If webm is disabled in "autoplug-continue", there is no state change
11010 * failure or error because the decodebin will expose the pad directly.
11011 * It make MSL invoke _prepare_async_callback.
11012 * So, we need to disable webm format in "autoplug-select" */
11013 if (caps_str && strstr(caps_str, "webm")) {
11014 LOGW("webm is not supported");
11015 result = GST_AUTOPLUG_SELECT_SKIP;
11019 /* check factory class for filtering */
11020 /* NOTE : msl don't need to use image plugins.
11021 * So, those plugins should be skipped for error handling.
11023 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11024 LOGD("skipping [%s] by not required\n", factory_name);
11025 result = GST_AUTOPLUG_SELECT_SKIP;
11029 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11030 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11031 // TO CHECK : subtitle if needed, add subparse exception.
11032 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11033 result = GST_AUTOPLUG_SELECT_SKIP;
11037 if (g_strrstr(factory_name, "mpegpsdemux")) {
11038 LOGD("skipping PS container - not support\n");
11039 result = GST_AUTOPLUG_SELECT_SKIP;
11043 if (g_strrstr(factory_name, "mssdemux"))
11044 player->smooth_streaming = TRUE;
11046 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11047 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11050 GstStructure *str = NULL;
11051 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11053 /* don't make video because of not required */
11054 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11055 (player->set_mode.media_packet_video_stream == FALSE)) {
11056 LOGD("no video because it's not required. -> return expose");
11057 result = GST_AUTOPLUG_SELECT_EXPOSE;
11061 /* get w/h for omx state-tune */
11062 /* FIXME: deprecated? */
11063 str = gst_caps_get_structure(caps, 0);
11064 gst_structure_get_int(str, "width", &width);
11067 if (player->v_stream_caps) {
11068 gst_caps_unref(player->v_stream_caps);
11069 player->v_stream_caps = NULL;
11072 player->v_stream_caps = gst_caps_copy(caps);
11073 LOGD("take caps for video state tune");
11074 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11078 if (g_strrstr(klass, "Codec/Decoder")) {
11079 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11080 LOGD("skipping %s codec", factory_name);
11081 result = GST_AUTOPLUG_SELECT_SKIP;
11087 MMPLAYER_FREEIF(caps_str);
11093 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11096 //mm_player_t* player = (mm_player_t*)data;
11097 GstCaps* caps = NULL;
11099 LOGD("[Decodebin2] pad-removed signal\n");
11101 caps = gst_pad_query_caps(new_pad, NULL);
11103 gchar* caps_str = NULL;
11104 caps_str = gst_caps_to_string(caps);
11106 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11108 MMPLAYER_FREEIF(caps_str);
11109 gst_caps_unref(caps);
11114 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11116 mm_player_t* player = (mm_player_t*)data;
11117 GstIterator *iter = NULL;
11118 GValue item = { 0, };
11119 GstPad *pad = NULL;
11120 gboolean done = FALSE;
11121 gboolean is_all_drained = TRUE;
11124 MMPLAYER_RETURN_IF_FAIL(player);
11126 LOGD("__mmplayer_gst_decode_drained");
11128 if (player->use_deinterleave == TRUE) {
11129 LOGD("group playing mode.");
11133 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11134 LOGW("Fail to get cmd lock");
11138 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11139 !__mmplayer_verify_next_play_path(player)) {
11140 LOGD("decoding is finished.");
11141 __mmplayer_reset_gapless_state(player);
11142 MMPLAYER_CMD_UNLOCK(player);
11146 player->gapless.reconfigure = TRUE;
11148 /* check decodebin src pads whether they received EOS or not */
11149 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11152 switch (gst_iterator_next(iter, &item)) {
11153 case GST_ITERATOR_OK:
11154 pad = g_value_get_object(&item);
11155 if (pad && !GST_PAD_IS_EOS(pad)) {
11156 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11157 is_all_drained = FALSE;
11160 g_value_reset(&item);
11162 case GST_ITERATOR_RESYNC:
11163 gst_iterator_resync(iter);
11165 case GST_ITERATOR_ERROR:
11166 case GST_ITERATOR_DONE:
11171 g_value_unset(&item);
11172 gst_iterator_free(iter);
11174 if (!is_all_drained) {
11175 LOGD("Wait util the all pads get EOS.");
11176 MMPLAYER_CMD_UNLOCK(player);
11181 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11182 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11184 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11185 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11186 __mmplayer_deactivate_old_path(player);
11187 MMPLAYER_CMD_UNLOCK(player);
11193 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11195 mm_player_t* player = (mm_player_t*)data;
11196 const gchar* klass = NULL;
11197 gchar* factory_name = NULL;
11199 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11200 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11202 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11204 if (__mmplayer_add_dump_buffer_probe(player, element))
11205 LOGD("add buffer probe");
11208 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11209 gchar* selected = NULL;
11210 selected = g_strdup(GST_ELEMENT_NAME(element));
11211 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11215 if (g_strrstr(klass, "Parser")) {
11216 gchar* selected = NULL;
11218 selected = g_strdup(factory_name);
11219 player->parsers = g_list_append(player->parsers, selected);
11222 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11223 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11224 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11226 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11227 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11229 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11230 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11231 "max-video-width", player->adaptive_info.limit.width,
11232 "max-video-height", player->adaptive_info.limit.height, NULL);
11234 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11235 /* FIXIT : first value will be overwritten if there's more
11236 * than 1 demuxer/parser
11239 //LOGD("plugged element is demuxer. take it\n");
11240 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11241 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11243 /*Added for multi audio support */ // Q. del?
11244 if (g_strrstr(klass, "Demux")) {
11245 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11246 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11250 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11251 int surface_type = 0;
11253 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11256 // to support trust-zone only
11257 if (g_strrstr(factory_name, "asfdemux")) {
11258 LOGD("set file-location %s\n", player->profile.uri);
11259 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11261 if (player->video_hub_download_mode == TRUE)
11262 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11263 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11264 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11265 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11266 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11267 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11268 (__mmplayer_is_only_mp3_type(player->type))) {
11269 LOGD("[mpegaudioparse] set streaming pull mode.");
11270 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11272 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11273 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11276 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11277 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11278 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11280 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11281 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11283 if (!MMPLAYER_IS_HTTP_PD(player) &&
11284 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11285 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11286 (MMPLAYER_IS_DASH_STREAMING(player)))) {
11287 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11288 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11289 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11297 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11300 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11302 if (MMPLAYER_IS_STREAMING(player))
11305 /* This callback can be set to music player only. */
11306 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11307 LOGW("audio callback is not supported for video");
11311 if (player->audio_stream_cb) {
11312 GstPad *pad = NULL;
11314 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11317 LOGE("failed to get sink pad from audiosink to probe data\n");
11320 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11321 __mmplayer_audio_stream_probe, player, NULL);
11323 gst_object_unref(pad);
11327 LOGE("There is no audio callback to configure.\n");
11337 __mmplayer_release_misc(mm_player_t* player)
11340 bool cur_mode = player->set_mode.rich_audio;
11343 MMPLAYER_RETURN_IF_FAIL(player);
11345 player->video_stream_cb = NULL;
11346 player->video_stream_cb_user_param = NULL;
11347 player->video_stream_prerolled = FALSE;
11349 player->audio_stream_cb = NULL;
11350 player->audio_stream_render_cb_ex = NULL;
11351 player->audio_stream_cb_user_param = NULL;
11352 player->audio_stream_sink_sync = false;
11354 player->video_stream_changed_cb = NULL;
11355 player->video_stream_changed_cb_user_param = NULL;
11357 player->audio_stream_changed_cb = NULL;
11358 player->audio_stream_changed_cb_user_param = NULL;
11360 player->sent_bos = FALSE;
11361 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11363 player->seek_state = MMPLAYER_SEEK_NONE;
11365 player->total_bitrate = 0;
11366 player->total_maximum_bitrate = 0;
11368 player->not_found_demuxer = 0;
11370 player->last_position = 0;
11371 player->duration = 0;
11372 player->http_content_size = 0;
11373 player->not_supported_codec = MISSING_PLUGIN_NONE;
11374 player->can_support_codec = FOUND_PLUGIN_NONE;
11375 player->pending_seek.is_pending = FALSE;
11376 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11377 player->pending_seek.pos = 0;
11378 player->msg_posted = FALSE;
11379 player->has_many_types = FALSE;
11380 player->max_audio_channels = 0;
11381 player->video_share_api_delta = 0;
11382 player->video_share_clock_delta = 0;
11383 player->is_subtitle_force_drop = FALSE;
11384 player->play_subtitle = FALSE;
11385 player->adjust_subtitle_pos = 0;
11386 player->last_multiwin_status = FALSE;
11387 player->has_closed_caption = FALSE;
11388 player->set_mode.media_packet_video_stream = FALSE;
11389 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11390 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11392 player->set_mode.rich_audio = cur_mode;
11394 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11395 player->bitrate[i] = 0;
11396 player->maximum_bitrate[i] = 0;
11399 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11401 /* remove media stream cb(appsrc cb) */
11402 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11403 player->media_stream_buffer_status_cb[i] = NULL;
11404 player->media_stream_seek_data_cb[i] = NULL;
11405 player->buffer_cb_user_param[i] = NULL;
11406 player->seek_cb_user_param[i] = NULL;
11408 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11410 /* free memory related to audio effect */
11411 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11413 if (player->adaptive_info.var_list) {
11414 g_list_free_full(player->adaptive_info.var_list, g_free);
11415 player->adaptive_info.var_list = NULL;
11418 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11419 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11420 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11422 /* Reset video360 settings to their defaults in case if the pipeline is to be
11425 player->video360_metadata.is_spherical = -1;
11426 player->is_openal_plugin_used = FALSE;
11428 player->is_content_spherical = FALSE;
11429 player->is_video360_enabled = TRUE;
11430 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11431 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11432 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11433 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11434 player->video360_zoom = 1.0f;
11435 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11436 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11438 player->sound.rg_enable = false;
11444 __mmplayer_release_misc_post(mm_player_t* player)
11446 char *original_uri = NULL;
11449 /* player->pipeline is already released before. */
11451 MMPLAYER_RETURN_IF_FAIL(player);
11453 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11455 /* clean found parsers */
11456 if (player->parsers) {
11457 GList *parsers = player->parsers;
11458 for (; parsers; parsers = g_list_next(parsers)) {
11459 gchar *name = parsers->data;
11460 MMPLAYER_FREEIF(name);
11462 g_list_free(player->parsers);
11463 player->parsers = NULL;
11466 /* clean found audio decoders */
11467 if (player->audio_decoders) {
11468 GList *a_dec = player->audio_decoders;
11469 for (; a_dec; a_dec = g_list_next(a_dec)) {
11470 gchar *name = a_dec->data;
11471 MMPLAYER_FREEIF(name);
11473 g_list_free(player->audio_decoders);
11474 player->audio_decoders = NULL;
11477 /* clean the uri list except original uri */
11478 if (player->uri_info.uri_list) {
11479 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11481 if (player->attrs) {
11482 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11483 LOGD("restore original uri = %s\n", original_uri);
11485 if (mmf_attrs_commit(player->attrs))
11486 LOGE("failed to commit the original uri.\n");
11489 GList *uri_list = player->uri_info.uri_list;
11490 for (; uri_list; uri_list = g_list_next(uri_list)) {
11491 gchar *uri = uri_list->data;
11492 MMPLAYER_FREEIF(uri);
11494 g_list_free(player->uri_info.uri_list);
11495 player->uri_info.uri_list = NULL;
11498 /* clear the audio stream buffer list */
11499 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11501 /* clear the video stream bo list */
11502 __mmplayer_video_stream_destroy_bo_list(player);
11503 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11505 if (player->profile.input_mem.buf) {
11506 free(player->profile.input_mem.buf);
11507 player->profile.input_mem.buf = NULL;
11509 player->profile.input_mem.len = 0;
11510 player->profile.input_mem.offset = 0;
11512 player->uri_info.uri_idx = 0;
11516 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11518 GstElement *element = NULL;
11521 LOGD("creating %s to plug\n", name);
11523 element = gst_element_factory_make(name, NULL);
11525 LOGE("failed to create queue\n");
11529 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11530 LOGE("failed to set state READY to %s\n", name);
11531 gst_object_unref(element);
11535 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11536 LOGE("failed to add %s\n", name);
11537 gst_object_unref(element);
11541 sinkpad = gst_element_get_static_pad(element, "sink");
11543 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11544 LOGE("failed to link %s\n", name);
11545 gst_object_unref(sinkpad);
11546 gst_object_unref(element);
11550 LOGD("linked %s to pipeline successfully\n", name);
11552 gst_object_unref(sinkpad);
11558 __mmplayer_check_subtitle(mm_player_t* player)
11560 MMHandleType attrs = 0;
11561 char *subtitle_uri = NULL;
11565 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11567 /* get subtitle attribute */
11568 attrs = MMPLAYER_GET_ATTRS(player);
11572 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11573 if (!subtitle_uri || !strlen(subtitle_uri))
11576 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11577 player->is_external_subtitle_present = TRUE;
11585 __mmplayer_can_extract_pcm(mm_player_t* player)
11587 MMHandleType attrs = 0;
11588 gboolean sound_extraction = FALSE;
11590 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11592 attrs = MMPLAYER_GET_ATTRS(player);
11594 LOGE("fail to get attributes.");
11598 /* get sound_extraction property */
11599 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11601 if (!sound_extraction) {
11602 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11610 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11613 MMMessageParamType msg_param;
11614 gchar *msg_src_element = NULL;
11615 GstStructure *s = NULL;
11616 guint error_id = 0;
11617 gchar *error_string = NULL;
11621 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11622 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11624 s = gst_structure_copy(gst_message_get_structure(message));
11627 if (!gst_structure_get_uint(s, "error_id", &error_id))
11628 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11630 switch (error_id) {
11631 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11632 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11634 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11635 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11637 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11638 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11640 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11641 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11643 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11644 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11646 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11647 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11649 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11650 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11652 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11653 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11655 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11656 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11658 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11659 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11661 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11662 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11664 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11665 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11667 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11668 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11670 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11671 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11673 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11674 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11676 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11677 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11679 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11680 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11682 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11683 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11685 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11686 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11688 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11689 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11691 case MMPLAYER_STREAMING_ERROR_GONE:
11692 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11694 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11695 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11697 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11698 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11700 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11701 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11703 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11704 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11706 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11707 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11709 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11710 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11712 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11713 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11715 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11716 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11718 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11719 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11721 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11722 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11724 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11725 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11727 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11728 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11730 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11731 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11733 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11734 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11736 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11737 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11739 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11740 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11742 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11743 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11745 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11746 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11748 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11749 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11751 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11752 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11754 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11755 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11757 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11758 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11760 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11761 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11763 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11764 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11768 gst_structure_free(s);
11769 return MM_ERROR_PLAYER_STREAMING_FAIL;
11773 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11775 msg_param.data = (void *) error_string;
11777 if (message->src) {
11778 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11780 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11781 msg_src_element, msg_param.code, (char*)msg_param.data);
11784 /* post error to application */
11785 if (!player->msg_posted) {
11786 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11788 /* don't post more if one was sent already */
11789 player->msg_posted = TRUE;
11791 LOGD("skip error post because it's sent already.\n");
11793 gst_structure_free(s);
11795 g_free(error_string);
11802 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11804 MMPLAYER_RETURN_IF_FAIL(player);
11806 /* post now if delay is zero */
11807 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11808 LOGD("eos delay is zero. posting EOS now\n");
11809 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11811 if (player->set_mode.pcm_extraction)
11812 __mmplayer_cancel_eos_timer(player);
11817 /* cancel if existing */
11818 __mmplayer_cancel_eos_timer(player);
11820 /* init new timeout */
11821 /* NOTE : consider give high priority to this timer */
11822 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11824 player->eos_timer = g_timeout_add(delay_in_ms,
11825 __mmplayer_eos_timer_cb, player);
11827 player->context.global_default = g_main_context_default();
11828 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11830 /* check timer is valid. if not, send EOS now */
11831 if (player->eos_timer == 0) {
11832 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11833 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11838 __mmplayer_cancel_eos_timer(mm_player_t* player)
11840 MMPLAYER_RETURN_IF_FAIL(player);
11842 if (player->eos_timer) {
11843 LOGD("cancel eos timer");
11844 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11845 player->eos_timer = 0;
11852 __mmplayer_eos_timer_cb(gpointer u_data)
11854 mm_player_t* player = NULL;
11855 MMHandleType attrs = 0;
11858 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11860 player = (mm_player_t*) u_data;
11861 attrs = MMPLAYER_GET_ATTRS(player);
11863 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11866 gint ret_value = 0;
11867 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11868 if (ret_value != MM_ERROR_NONE)
11869 LOGE("seeking to 0 failed in repeat play");
11872 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11875 /* we are returning FALSE as we need only one posting */
11879 /* sending event to one of sinkelements */
11881 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11883 GstEvent * event2 = NULL;
11884 GList *sinks = NULL;
11885 gboolean res = FALSE;
11888 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11889 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11891 /* While adding subtitles in live feeds seek is getting called.
11892 Adding defensive check in framework layer.*/
11893 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11894 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11895 LOGE("Should not send seek event during live playback");
11900 if (player->play_subtitle)
11901 event2 = gst_event_copy((const GstEvent *)event);
11903 sinks = player->sink_elements;
11905 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11907 if (GST_IS_ELEMENT(sink)) {
11908 /* keep ref to the event */
11909 gst_event_ref(event);
11911 if ((res = gst_element_send_event(sink, event))) {
11912 LOGD("sending event[%s] to sink element [%s] success!\n",
11913 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11915 /* rtsp case, asyn_done is not called after seek during pause state */
11916 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11917 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11918 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11919 LOGD("RTSP seek completed, after pause state..\n");
11920 player->seek_state = MMPLAYER_SEEK_NONE;
11921 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11927 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11928 sinks = g_list_next(sinks);
11935 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11936 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11939 sinks = g_list_next(sinks);
11942 /* Note : Textbin is not linked to the video or audio bin.
11943 * It needs to send the event to the text sink seperatelly.
11945 if (player->play_subtitle && player->pipeline) {
11946 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11948 if (GST_IS_ELEMENT(text_sink)) {
11949 /* keep ref to the event */
11950 gst_event_ref(event2);
11952 if ((res = gst_element_send_event(text_sink, event2)))
11953 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11954 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11956 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11957 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11959 gst_event_unref(event2);
11963 gst_event_unref(event);
11971 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11975 MMPLAYER_RETURN_IF_FAIL(player);
11976 MMPLAYER_RETURN_IF_FAIL(sink);
11978 player->sink_elements =
11979 g_list_append(player->sink_elements, sink);
11985 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11989 MMPLAYER_RETURN_IF_FAIL(player);
11990 MMPLAYER_RETURN_IF_FAIL(sink);
11992 player->sink_elements =
11993 g_list_remove(player->sink_elements, sink);
11999 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
12000 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
12001 gint64 cur, GstSeekType stop_type, gint64 stop)
12003 GstEvent* event = NULL;
12004 gboolean result = FALSE;
12008 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12010 if (player->pipeline && player->pipeline->textbin)
12011 __mmplayer_drop_subtitle(player, FALSE);
12013 event = gst_event_new_seek(rate, format, flags, cur_type,
12014 cur, stop_type, stop);
12016 result = __gst_send_event_to_sink(player, event);
12023 /* NOTE : be careful with calling this api. please refer to below glib comment
12024 * glib comment : Note that there is a bug in GObject that makes this function much
12025 * less useful than it might seem otherwise. Once gobject is disposed, the callback
12026 * will no longer be called, but, the signal handler is not currently disconnected.
12027 * If the instance is itself being freed at the same time than this doesn't matter,
12028 * since the signal will automatically be removed, but if instance persists,
12029 * then the signal handler will leak. You should not remove the signal yourself
12030 * because in a future versions of GObject, the handler will automatically be
12033 * It's possible to work around this problem in a way that will continue to work
12034 * with future versions of GObject by checking that the signal handler is still
12035 * connected before disconnected it:
12037 * if (g_signal_handler_is_connected(instance, id))
12038 * g_signal_handler_disconnect(instance, id);
12041 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12043 GList* sig_list = NULL;
12044 MMPlayerSignalItem* item = NULL;
12048 MMPLAYER_RETURN_IF_FAIL(player);
12050 LOGD("release signals type : %d", type);
12052 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12053 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12054 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12055 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12056 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12057 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12061 sig_list = player->signals[type];
12063 for (; sig_list; sig_list = sig_list->next) {
12064 item = sig_list->data;
12066 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12067 if (g_signal_handler_is_connected(item->obj, item->sig))
12068 g_signal_handler_disconnect(item->obj, item->sig);
12071 MMPLAYER_FREEIF(item);
12074 g_list_free(player->signals[type]);
12075 player->signals[type] = NULL;
12082 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12084 mm_player_t* player = 0;
12085 int prev_display_surface_type = 0;
12086 void *prev_display_overlay = NULL;
12087 const gchar *klass = NULL;
12088 gchar *cur_videosink_name = NULL;
12091 int num_of_dec = 2; /* DEC1, DEC2 */
12095 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12096 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12098 player = MM_PLAYER_CAST(handle);
12100 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12101 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12103 return MM_ERROR_INVALID_ARGUMENT;
12106 /* load previous attributes */
12107 if (player->attrs) {
12108 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12109 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12110 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12111 if (prev_display_surface_type == surface_type) {
12112 LOGD("incoming display surface type is same as previous one, do nothing..");
12114 return MM_ERROR_NONE;
12117 LOGE("failed to load attributes");
12119 return MM_ERROR_PLAYER_INTERNAL;
12122 /* check videosink element is created */
12123 if (!player->pipeline || !player->pipeline->videobin ||
12124 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12125 LOGD("videosink element is not yet ready");
12127 /* videobin is not created yet, so we just set attributes related to display surface */
12128 LOGD("store display attribute for given surface type(%d)", surface_type);
12129 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12130 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12131 if (mmf_attrs_commit(player->attrs)) {
12132 LOGE("failed to commit attribute");
12134 return MM_ERROR_PLAYER_INTERNAL;
12137 return MM_ERROR_NONE;
12139 /* get player command status */
12140 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12141 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12143 return MM_ERROR_PLAYER_INVALID_STATE;
12146 /* surface change */
12147 for (i = 0 ; i < num_of_dec ; i++) {
12148 if (player->pipeline->mainbin &&
12149 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12150 GstElementFactory *decfactory;
12151 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12153 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12154 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12155 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12156 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12160 LOGW("success to changing display surface(%d)", surface_type);
12162 return MM_ERROR_NONE;
12164 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12165 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12169 LOGW("success to changing display surface(%d)", surface_type);
12171 return MM_ERROR_NONE;
12174 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12175 ret = MM_ERROR_PLAYER_INTERNAL;
12184 /* rollback to previous attributes */
12185 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12186 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12187 if (mmf_attrs_commit(player->attrs)) {
12188 LOGE("failed to commit attributes to rollback");
12190 return MM_ERROR_PLAYER_INTERNAL;
12196 /* NOTE : It does not support some use cases, eg using colorspace converter */
12198 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12200 GstPad *src_pad_dec = NULL;
12201 GstPad *sink_pad_videosink = NULL;
12202 GstPad *sink_pad_videobin = NULL;
12203 GstClock *clock = NULL;
12204 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12205 int ret = MM_ERROR_NONE;
12206 gboolean is_audiobin_created = TRUE;
12210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12211 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12212 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12214 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12215 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12217 /* get information whether if audiobin is created */
12218 if (!player->pipeline->audiobin ||
12219 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12220 LOGW("audiobin is null, this video content may not have audio data");
12221 is_audiobin_created = FALSE;
12224 /* get current state of player */
12225 previous_state = MMPLAYER_CURRENT_STATE(player);
12226 LOGD("previous state(%d)", previous_state);
12229 /* get src pad of decoder and block it */
12230 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12231 if (!src_pad_dec) {
12232 LOGE("failed to get src pad from decode in mainbin");
12233 return MM_ERROR_PLAYER_INTERNAL;
12236 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12237 LOGW("trying to block pad(video)");
12238 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12239 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12242 LOGE("failed to set block pad(video)");
12243 return MM_ERROR_PLAYER_INTERNAL;
12245 LOGW("pad is blocked(video)");
12247 /* no data flows, so no need to do pad_block */
12248 if (player->seek_state != MMPLAYER_SEEK_NONE)
12249 LOGW("not completed seek(%d), do nothing", player->seek_state);
12251 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12255 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12256 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12257 LOGE("failed to remove previous ghost_pad for videobin");
12258 return MM_ERROR_PLAYER_INTERNAL;
12261 /* change state of videobin to NULL */
12262 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12263 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12264 if (ret != GST_STATE_CHANGE_SUCCESS) {
12265 LOGE("failed to change state of videobin to NULL");
12266 return MM_ERROR_PLAYER_INTERNAL;
12269 /* unlink between decoder and videobin and remove previous videosink from videobin */
12270 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12271 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12272 LOGE("failed to remove former videosink from videobin");
12273 return MM_ERROR_PLAYER_INTERNAL;
12276 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12278 /* create a new videosink and add it to videobin */
12279 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12280 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12281 LOGE("failed to create videosink element\n");
12283 return MM_ERROR_PLAYER_INTERNAL;
12285 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12286 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12287 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12289 /* save attributes */
12290 if (player->attrs) {
12291 /* set a new display surface type */
12292 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12293 /* set a new diplay overlay */
12294 switch (surface_type) {
12295 case MM_DISPLAY_SURFACE_OVERLAY:
12296 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12297 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12300 LOGE("invalid type(%d) for changing display surface", surface_type);
12302 return MM_ERROR_INVALID_ARGUMENT;
12304 if (mmf_attrs_commit(player->attrs)) {
12305 LOGE("failed to commit");
12307 return MM_ERROR_PLAYER_INTERNAL;
12310 LOGE("player->attrs is null, failed to save attributes");
12312 return MM_ERROR_PLAYER_INTERNAL;
12315 /* update video param */
12316 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12317 LOGE("failed to update video param");
12318 return MM_ERROR_PLAYER_INTERNAL;
12321 /* change state of videobin to READY */
12322 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12323 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12324 if (ret != GST_STATE_CHANGE_SUCCESS) {
12325 LOGE("failed to change state of videobin to READY");
12326 return MM_ERROR_PLAYER_INTERNAL;
12329 /* change ghostpad */
12330 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12331 if (!sink_pad_videosink) {
12332 LOGE("failed to get sink pad from videosink element");
12333 return MM_ERROR_PLAYER_INTERNAL;
12335 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12336 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12337 LOGE("failed to set active to ghost_pad");
12338 return MM_ERROR_PLAYER_INTERNAL;
12340 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12341 LOGE("failed to change ghostpad for videobin");
12342 return MM_ERROR_PLAYER_INTERNAL;
12344 gst_object_unref(sink_pad_videosink);
12346 /* link decoder with videobin */
12347 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12348 if (!sink_pad_videobin) {
12349 LOGE("failed to get sink pad from videobin");
12350 return MM_ERROR_PLAYER_INTERNAL;
12352 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12353 LOGE("failed to link");
12354 return MM_ERROR_PLAYER_INTERNAL;
12356 gst_object_unref(sink_pad_videobin);
12358 /* clock setting for a new videosink plugin */
12359 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12360 so we set it from audiosink plugin or pipeline(system clock) */
12361 if (!is_audiobin_created) {
12362 LOGW("audiobin is not created, get clock from pipeline..");
12363 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12365 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12369 GstClockTime base_time;
12370 LOGD("set the clock to videosink");
12371 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12372 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12374 LOGD("got clock of videosink");
12375 now = gst_clock_get_time(clock);
12376 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12377 LOGD("at time %" GST_TIME_FORMAT ", base %"
12378 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12380 LOGE("failed to get clock of videosink after setting clock");
12381 return MM_ERROR_PLAYER_INTERNAL;
12384 LOGW("failed to get clock, maybe it is the time before first playing");
12386 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
12387 /* change state of videobin to PAUSED */
12388 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12389 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12390 if (ret != GST_STATE_CHANGE_FAILURE) {
12391 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12393 LOGE("failed to change state of videobin to PLAYING");
12394 return MM_ERROR_PLAYER_INTERNAL;
12397 /* release blocked and unref src pad of video decoder */
12399 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12400 LOGE("failed to set pad blocked FALSE(video)");
12401 return MM_ERROR_PLAYER_INTERNAL;
12404 LOGW("pad is unblocked(video)");
12406 if (player->seek_state != MMPLAYER_SEEK_NONE)
12407 LOGW("not completed seek(%d)", player->seek_state);
12408 /* change state of videobin to PAUSED */
12409 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12410 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12411 if (ret != GST_STATE_CHANGE_FAILURE) {
12412 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12414 LOGE("failed to change state of videobin to PLAYING");
12415 return MM_ERROR_PLAYER_INTERNAL;
12418 /* already skipped pad block */
12419 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12422 /* do get/set position for new videosink plugin */
12424 gint64 position = 0;
12426 LOGD("do get/set position for new videosink plugin");
12427 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12428 LOGE("failed to get position");
12429 return MM_ERROR_PLAYER_INTERNAL;
12431 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12432 /* accurate seek */
12433 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12434 LOGE("failed to set position");
12435 return MM_ERROR_PLAYER_INTERNAL;
12438 /* key unit seek */
12439 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12440 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12441 GST_SEEK_TYPE_SET, position,
12442 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12444 LOGE("failed to set position");
12445 return MM_ERROR_PLAYER_INTERNAL;
12451 gst_object_unref(src_pad_dec);
12452 LOGD("success to change sink");
12456 return MM_ERROR_NONE;
12460 /* Note : if silent is true, then subtitle would not be displayed. :*/
12461 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12463 mm_player_t* player = (mm_player_t*) hplayer;
12467 /* check player handle */
12468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12470 player->set_mode.subtitle_off = silent;
12472 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12476 return MM_ERROR_NONE;
12479 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12481 MMPlayerGstElement* mainbin = NULL;
12482 MMPlayerGstElement* textbin = NULL;
12483 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12484 GstState current_state = GST_STATE_VOID_PENDING;
12485 GstState element_state = GST_STATE_VOID_PENDING;
12486 GstState element_pending_state = GST_STATE_VOID_PENDING;
12488 GstEvent *event = NULL;
12489 int result = MM_ERROR_NONE;
12491 GstClock *curr_clock = NULL;
12492 GstClockTime base_time, start_time, curr_time;
12497 /* check player handle */
12498 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12499 player->pipeline &&
12500 player->pipeline->mainbin &&
12501 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12503 mainbin = player->pipeline->mainbin;
12504 textbin = player->pipeline->textbin;
12506 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12508 // sync clock with current pipeline
12509 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12510 curr_time = gst_clock_get_time(curr_clock);
12512 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12513 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12515 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12516 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12518 if (current_state > GST_STATE_READY) {
12519 // sync state with current pipeline
12520 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12521 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12522 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12524 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12525 if (GST_STATE_CHANGE_FAILURE == ret) {
12526 LOGE("fail to state change.\n");
12527 result = MM_ERROR_PLAYER_INTERNAL;
12532 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12533 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12536 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12537 gst_object_unref(curr_clock);
12540 // seek to current position
12541 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12542 result = MM_ERROR_PLAYER_INVALID_STATE;
12543 LOGE("gst_element_query_position failed, invalid state\n");
12547 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12548 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);
12550 __gst_send_event_to_sink(player, event);
12552 result = MM_ERROR_PLAYER_INTERNAL;
12553 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12557 /* sync state with current pipeline */
12558 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12559 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12560 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12562 return MM_ERROR_NONE;
12565 /* release text pipeline resource */
12566 player->textsink_linked = 0;
12568 /* release signal */
12569 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12571 /* release textbin with it's childs */
12572 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12573 MMPLAYER_FREEIF(player->pipeline->textbin);
12574 player->pipeline->textbin = NULL;
12576 /* release subtitle elem */
12577 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12578 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12584 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12586 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12587 GstState current_state = GST_STATE_VOID_PENDING;
12589 MMHandleType attrs = 0;
12590 MMPlayerGstElement* mainbin = NULL;
12591 MMPlayerGstElement* textbin = NULL;
12593 gchar* subtitle_uri = NULL;
12594 int result = MM_ERROR_NONE;
12595 const gchar *charset = NULL;
12599 /* check player handle */
12600 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12601 player->pipeline &&
12602 player->pipeline->mainbin &&
12603 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12604 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12606 mainbin = player->pipeline->mainbin;
12607 textbin = player->pipeline->textbin;
12609 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12610 if (current_state < GST_STATE_READY) {
12611 result = MM_ERROR_PLAYER_INVALID_STATE;
12612 LOGE("Pipeline is not in proper state\n");
12616 attrs = MMPLAYER_GET_ATTRS(player);
12618 LOGE("cannot get content attribute\n");
12619 result = MM_ERROR_PLAYER_INTERNAL;
12623 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12624 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12625 LOGE("subtitle uri is not proper filepath\n");
12626 result = MM_ERROR_PLAYER_INVALID_URI;
12630 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12631 LOGE("failed to get storage info of subtitle path");
12632 result = MM_ERROR_PLAYER_INVALID_URI;
12636 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12637 LOGD("new subtitle file path is [%s]\n", filepath);
12639 if (!strcmp(filepath, subtitle_uri)) {
12640 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12643 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12644 if (mmf_attrs_commit(player->attrs)) {
12645 LOGE("failed to commit.\n");
12650 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12651 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12652 player->subtitle_language_list = NULL;
12653 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12655 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12656 if (ret != GST_STATE_CHANGE_SUCCESS) {
12657 LOGE("failed to change state of textbin to READY");
12658 result = MM_ERROR_PLAYER_INTERNAL;
12662 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12663 if (ret != GST_STATE_CHANGE_SUCCESS) {
12664 LOGE("failed to change state of subparse to READY");
12665 result = MM_ERROR_PLAYER_INTERNAL;
12669 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12670 if (ret != GST_STATE_CHANGE_SUCCESS) {
12671 LOGE("failed to change state of filesrc to READY");
12672 result = MM_ERROR_PLAYER_INTERNAL;
12676 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12678 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12680 charset = util_get_charset(filepath);
12682 LOGD("detected charset is %s\n", charset);
12683 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12686 result = _mmplayer_sync_subtitle_pipeline(player);
12693 /* API to switch between external subtitles */
12694 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12696 int result = MM_ERROR_NONE;
12697 mm_player_t* player = (mm_player_t*)hplayer;
12702 /* check player handle */
12703 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12705 /* filepath can be null in idle state */
12707 /* check file path */
12708 if ((path = strstr(filepath, "file://")))
12709 result = util_exist_file_path(path + 7);
12711 result = util_exist_file_path(filepath);
12713 if (result != MM_ERROR_NONE) {
12714 LOGE("invalid subtitle path 0x%X", result);
12715 return result; /* file not found or permission denied */
12719 if (!player->pipeline) {
12721 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12722 if (mmf_attrs_commit(player->attrs)) {
12723 LOGE("failed to commit"); /* subtitle path will not be created */
12724 return MM_ERROR_PLAYER_INTERNAL;
12727 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12728 /* check filepath */
12729 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12731 if (!__mmplayer_check_subtitle(player)) {
12732 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12733 if (mmf_attrs_commit(player->attrs)) {
12734 LOGE("failed to commit");
12735 return MM_ERROR_PLAYER_INTERNAL;
12738 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12739 LOGE("fail to create text pipeline");
12740 return MM_ERROR_PLAYER_INTERNAL;
12743 result = _mmplayer_sync_subtitle_pipeline(player);
12745 result = __mmplayer_change_external_subtitle_language(player, filepath);
12748 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12749 player->is_external_subtitle_added_now = TRUE;
12751 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12752 if (!player->subtitle_language_list) {
12753 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12754 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12755 LOGW("subtitle language list is not updated yet");
12757 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12765 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12767 int result = MM_ERROR_NONE;
12768 gchar* change_pad_name = NULL;
12769 GstPad* sinkpad = NULL;
12770 MMPlayerGstElement* mainbin = NULL;
12771 enum MainElementID elemId = MMPLAYER_M_NUM;
12772 GstCaps* caps = NULL;
12773 gint total_track_num = 0;
12777 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12778 MM_ERROR_PLAYER_NOT_INITIALIZED);
12780 LOGD("Change Track(%d) to %d\n", type, index);
12782 mainbin = player->pipeline->mainbin;
12784 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12785 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12786 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12787 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12789 /* Changing Video Track is not supported. */
12790 LOGE("Track Type Error\n");
12794 if (mainbin[elemId].gst == NULL) {
12795 result = MM_ERROR_PLAYER_NO_OP;
12796 LOGD("Req track doesn't exist\n");
12800 total_track_num = player->selector[type].total_track_num;
12801 if (total_track_num <= 0) {
12802 result = MM_ERROR_PLAYER_NO_OP;
12803 LOGD("Language list is not available \n");
12807 if ((index < 0) || (index >= total_track_num)) {
12808 result = MM_ERROR_INVALID_ARGUMENT;
12809 LOGD("Not a proper index : %d \n", index);
12813 /*To get the new pad from the selector*/
12814 change_pad_name = g_strdup_printf("sink_%u", index);
12815 if (change_pad_name == NULL) {
12816 result = MM_ERROR_PLAYER_INTERNAL;
12817 LOGD("Pad does not exists\n");
12821 LOGD("new active pad name: %s\n", change_pad_name);
12823 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12824 if (sinkpad == NULL) {
12825 LOGD("sinkpad is NULL");
12826 result = MM_ERROR_PLAYER_INTERNAL;
12830 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12831 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12833 caps = gst_pad_get_current_caps(sinkpad);
12834 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12837 gst_object_unref(sinkpad);
12839 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12840 __mmplayer_set_audio_attrs(player, caps);
12844 MMPLAYER_FREEIF(change_pad_name);
12848 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12850 int result = MM_ERROR_NONE;
12851 mm_player_t* player = NULL;
12852 MMPlayerGstElement* mainbin = NULL;
12854 gint current_active_index = 0;
12856 GstState current_state = GST_STATE_VOID_PENDING;
12857 GstEvent* event = NULL;
12862 player = (mm_player_t*)hplayer;
12863 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12865 if (!player->pipeline) {
12866 LOGE("Track %d pre setting -> %d\n", type, index);
12868 player->selector[type].active_pad_index = index;
12872 mainbin = player->pipeline->mainbin;
12874 current_active_index = player->selector[type].active_pad_index;
12876 /*If index is same as running index no need to change the pad*/
12877 if (current_active_index == index)
12880 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12881 result = MM_ERROR_PLAYER_INVALID_STATE;
12885 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12886 if (current_state < GST_STATE_PAUSED) {
12887 result = MM_ERROR_PLAYER_INVALID_STATE;
12888 LOGW("Pipeline not in porper state\n");
12892 result = __mmplayer_change_selector_pad(player, type, index);
12893 if (result != MM_ERROR_NONE) {
12894 LOGE("change selector pad error\n");
12898 player->selector[type].active_pad_index = index;
12900 if (current_state == GST_STATE_PLAYING) {
12901 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);
12903 __gst_send_event_to_sink(player, event);
12905 result = MM_ERROR_PLAYER_INTERNAL;
12914 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12916 mm_player_t* player = (mm_player_t*) hplayer;
12920 /* check player handle */
12921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12923 *silent = player->set_mode.subtitle_off;
12925 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12929 return MM_ERROR_NONE;
12933 __is_ms_buff_src(mm_player_t* player)
12935 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12937 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12941 __has_suffix(mm_player_t* player, const gchar* suffix)
12943 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12944 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12946 gboolean ret = FALSE;
12947 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12948 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12950 if (g_str_has_suffix(player->profile.uri, suffix))
12953 MMPLAYER_FREEIF(t_url);
12954 MMPLAYER_FREEIF(t_suffix);
12960 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12962 mm_player_t* player = (mm_player_t*) hplayer;
12964 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12966 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12967 MMPLAYER_PRINT_STATE(player);
12968 LOGE("wrong-state : can't set the download mode to parse");
12969 return MM_ERROR_PLAYER_INVALID_STATE;
12972 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12973 player->video_hub_download_mode = mode;
12975 return MM_ERROR_NONE;
12979 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12981 mm_player_t* player = (mm_player_t*) hplayer;
12983 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12985 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12986 player->sync_handler = enable;
12988 return MM_ERROR_NONE;
12992 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12993 gint64 video_time, gint64 media_clock, gint64 audio_time)
12995 mm_player_t* player = (mm_player_t*) hplayer;
12996 MMPlayerGstElement* mainbin = NULL;
12997 GstClockTime start_time_audio = 0, start_time_video = 0;
12998 GstClockTimeDiff base_time = 0, new_base_time = 0;
12999 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13000 gint64 api_delta = 0;
13001 gint64 position = 0, position_delta = 0;
13002 gint64 adj_base_time = 0;
13003 GstClock *curr_clock = NULL;
13004 GstClockTime curr_time = 0;
13005 gboolean query_ret = TRUE;
13006 int result = MM_ERROR_NONE;
13010 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13011 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13012 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13014 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
13015 clock, clock_delta, video_time, media_clock, audio_time); */
13017 if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
13018 LOGD("skip setting master clock. %lld", video_time);
13022 mainbin = player->pipeline->mainbin;
13024 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13025 curr_time = gst_clock_get_time(curr_clock);
13027 current_state = MMPLAYER_CURRENT_STATE(player);
13029 if (current_state == MM_PLAYER_STATE_PLAYING)
13030 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13032 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13034 position = player->last_position;
13035 LOGD("query fail. %"G_GINT64_FORMAT, position);
13038 clock *= GST_USECOND;
13039 clock_delta *= GST_USECOND;
13041 api_delta = clock - curr_time;
13042 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13043 player->video_share_api_delta = api_delta;
13045 clock_delta += (api_delta - player->video_share_api_delta);
13047 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13048 player->video_share_clock_delta = (gint64)clock_delta;
13050 position_delta = (position/GST_USECOND) - video_time;
13051 position_delta *= GST_USECOND;
13053 adj_base_time = position_delta;
13054 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13057 gint64 new_play_time = 0;
13058 gint64 network_delay = 0;
13060 video_time *= GST_USECOND;
13062 network_delay = clock_delta - player->video_share_clock_delta;
13063 new_play_time = video_time + network_delay;
13065 adj_base_time = position - new_play_time;
13067 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13068 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13069 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13072 /* Adjust Current Stream Time with base_time of sink
13073 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13074 * 2. Set new base time
13075 * if adj_base_time is positive value, the stream time will be decreased.
13076 * 3. If seek event is occurred, the start time will be reset. */
13077 if ((player->pipeline->audiobin) &&
13078 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13079 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13081 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13082 LOGD("audio sink : gst_element_set_start_time -> NONE");
13083 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13086 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13089 if ((player->pipeline->videobin) &&
13090 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13091 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13093 if (start_time_video != GST_CLOCK_TIME_NONE) {
13094 LOGD("video sink : gst_element_set_start_time -> NONE");
13095 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13098 // if videobin exist, get base_time from videobin.
13099 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13102 new_base_time = base_time + adj_base_time;
13104 if ((player->pipeline->audiobin) &&
13105 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13106 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13108 if ((player->pipeline->videobin) &&
13109 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13110 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13119 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13121 mm_player_t* player = (mm_player_t*) hplayer;
13122 MMPlayerGstElement* mainbin = NULL;
13123 GstClock *curr_clock = NULL;
13124 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13125 gint64 position = 0;
13126 gboolean query_ret = TRUE;
13130 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13131 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13132 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13134 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13135 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13136 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13138 mainbin = player->pipeline->mainbin;
13140 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13142 current_state = MMPLAYER_CURRENT_STATE(player);
13144 if (current_state != MM_PLAYER_STATE_PAUSED)
13145 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13147 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13149 position = player->last_position;
13151 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13153 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13156 gst_object_unref(curr_clock);
13160 return MM_ERROR_NONE;
13164 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13166 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13167 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13169 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13170 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13174 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13175 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13176 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13177 mm_player_dump_t *dump_s;
13178 dump_s = g_malloc(sizeof(mm_player_dump_t));
13180 if (dump_s == NULL) {
13181 LOGE("malloc fail");
13185 dump_s->dump_element_file = NULL;
13186 dump_s->dump_pad = NULL;
13187 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13189 if (dump_s->dump_pad) {
13190 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13191 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]);
13192 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13193 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);
13194 /* add list for removed buffer probe and close FILE */
13195 player->dump_list = g_list_append(player->dump_list, dump_s);
13196 LOGD("%s sink pad added buffer probe for dump", factory_name);
13201 LOGE("failed to get %s sink pad added", factory_name);
13210 static GstPadProbeReturn
13211 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13213 FILE *dump_data = (FILE *) u_data;
13214 // int written = 0;
13215 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13216 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13218 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13220 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13222 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13224 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13226 return GST_PAD_PROBE_OK;
13230 __mmplayer_release_dump_list(GList *dump_list)
13233 GList *d_list = dump_list;
13234 for (; d_list; d_list = g_list_next(d_list)) {
13235 mm_player_dump_t *dump_s = d_list->data;
13236 if (dump_s->dump_pad) {
13237 if (dump_s->probe_handle_id)
13238 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13240 if (dump_s->dump_element_file) {
13241 fclose(dump_s->dump_element_file);
13242 dump_s->dump_element_file = NULL;
13244 MMPLAYER_FREEIF(dump_s);
13246 g_list_free(dump_list);
13252 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13254 mm_player_t* player = (mm_player_t*) hplayer;
13258 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13259 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13261 *exist = player->has_closed_caption;
13265 return MM_ERROR_NONE;
13268 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13272 // LOGD("unref internal gst buffer %p", buffer);
13273 gst_buffer_unref((GstBuffer *)buffer);
13280 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13282 mm_player_t *player = (mm_player_t*)user_data;
13283 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13284 guint64 current_level_bytes = 0;
13286 MMPLAYER_RETURN_IF_FAIL(player);
13288 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13290 LOGI("app-src: feed audio(%llu)", current_level_bytes);
13291 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13293 if (player->media_stream_buffer_status_cb[type])
13294 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13295 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13300 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13302 mm_player_t *player = (mm_player_t*)user_data;
13303 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13304 guint64 current_level_bytes = 0;
13306 MMPLAYER_RETURN_IF_FAIL(player);
13308 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13310 LOGI("app-src: feed video(%llu)", current_level_bytes);
13312 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13313 if (player->media_stream_buffer_status_cb[type])
13314 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13315 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13319 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13321 mm_player_t *player = (mm_player_t*)user_data;
13322 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13323 guint64 current_level_bytes = 0;
13325 MMPLAYER_RETURN_IF_FAIL(player);
13327 LOGI("app-src: feed subtitle");
13329 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13331 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13332 if (player->media_stream_buffer_status_cb[type])
13333 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13335 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13339 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13341 mm_player_t *player = (mm_player_t*)user_data;
13342 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13343 guint64 current_level_bytes = 0;
13345 MMPLAYER_RETURN_IF_FAIL(player);
13347 LOGI("app-src: audio buffer is full");
13349 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13351 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13353 if (player->media_stream_buffer_status_cb[type])
13354 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13356 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13360 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13362 mm_player_t *player = (mm_player_t*)user_data;
13363 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13364 guint64 current_level_bytes = 0;
13366 MMPLAYER_RETURN_IF_FAIL(player);
13368 LOGI("app-src: video buffer is full");
13370 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13372 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13373 if (player->media_stream_buffer_status_cb[type])
13374 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13376 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13380 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13382 mm_player_t *player = (mm_player_t*)user_data;
13383 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13385 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13387 LOGD("app-src: seek audio data %llu", position);
13388 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13390 if (player->media_stream_seek_data_cb[type])
13391 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13392 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13398 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13400 mm_player_t *player = (mm_player_t*)user_data;
13401 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13403 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13405 LOGD("app-src: seek video data %llu", position);
13406 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13407 if (player->media_stream_seek_data_cb[type])
13408 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13409 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13415 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13417 mm_player_t *player = (mm_player_t*)user_data;
13418 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13420 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13422 LOGD("app-src: seek subtitle data");
13423 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13425 if (player->media_stream_seek_data_cb[type])
13426 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13427 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13433 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13435 mm_player_t* player = (mm_player_t*) hplayer;
13439 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13441 player->pcm_samplerate = samplerate;
13442 player->pcm_channel = channel;
13445 return MM_ERROR_NONE;
13448 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13450 mm_player_t* player = (mm_player_t*) hplayer;
13454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13455 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13457 if (MMPLAYER_IS_STREAMING(player))
13458 *timeout = player->ini.live_state_change_timeout;
13460 *timeout = player->ini.localplayback_state_change_timeout;
13462 LOGD("timeout = %d\n", *timeout);
13465 return MM_ERROR_NONE;
13468 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13470 mm_player_t* player = (mm_player_t*) hplayer;
13474 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13475 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13477 *num = player->video_num_buffers;
13478 *extra_num = player->video_extra_num_buffers;
13480 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13483 return MM_ERROR_NONE;
13487 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13491 MMPLAYER_RETURN_IF_FAIL(player);
13493 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13495 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13496 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13497 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13498 player->storage_info[i].id = -1;
13499 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13501 if (path_type != MMPLAYER_PATH_MAX)
13509 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13511 int ret = MM_ERROR_NONE;
13512 mm_player_t* player = (mm_player_t*)hplayer;
13513 MMMessageParamType msg_param = {0, };
13516 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13518 LOGW("state changed storage %d:%d", id, state);
13520 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13521 return MM_ERROR_NONE;
13523 /* FIXME: text path should be handled seperately. */
13524 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13525 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13526 LOGW("external storage is removed");
13528 if (player->msg_posted == FALSE) {
13529 memset(&msg_param, 0, sizeof(MMMessageParamType));
13530 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13531 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13532 player->msg_posted = TRUE;
13535 /* unrealize the player */
13536 ret = _mmplayer_unrealize(hplayer);
13537 if (ret != MM_ERROR_NONE)
13538 LOGE("failed to unrealize");
13545 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13547 int ret = MM_ERROR_NONE;
13548 mm_player_t* player = (mm_player_t*) hplayer;
13549 int idx = 0, total = 0;
13550 gchar *result = NULL, *tmp = NULL;
13553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13554 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13556 total = *num = g_list_length(player->adaptive_info.var_list);
13558 LOGW("There is no stream variant info.");
13562 result = g_strdup("");
13563 for (idx = 0 ; idx < total ; idx++) {
13564 VariantData *v_data = NULL;
13565 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13568 gchar data[64] = {0};
13569 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13571 tmp = g_strconcat(result, data, NULL);
13575 LOGW("There is no variant data in %d", idx);
13580 *var_info = (char *)result;
13582 LOGD("variant info %d:%s", *num, *var_info);
13587 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13589 int ret = MM_ERROR_NONE;
13590 mm_player_t* player = (mm_player_t*) hplayer;
13593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13595 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13597 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13598 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13599 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13601 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13602 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13603 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13604 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13606 /* FIXME: seek to current position for applying new variant limitation */
13614 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13616 int ret = MM_ERROR_NONE;
13617 mm_player_t* player = (mm_player_t*) hplayer;
13620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13621 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13623 *bandwidth = player->adaptive_info.limit.bandwidth;
13624 *width = player->adaptive_info.limit.width;
13625 *height = player->adaptive_info.limit.height;
13627 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13633 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13635 int ret = MM_ERROR_NONE;
13636 mm_player_t* player = (mm_player_t*) hplayer;
13639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13641 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13642 LOGW("buffer_ms will not be applied.");
13645 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13647 if (player->streamer == NULL) {
13648 player->streamer = __mm_player_streaming_create();
13649 __mm_player_streaming_initialize(player->streamer);
13652 if (buffer_ms >= 0)
13653 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13655 if (rebuffer_ms >= 0)
13656 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13663 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13665 int ret = MM_ERROR_NONE;
13666 mm_player_t* player = (mm_player_t*) hplayer;
13669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13670 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13672 if (player->streamer == NULL) {
13673 player->streamer = __mm_player_streaming_create();
13674 __mm_player_streaming_initialize(player->streamer);
13677 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13678 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13680 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13686 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13688 #define IDX_FIRST_SW_CODEC 0
13689 mm_player_t* player = (mm_player_t*) hplayer;
13690 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13691 MMHandleType attrs = 0;
13694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13696 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13697 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13698 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13700 switch (stream_type) {
13701 case MM_PLAYER_STREAM_TYPE_AUDIO:
13702 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13703 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13704 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13705 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13706 LOGE("There is no a codec for codec_type %d", codec_type);
13707 return MM_ERROR_PLAYER_NO_OP;
13710 case MM_PLAYER_STREAM_TYPE_VIDEO:
13711 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13712 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13713 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13714 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13715 LOGE("There is no v codec for codec_type %d", codec_type);
13716 return MM_ERROR_PLAYER_NO_OP;
13721 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13722 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13726 LOGD("update %s codec_type to %d", attr_name, codec_type);
13728 attrs = MMPLAYER_GET_ATTRS(player);
13729 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13731 if (mmf_attrs_commit(player->attrs)) {
13732 LOGE("failed to commit codec_type attributes");
13733 return MM_ERROR_PLAYER_INTERNAL;
13737 return MM_ERROR_NONE;
13741 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13743 mm_player_t* player = (mm_player_t*) hplayer;
13744 GstElement* rg_vol_element = NULL;
13748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13750 player->sound.rg_enable = enabled;
13752 /* just hold rgvolume enable value if pipeline is not ready */
13753 if (!player->pipeline || !player->pipeline->audiobin) {
13754 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13755 return MM_ERROR_NONE;
13758 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13760 if (!rg_vol_element) {
13761 LOGD("rgvolume element is not created");
13762 return MM_ERROR_PLAYER_INTERNAL;
13766 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13768 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13772 return MM_ERROR_NONE;
13776 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13778 mm_player_t* player = (mm_player_t*) hplayer;
13779 GstElement* rg_vol_element = NULL;
13780 gboolean enable = FALSE;
13784 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13785 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13787 /* just hold enable_rg value if pipeline is not ready */
13788 if (!player->pipeline || !player->pipeline->audiobin) {
13789 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13790 *enabled = player->sound.rg_enable;
13791 return MM_ERROR_NONE;
13794 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13796 if (!rg_vol_element) {
13797 LOGD("rgvolume element is not created");
13798 return MM_ERROR_PLAYER_INTERNAL;
13801 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13806 return MM_ERROR_NONE;