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);
1062 static gboolean async_done = FALSE;
1064 MMPLAYER_RETURN_IF_FAIL(player);
1065 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1067 switch (GST_MESSAGE_TYPE(msg)) {
1068 case GST_MESSAGE_UNKNOWN:
1069 LOGD("unknown message received\n");
1072 case GST_MESSAGE_EOS:
1074 MMHandleType attrs = 0;
1077 LOGD("GST_MESSAGE_EOS received\n");
1079 /* NOTE : EOS event is comming multiple time. watch out it */
1080 /* check state. we only process EOS when pipeline state goes to PLAYING */
1081 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1082 LOGD("EOS received on non-playing state. ignoring it\n");
1086 if (player->pipeline) {
1087 if (player->pipeline->textbin)
1088 __mmplayer_drop_subtitle(player, TRUE);
1090 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1093 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1095 LOGD("release audio callback\n");
1097 /* release audio callback */
1098 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1099 player->audio_cb_probe_id = 0;
1100 /* audio callback should be free because it can be called even though probe remove.*/
1101 player->audio_stream_cb = NULL;
1102 player->audio_stream_cb_user_param = NULL;
1106 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1107 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1109 /* rewind if repeat count is greater then zero */
1110 /* get play count */
1111 attrs = MMPLAYER_GET_ATTRS(player);
1114 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1116 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1118 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1119 if (player->playback_rate < 0.0) {
1120 player->resumed_by_rewind = TRUE;
1121 _mmplayer_set_mute((MMHandleType)player, 0);
1122 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1125 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1128 player->sent_bos = FALSE;
1130 /* not posting eos when repeating */
1135 if (player->pipeline)
1136 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1138 /* post eos message to application */
1139 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1141 /* reset last position */
1142 player->last_position = 0;
1146 case GST_MESSAGE_ERROR:
1148 GError *error = NULL;
1149 gchar* debug = NULL;
1151 /* generating debug info before returning error */
1152 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1154 /* get error code */
1155 gst_message_parse_error(msg, &error, &debug);
1157 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1158 /* Note : the streaming error from the streaming source is handled
1159 * using __mmplayer_handle_streaming_error.
1161 __mmplayer_handle_streaming_error(player, msg);
1163 /* dump state of all element */
1164 __mmplayer_dump_pipeline_state(player);
1166 /* traslate gst error code to msl error code. then post it
1167 * to application if needed
1169 __mmplayer_handle_gst_error(player, msg, error);
1172 LOGE("error debug : %s", debug);
1175 if (MMPLAYER_IS_HTTP_PD(player))
1176 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1178 MMPLAYER_FREEIF(debug);
1179 g_error_free(error);
1183 case GST_MESSAGE_WARNING:
1186 GError* error = NULL;
1188 gst_message_parse_warning(msg, &error, &debug);
1190 LOGD("warning : %s\n", error->message);
1191 LOGD("debug : %s\n", debug);
1193 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1195 MMPLAYER_FREEIF(debug);
1196 g_error_free(error);
1200 case GST_MESSAGE_TAG:
1202 LOGD("GST_MESSAGE_TAG\n");
1203 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1204 LOGW("failed to extract tags from gstmessage\n");
1208 case GST_MESSAGE_BUFFERING:
1210 MMMessageParamType msg_param = {0, };
1211 int bRet = MM_ERROR_NONE;
1213 if (!(player->pipeline && player->pipeline->mainbin)) {
1214 LOGE("Pipeline is not initialized");
1218 if (!MMPLAYER_IS_STREAMING(player))
1221 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1222 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1223 /* skip the playback control by buffering msg while user request is handled. */
1226 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1228 gst_message_parse_buffering(msg, &per);
1229 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1231 msg_param.connection.buffering = per;
1232 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1236 MMPLAYER_CMD_LOCK(player);
1239 if (!player->streamer) {
1240 LOGW("Pipeline is shutting down");
1241 MMPLAYER_CMD_UNLOCK(player);
1245 /* ignore the remained buffering message till getting 100% msg */
1246 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_COMPLETE) {
1247 gint buffer_percent = 0;
1249 gst_message_parse_buffering(msg, &buffer_percent);
1251 if (buffer_percent == MAX_BUFFER_PERCENT) {
1252 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1253 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1255 MMPLAYER_CMD_UNLOCK(player);
1259 /* ignore the remained buffering message */
1260 if (player->streamer->buffering_state == MM_PLAYER_BUFFERING_ABORT) {
1261 gint buffer_percent = 0;
1263 gst_message_parse_buffering(msg, &buffer_percent);
1265 LOGD("force resume -last posted %d %%, new per %d %%",
1266 player->streamer->buffering_percent, buffer_percent);
1268 if (player->streamer->buffering_percent > buffer_percent) {
1269 player->streamer->buffering_state = MM_PLAYER_BUFFERING_DEFAULT;
1270 player->streamer->buffering_req.is_pre_buffering = FALSE;
1272 LOGD("force resume - need to enter the buffering mode again - %d %%", buffer_percent);
1274 LOGD("force resume - ignored the remained buffering msg!");
1275 MMPLAYER_CMD_UNLOCK(player);
1280 __mmplayer_update_buffer_setting(player, msg);
1282 bRet = __mmplayer_handle_buffering_message(player); /* playback control */
1284 if (bRet == MM_ERROR_NONE) {
1285 msg_param.connection.buffering = player->streamer->buffering_percent;
1286 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1288 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1289 player->pending_resume &&
1290 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1292 player->is_external_subtitle_added_now = FALSE;
1293 player->pending_resume = FALSE;
1294 _mmplayer_resume((MMHandleType)player);
1297 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1298 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1300 if (player->doing_seek) {
1301 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1302 player->doing_seek = FALSE;
1303 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1304 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1309 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1310 if (!player->streamer) {
1311 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1312 MMPLAYER_CMD_UNLOCK(player);
1316 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1318 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1319 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1321 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1322 msg_param.connection.buffering = player->streamer->buffering_percent;
1323 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1325 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1328 msg_param.connection.buffering = player->streamer->buffering_percent;
1329 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1332 MMPLAYER_CMD_UNLOCK(player);
1336 case GST_MESSAGE_STATE_CHANGED:
1338 MMPlayerGstElement *mainbin;
1339 const GValue *voldstate, *vnewstate, *vpending;
1340 GstState oldstate = GST_STATE_NULL;
1341 GstState newstate = GST_STATE_NULL;
1342 GstState pending = GST_STATE_NULL;
1344 if (!(player->pipeline && player->pipeline->mainbin)) {
1345 LOGE("player pipeline handle is null");
1349 mainbin = player->pipeline->mainbin;
1351 /* we only handle messages from pipeline */
1352 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1355 /* get state info from msg */
1356 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1357 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1358 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1360 if (!voldstate || !vnewstate) {
1361 LOGE("received msg has wrong format.");
1365 oldstate = (GstState)voldstate->data[0].v_int;
1366 newstate = (GstState)vnewstate->data[0].v_int;
1368 pending = (GstState)vpending->data[0].v_int;
1370 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1371 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1372 gst_element_state_get_name((GstState)oldstate),
1373 gst_element_state_get_name((GstState)newstate),
1374 gst_element_state_get_name((GstState)pending));
1376 if (newstate == GST_STATE_PLAYING) {
1377 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1379 int retVal = MM_ERROR_NONE;
1380 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1382 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1384 if (MM_ERROR_NONE != retVal)
1385 LOGE("failed to seek pending postion. just keep staying current position.\n");
1387 player->pending_seek.is_pending = FALSE;
1391 if (oldstate == newstate) {
1392 LOGD("pipeline reports state transition to old state");
1397 case GST_STATE_VOID_PENDING:
1400 case GST_STATE_NULL:
1403 case GST_STATE_READY:
1406 case GST_STATE_PAUSED:
1408 gboolean prepare_async = FALSE;
1410 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1411 __mmplayer_configure_audio_callback(player);
1413 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1414 // managed prepare async case
1415 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1416 LOGD("checking prepare mode for async transition - %d", prepare_async);
1419 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1420 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1422 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1423 __mm_player_streaming_set_content_bitrate(player->streamer,
1424 player->total_maximum_bitrate, player->total_bitrate);
1426 if (player->pending_seek.is_pending) {
1427 LOGW("trying to do pending seek");
1428 MMPLAYER_CMD_LOCK(player);
1429 __gst_pending_seek(player);
1430 MMPLAYER_CMD_UNLOCK(player);
1436 case GST_STATE_PLAYING:
1438 if (MMPLAYER_IS_STREAMING(player)) {
1439 // managed prepare async case when buffering is completed
1440 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1441 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1442 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1443 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1445 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1447 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1448 if (player->streamer->buffering_percent < 100) {
1450 MMMessageParamType msg_param = {0, };
1451 LOGW("Posting Buffering Completed Message to Application !!!");
1453 msg_param.connection.buffering = 100;
1454 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1459 if (player->gapless.stream_changed) {
1460 _mmplayer_update_content_attrs(player, ATTR_ALL);
1461 player->gapless.stream_changed = FALSE;
1464 if (player->doing_seek && async_done) {
1465 player->doing_seek = FALSE;
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 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1682 /* we only handle messages from pipeline */
1683 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1686 if (player->doing_seek) {
1687 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1688 player->doing_seek = FALSE;
1689 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1690 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1691 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1692 (player->streamer) &&
1693 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1694 !(player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
1695 GstQuery *query = NULL;
1696 gboolean busy = FALSE;
1699 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1700 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1701 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1702 gst_query_parse_buffering_percent(query, &busy, &percent);
1703 gst_query_unref(query);
1705 LOGD("buffered percent(%s): %d\n",
1706 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1710 __mmplayer_handle_buffering_message(player);
1719 #if 0 /* delete unnecessary logs */
1720 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1721 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1722 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1723 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1724 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1725 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1726 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1727 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1728 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1729 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1730 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1731 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1732 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1733 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1734 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1741 /* should not call 'gst_message_unref(msg)' */
1746 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1752 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1753 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1755 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1756 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1757 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1759 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1760 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1761 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1764 /* handling audio clip which has vbr. means duration is keep changing */
1765 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1773 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1774 mm_player_spherical_metadata_t *metadata) {
1775 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1776 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1777 gst_tag_list_get_string(tags, "stitching_software",
1778 &metadata->stitching_software);
1779 gst_tag_list_get_string(tags, "projection_type",
1780 &metadata->projection_type_string);
1781 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1782 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1783 gst_tag_list_get_int(tags, "init_view_heading",
1784 &metadata->init_view_heading);
1785 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1786 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1787 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1788 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1789 &metadata->full_pano_width_pixels);
1790 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1791 &metadata->full_pano_height_pixels);
1792 gst_tag_list_get_int(tags, "cropped_area_image_width",
1793 &metadata->cropped_area_image_width);
1794 gst_tag_list_get_int(tags, "cropped_area_image_height",
1795 &metadata->cropped_area_image_height);
1796 gst_tag_list_get_int(tags, "cropped_area_left",
1797 &metadata->cropped_area_left);
1798 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1799 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1800 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1801 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1805 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1808 /* macro for better code readability */
1809 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1810 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1811 if (string != NULL) { \
1812 SECURE_LOGD("update tag string : %s\n", string); \
1813 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1814 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1815 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1816 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1817 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1818 g_free(new_string); \
1819 new_string = NULL; \
1821 mm_attrs_set_string_by_name(attribute, playertag, string); \
1828 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1830 GstSample *sample = NULL;\
1831 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1832 GstMapInfo info = GST_MAP_INFO_INIT;\
1833 buffer = gst_sample_get_buffer(sample);\
1834 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1835 LOGD("failed to get image data from tag");\
1836 gst_sample_unref(sample);\
1839 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1840 MMPLAYER_FREEIF(player->album_art);\
1841 player->album_art = (gchar *)g_malloc(info.size);\
1842 if (player->album_art) {\
1843 memcpy(player->album_art, info.data, info.size);\
1844 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1845 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1846 msg_param.data = (void *)player->album_art;\
1847 msg_param.size = info.size;\
1848 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1849 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1852 gst_buffer_unmap(buffer, &info);\
1853 gst_sample_unref(sample);\
1857 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1859 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1862 gchar *tag_list_str = NULL; \
1863 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1864 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1865 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1866 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1867 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1869 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1870 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1871 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1872 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1873 player->bitrate[track_type] = v_uint; \
1874 player->total_bitrate = 0; \
1875 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1876 player->total_bitrate += player->bitrate[i]; \
1877 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1878 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1879 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1880 player->maximum_bitrate[track_type] = v_uint; \
1881 player->total_maximum_bitrate = 0; \
1882 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1883 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1884 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1885 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1887 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1890 g_free(tag_list_str); \
1895 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1896 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1897 if (date != NULL) {\
1898 string = g_strdup_printf("%d", g_date_get_year(date));\
1899 mm_attrs_set_string_by_name(attribute, playertag, string);\
1900 SECURE_LOGD("metainfo year : %s\n", string);\
1901 MMPLAYER_FREEIF(string);\
1906 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1907 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1908 if (datetime != NULL) {\
1909 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1910 mm_attrs_set_string_by_name(attribute, playertag, string);\
1911 SECURE_LOGD("metainfo year : %s\n", string);\
1912 MMPLAYER_FREEIF(string);\
1913 gst_date_time_unref(datetime);\
1917 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1918 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1920 /* FIXIT : don't know how to store date */\
1926 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1927 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1929 /* FIXIT : don't know how to store date */\
1935 /* function start */
1936 GstTagList* tag_list = NULL;
1938 MMHandleType attrs = 0;
1940 char *string = NULL;
1943 GstDateTime *datetime = NULL;
1945 GstBuffer *buffer = NULL;
1947 MMMessageParamType msg_param = {0, };
1949 /* currently not used. but those are needed for above macro */
1950 //guint64 v_uint64 = 0;
1951 //gdouble v_double = 0;
1953 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1955 attrs = MMPLAYER_GET_ATTRS(player);
1957 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1959 /* get tag list from gst message */
1960 gst_message_parse_tag(msg, &tag_list);
1962 /* store tags to player attributes */
1963 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1964 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1965 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1966 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1967 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1969 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1970 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1971 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1972 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1973 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1974 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1975 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1976 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1977 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1978 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1979 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1980 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1981 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1982 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1983 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1984 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1985 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1991 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1992 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1993 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1994 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1995 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1996 MMPLAYER_UPDATE_TAG_LOCK(player);
1997 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1998 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1999 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
2000 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
2001 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
2002 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
2003 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
2004 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
2005 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
2006 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
2007 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
2008 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
2009 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
2010 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
2011 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
2013 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2014 if (player->video360_metadata.is_spherical == -1) {
2015 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2016 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2017 player->video360_metadata.is_spherical);
2018 if (player->video360_metadata.is_spherical == 1) {
2019 LOGD("This is spherical content for 360 playback.");
2020 player->is_content_spherical = TRUE;
2022 LOGD("This is not spherical content");
2023 player->is_content_spherical = FALSE;
2026 if (player->video360_metadata.projection_type_string) {
2027 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2028 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2030 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2031 player->is_content_spherical = player->is_video360_enabled = FALSE;
2035 if (player->video360_metadata.stereo_mode_string) {
2036 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2037 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2038 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2039 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2040 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2041 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2043 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2044 player->is_content_spherical = player->is_video360_enabled = FALSE;
2050 if (mmf_attrs_commit(attrs))
2051 LOGE("failed to commit.\n");
2053 gst_tag_list_free(tag_list);
2059 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2061 mm_player_t* player = (mm_player_t*) data;
2065 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2066 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2067 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2068 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2070 * [1] audio and video will be dumped with filesink.
2071 * [2] autoplugging is done by just using pad caps.
2072 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2073 * and the video will be dumped via filesink.
2075 if (player->num_dynamic_pad == 0) {
2076 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2078 if (!__mmplayer_gst_remove_fakesink(player,
2079 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2080 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2081 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2082 * source element are not same. To overcome this situation, this function will called
2083 * several places and several times. Therefore, this is not an error case.
2088 /* create dot before error-return. for debugging */
2089 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2091 player->no_more_pad = TRUE;
2097 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2099 GstElement* parent = NULL;
2101 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2103 /* if we have no fakesink. this meas we are using decodebin which doesn'
2104 t need to add extra fakesink */
2105 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2108 MMPLAYER_FSINK_LOCK(player);
2113 /* get parent of fakesink */
2114 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2116 LOGD("fakesink already removed\n");
2120 gst_element_set_locked_state(fakesink->gst, TRUE);
2122 /* setting the state to NULL never returns async
2123 * so no need to wait for completion of state transiton
2125 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2126 LOGE("fakesink state change failure!\n");
2127 /* FIXIT : should I return here? or try to proceed to next? */
2130 /* remove fakesink from it's parent */
2131 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2132 LOGE("failed to remove fakesink\n");
2134 gst_object_unref(parent);
2139 gst_object_unref(parent);
2141 LOGD("state-holder removed\n");
2143 gst_element_set_locked_state(fakesink->gst, FALSE);
2145 MMPLAYER_FSINK_UNLOCK(player);
2150 gst_element_set_locked_state(fakesink->gst, FALSE);
2152 MMPLAYER_FSINK_UNLOCK(player);
2158 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2160 GstPad *sinkpad = NULL;
2161 GstCaps* caps = NULL;
2162 GstElement* new_element = NULL;
2163 GstStructure* str = NULL;
2164 const gchar* name = NULL;
2166 mm_player_t* player = (mm_player_t*) data;
2170 MMPLAYER_RETURN_IF_FAIL(element && pad);
2171 MMPLAYER_RETURN_IF_FAIL(player &&
2173 player->pipeline->mainbin);
2176 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2177 * num_dynamic_pad will decreased after creating a sinkbin.
2179 player->num_dynamic_pad++;
2180 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2182 caps = gst_pad_query_caps(pad, NULL);
2184 MMPLAYER_CHECK_NULL(caps);
2186 /* clear previous result*/
2187 player->have_dynamic_pad = FALSE;
2189 str = gst_caps_get_structure(caps, 0);
2192 LOGE("cannot get structure from caps.\n");
2196 name = gst_structure_get_name(str);
2198 LOGE("cannot get mimetype from structure.\n");
2202 if (strstr(name, "video")) {
2204 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2206 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2207 if (player->v_stream_caps) {
2208 gst_caps_unref(player->v_stream_caps);
2209 player->v_stream_caps = NULL;
2212 new_element = gst_element_factory_make("fakesink", NULL);
2213 player->num_dynamic_pad--;
2218 /* clear previous result*/
2219 player->have_dynamic_pad = FALSE;
2221 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2222 LOGE("failed to autoplug for caps");
2226 /* check if there's dynamic pad*/
2227 if (player->have_dynamic_pad) {
2228 LOGE("using pad caps assums there's no dynamic pad !\n");
2232 gst_caps_unref(caps);
2237 /* excute new_element if created*/
2239 LOGD("adding new element to pipeline\n");
2241 /* set state to READY before add to bin */
2242 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2244 /* add new element to the pipeline */
2245 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2246 LOGE("failed to add autoplug element to bin\n");
2250 /* get pad from element */
2251 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2253 LOGE("failed to get sinkpad from autoplug element\n");
2258 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2259 LOGE("failed to link autoplug element\n");
2263 gst_object_unref(sinkpad);
2266 /* run. setting PLAYING here since streamming source is live source */
2267 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2271 gst_caps_unref(caps);
2277 STATE_CHANGE_FAILED:
2279 /* FIXIT : take care if new_element has already added to pipeline */
2281 gst_object_unref(GST_OBJECT(new_element));
2284 gst_object_unref(GST_OBJECT(sinkpad));
2287 gst_caps_unref(caps);
2289 /* FIXIT : how to inform this error to MSL ????? */
2290 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2291 * then post an error to application
2295 static GstPadProbeReturn
2296 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2298 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2299 return GST_PAD_PROBE_OK;
2302 static GstPadProbeReturn
2303 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2305 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2306 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2307 mm_player_t* player = (mm_player_t*)data;
2308 GstCaps* caps = NULL;
2309 GstStructure* str = NULL;
2310 const gchar* name = NULL;
2311 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2314 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2315 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2316 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2317 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2318 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2320 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2321 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2325 caps = gst_pad_query_caps(pad, NULL);
2327 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2331 str = gst_caps_get_structure(caps, 0);
2333 LOGE("failed to get structure from caps");
2337 name = gst_structure_get_name(str);
2339 LOGE("failed to get name from str");
2343 if (strstr(name, "audio")) {
2344 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2345 } else if (strstr(name, "video")) {
2346 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2348 /* text track is not supportable */
2349 LOGE("invalid name %s", name);
2353 switch (GST_EVENT_TYPE(event)) {
2356 /* in case of gapless, drop eos event not to send it to sink */
2357 if (player->gapless.reconfigure && !player->msg_posted) {
2358 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2359 ret = GST_PAD_PROBE_DROP;
2363 case GST_EVENT_STREAM_START:
2365 gint64 stop_running_time = 0;
2366 gint64 position_running_time = 0;
2367 gint64 position = 0;
2370 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2371 if ((player->gapless.update_segment[idx] == TRUE) ||
2372 !(player->selector[idx].event_probe_id)) {
2373 /* LOGW("[%d] skip", idx); */
2377 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2379 gst_segment_to_running_time(&player->gapless.segment[idx],
2380 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2381 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2383 gst_segment_to_running_time(&player->gapless.segment[idx],
2384 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2386 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2388 gst_segment_to_running_time(&player->gapless.segment[idx],
2389 GST_FORMAT_TIME, player->duration);
2392 position_running_time =
2393 gst_segment_to_running_time(&player->gapless.segment[idx],
2394 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2396 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2397 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2399 GST_TIME_ARGS(stop_running_time),
2400 GST_TIME_ARGS(position_running_time),
2401 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2402 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2404 position_running_time = MAX(position_running_time, stop_running_time);
2405 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2406 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2407 position_running_time = MAX(0, position_running_time);
2408 position = MAX(position, position_running_time);
2411 if (position != 0) {
2412 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2413 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2414 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2416 player->gapless.start_time[stream_type] += position;
2420 case GST_EVENT_FLUSH_STOP:
2422 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2423 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2424 player->gapless.start_time[stream_type] = 0;
2427 case GST_EVENT_SEGMENT:
2432 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2433 gst_event_copy_segment(event, &segment);
2435 if (segment.format == GST_FORMAT_TIME) {
2436 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2437 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2438 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2439 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2440 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2441 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2443 /* keep the all the segment ev to cover the seeking */
2444 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2445 player->gapless.update_segment[stream_type] = TRUE;
2447 if (!player->gapless.running)
2450 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2452 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2454 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2455 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2456 gst_event_unref(event);
2457 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2463 gdouble proportion = 0.0;
2464 GstClockTimeDiff diff = 0;
2465 GstClockTime timestamp = 0;
2466 gint64 running_time_diff = -1;
2467 GstQOSType type = 0;
2468 GstEvent *tmpev = NULL;
2470 running_time_diff = player->gapless.segment[stream_type].base;
2472 if (running_time_diff <= 0) /* don't need to adjust */
2475 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2476 gst_event_unref(event);
2478 if (timestamp < running_time_diff) {
2479 LOGW("QOS event from previous group");
2480 ret = GST_PAD_PROBE_DROP;
2484 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2485 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2486 stream_type, GST_TIME_ARGS(timestamp),
2487 GST_TIME_ARGS(running_time_diff),
2488 GST_TIME_ARGS(timestamp - running_time_diff));
2490 timestamp -= running_time_diff;
2492 /* That case is invalid for QoS events */
2493 if (diff < 0 && -diff > timestamp) {
2494 LOGW("QOS event from previous group");
2495 ret = GST_PAD_PROBE_DROP;
2499 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2500 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2510 gst_caps_unref(caps);
2515 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2517 mm_player_t* player = NULL;
2518 GstElement* pipeline = NULL;
2519 GstElement* selector = NULL;
2520 GstElement* fakesink = NULL;
2521 GstCaps* caps = NULL;
2522 GstStructure* str = NULL;
2523 const gchar* name = NULL;
2524 GstPad* sinkpad = NULL;
2525 GstPad* srcpad = NULL;
2526 gboolean first_track = FALSE;
2528 enum MainElementID elemId = MMPLAYER_M_NUM;
2529 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2532 player = (mm_player_t*)data;
2534 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2535 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2537 //LOGD("pad-added signal handling\n");
2539 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2541 /* get mimetype from caps */
2542 caps = gst_pad_query_caps(pad, NULL);
2544 LOGE("cannot get caps from pad.\n");
2548 str = gst_caps_get_structure(caps, 0);
2550 LOGE("cannot get structure from caps.\n");
2554 name = gst_structure_get_name(str);
2556 LOGE("cannot get mimetype from structure.\n");
2560 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2561 //LOGD("detected mimetype : %s\n", name);
2563 if (strstr(name, "video")) {
2566 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2567 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2569 /* don't make video because of not required, and not support multiple track */
2570 if (stype == MM_DISPLAY_SURFACE_NULL) {
2571 LOGD("no video sink by null surface");
2573 gchar *caps_str = gst_caps_to_string(caps);
2574 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2575 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2576 player->set_mode.video_zc = TRUE;
2578 MMPLAYER_FREEIF(caps_str);
2580 if (player->v_stream_caps) {
2581 gst_caps_unref(player->v_stream_caps);
2582 player->v_stream_caps = NULL;
2585 LOGD("create fakesink instead of videobin");
2588 fakesink = gst_element_factory_make("fakesink", NULL);
2589 if (fakesink == NULL) {
2590 LOGE("ERROR : fakesink create error\n");
2594 if (player->ini.set_dump_element_flag)
2595 __mmplayer_add_dump_buffer_probe(player, fakesink);
2597 player->video_fakesink = fakesink;
2599 /* store it as it's sink element */
2600 __mmplayer_add_sink(player, player->video_fakesink);
2602 gst_bin_add(GST_BIN(pipeline), fakesink);
2605 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2607 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2608 LOGW("failed to link fakesink\n");
2609 gst_object_unref(GST_OBJECT(fakesink));
2613 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2614 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2615 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2618 if (player->set_mode.media_packet_video_stream) {
2619 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2621 MMPLAYER_SIGNAL_CONNECT(player,
2623 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2625 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2628 MMPLAYER_SIGNAL_CONNECT(player,
2630 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2632 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2636 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2637 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2641 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2642 __mmplayer_gst_decode_callback(elem, pad, player);
2646 LOGD("video selector \n");
2647 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2648 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2650 if (strstr(name, "audio")) {
2651 gint samplerate = 0;
2654 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2655 __mmplayer_gst_decode_callback(elem, pad, player);
2659 LOGD("audio selector \n");
2660 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2661 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2663 gst_structure_get_int(str, "rate", &samplerate);
2664 gst_structure_get_int(str, "channels", &channels);
2666 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2668 fakesink = gst_element_factory_make("fakesink", NULL);
2669 if (fakesink == NULL) {
2670 LOGE("ERROR : fakesink create error\n");
2674 gst_bin_add(GST_BIN(pipeline), fakesink);
2677 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2679 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2680 LOGW("failed to link fakesink\n");
2681 gst_object_unref(GST_OBJECT(fakesink));
2685 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2686 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2687 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2691 } else if (strstr(name, "text")) {
2692 LOGD("text selector \n");
2693 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2694 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2696 LOGE("wrong elem id \n");
2701 selector = player->pipeline->mainbin[elemId].gst;
2702 if (selector == NULL) {
2703 selector = gst_element_factory_make("input-selector", NULL);
2704 LOGD("Creating input-selector\n");
2705 if (selector == NULL) {
2706 LOGE("ERROR : input-selector create error\n");
2709 g_object_set(selector, "sync-streams", TRUE, NULL);
2711 player->pipeline->mainbin[elemId].id = elemId;
2712 player->pipeline->mainbin[elemId].gst = selector;
2715 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2717 srcpad = gst_element_get_static_pad(selector, "src");
2719 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2720 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2721 __mmplayer_gst_selector_blocked, NULL, NULL);
2722 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2723 __mmplayer_gst_selector_event_probe, player, NULL);
2725 gst_element_set_state(selector, GST_STATE_PAUSED);
2726 gst_bin_add(GST_BIN(pipeline), selector);
2728 LOGD("input-selector is already created.\n");
2731 LOGD("Calling request pad with selector %p \n", selector);
2732 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2734 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2736 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2737 LOGW("failed to link selector\n");
2738 gst_object_unref(GST_OBJECT(selector));
2743 LOGD("this is first track --> active track \n");
2744 g_object_set(selector, "active-pad", sinkpad, NULL);
2747 _mmplayer_track_update_info(player, stream_type, sinkpad);
2754 gst_caps_unref(caps);
2757 gst_object_unref(GST_OBJECT(sinkpad));
2762 gst_object_unref(GST_OBJECT(srcpad));
2769 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2771 GstPad* srcpad = NULL;
2772 MMHandleType attrs = 0;
2773 gint active_index = 0;
2775 // [link] input-selector :: textbin
2776 srcpad = gst_element_get_static_pad(text_selector, "src");
2778 LOGE("failed to get srcpad from selector\n");
2782 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2784 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2785 if ((active_index != DEFAULT_TRACK) &&
2786 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2787 LOGW("failed to change text track\n");
2788 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2791 player->no_more_pad = TRUE;
2792 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2794 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2795 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2796 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2797 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2800 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2802 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2803 player->has_closed_caption = TRUE;
2805 attrs = MMPLAYER_GET_ATTRS(player);
2807 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2808 if (mmf_attrs_commit(attrs))
2809 LOGE("failed to commit.\n");
2811 LOGE("cannot get content attribute");
2814 gst_object_unref(GST_OBJECT(srcpad));
2820 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2822 mm_player_t* player = (mm_player_t*)data;
2823 GstElement* selector = NULL;
2824 GstElement* queue = NULL;
2826 GstPad* srcpad = NULL;
2827 GstPad* sinkpad = NULL;
2828 GstCaps* caps = NULL;
2829 gchar* caps_str = NULL;
2832 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2834 caps = gst_pad_get_current_caps(pad);
2835 caps_str = gst_caps_to_string(caps);
2836 LOGD("deinterleave new caps : %s\n", caps_str);
2837 MMPLAYER_FREEIF(caps_str);
2838 gst_caps_unref(caps);
2840 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2841 LOGE("ERROR : queue create error\n");
2845 g_object_set(G_OBJECT(queue),
2846 "max-size-buffers", 10,
2847 "max-size-bytes", 0,
2848 "max-size-time", (guint64)0,
2851 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2854 LOGE("there is no audio channel selector.\n");
2858 srcpad = gst_element_get_static_pad(queue, "src");
2859 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2861 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2863 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2864 LOGW("failed to link deinterleave - selector\n");
2868 gst_element_set_state(queue, GST_STATE_PAUSED);
2869 player->audio_mode.total_track_num++;
2874 gst_object_unref(GST_OBJECT(srcpad));
2879 gst_object_unref(GST_OBJECT(sinkpad));
2888 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2890 mm_player_t* player = NULL;
2891 GstElement* selector = NULL;
2892 GstPad* sinkpad = NULL;
2893 gint active_index = 0;
2894 gchar* change_pad_name = NULL;
2895 GstCaps* caps = NULL; // no need to unref
2896 gint default_audio_ch = 0;
2899 player = (mm_player_t*) data;
2901 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2904 LOGE("there is no audio channel selector.\n");
2908 active_index = player->audio_mode.active_pad_index;
2910 if (active_index != default_audio_ch) {
2911 gint audio_ch = default_audio_ch;
2913 /*To get the new pad from the selector*/
2914 change_pad_name = g_strdup_printf("sink%d", active_index);
2915 if (change_pad_name != NULL) {
2916 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2917 if (sinkpad != NULL) {
2918 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2919 g_object_set(selector, "active-pad", sinkpad, NULL);
2921 audio_ch = active_index;
2923 caps = gst_pad_get_current_caps(sinkpad);
2924 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2926 __mmplayer_set_audio_attrs(player, caps);
2927 gst_caps_unref(caps);
2929 MMPLAYER_FREEIF(change_pad_name);
2932 player->audio_mode.active_pad_index = audio_ch;
2933 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2939 gst_object_unref(sinkpad);
2946 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2948 mm_player_t* player = NULL;
2949 MMPlayerGstElement *mainbin = NULL;
2951 GstElement* tee = NULL;
2952 GstElement* stereo_queue = NULL;
2953 GstElement* mono_queue = NULL;
2954 GstElement* conv = NULL;
2955 GstElement* filter = NULL;
2956 GstElement* deinterleave = NULL;
2957 GstElement* selector = NULL;
2959 GstPad* srcpad = NULL;
2960 GstPad* selector_srcpad = NULL;
2961 GstPad* sinkpad = NULL;
2962 GstCaps* caps = NULL;
2963 gulong block_id = 0;
2968 player = (mm_player_t*) data;
2970 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2971 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2973 mainbin = player->pipeline->mainbin;
2976 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2977 LOGE("ERROR : tee create error\n");
2981 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2982 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2984 gst_element_set_state(tee, GST_STATE_PAUSED);
2987 srcpad = gst_element_get_request_pad(tee, "src_%u");
2988 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2989 LOGE("ERROR : stereo queue create error\n");
2993 g_object_set(G_OBJECT(stereo_queue),
2994 "max-size-buffers", 10,
2995 "max-size-bytes", 0,
2996 "max-size-time", (guint64)0,
2999 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
3000 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
3003 gst_object_unref(GST_OBJECT(srcpad));
3007 srcpad = gst_element_get_request_pad(tee, "src_%u");
3009 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
3010 LOGE("ERROR : mono queue create error\n");
3014 g_object_set(G_OBJECT(mono_queue),
3015 "max-size-buffers", 10,
3016 "max-size-bytes", 0,
3017 "max-size-time", (guint64)0,
3020 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3021 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3023 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3024 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3027 srcpad = gst_element_get_static_pad(mono_queue, "src");
3028 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3029 LOGE("ERROR : audioconvert create error\n");
3033 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3034 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3038 gst_object_unref(GST_OBJECT(srcpad));
3041 srcpad = gst_element_get_static_pad(conv, "src");
3043 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3044 LOGE("ERROR : capsfilter create error\n");
3048 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3049 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3051 caps = gst_caps_from_string("audio/x-raw-int, "
3052 "width = (int) 16, "
3053 "depth = (int) 16, "
3054 "channels = (int) 2");
3056 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3057 gst_caps_unref(caps);
3059 gst_element_set_state(conv, GST_STATE_PAUSED);
3060 gst_element_set_state(filter, GST_STATE_PAUSED);
3064 gst_object_unref(GST_OBJECT(srcpad));
3067 srcpad = gst_element_get_static_pad(filter, "src");
3069 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3070 LOGE("ERROR : deinterleave create error\n");
3074 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3076 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3077 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3079 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3080 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3082 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3083 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3086 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3087 if (selector == NULL) {
3088 LOGE("ERROR : audio-selector create error\n");
3092 g_object_set(selector, "sync-streams", TRUE, NULL);
3093 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3095 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3096 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3098 selector_srcpad = gst_element_get_static_pad(selector, "src");
3100 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3102 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3103 __mmplayer_gst_selector_blocked, NULL, NULL);
3106 gst_object_unref(GST_OBJECT(srcpad));
3110 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3111 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3113 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3114 LOGW("failed to link queue_stereo - selector\n");
3118 player->audio_mode.total_track_num++;
3120 g_object_set(selector, "active-pad", sinkpad, NULL);
3121 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3122 gst_element_set_state(selector, GST_STATE_PAUSED);
3124 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3128 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3129 if (block_id != 0) {
3130 gst_pad_remove_probe(selector_srcpad, block_id);
3135 gst_object_unref(GST_OBJECT(sinkpad));
3140 gst_object_unref(GST_OBJECT(srcpad));
3144 if (selector_srcpad) {
3145 gst_object_unref(GST_OBJECT(selector_srcpad));
3146 selector_srcpad = NULL;
3154 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3156 mm_player_t* player = NULL;
3157 GstPad* srcpad = NULL;
3158 GstElement* video_selector = NULL;
3159 GstElement* audio_selector = NULL;
3160 GstElement* text_selector = NULL;
3161 MMHandleType attrs = 0;
3162 gint active_index = 0;
3163 gint64 dur_bytes = 0L;
3165 player = (mm_player_t*) data;
3167 LOGD("no-more-pad signal handling\n");
3169 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3170 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3171 LOGW("no need to go more");
3173 if (player->gapless.reconfigure) {
3174 player->gapless.reconfigure = FALSE;
3175 MMPLAYER_PLAYBACK_UNLOCK(player);
3181 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3182 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3183 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3184 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3185 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3187 if (NULL == player->streamer) {
3188 LOGW("invalid state for buffering");
3192 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3193 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3195 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3196 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3198 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3200 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3201 LOGE("fail to get duration.\n");
3203 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
3204 * use file information was already set on Q2 when it was created. */
3205 __mm_player_streaming_set_queue2(player->streamer,
3206 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3207 TRUE, /* use_buffering */
3209 init_buffering_time,
3210 1.0, /* low percent */
3211 player->ini.http_buffering_limit, /* high percent */
3212 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
3214 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3217 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3218 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3219 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3220 if (video_selector) {
3221 // [link] input-selector :: videobin
3222 srcpad = gst_element_get_static_pad(video_selector, "src");
3224 LOGE("failed to get srcpad from video selector\n");
3228 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3229 if (!text_selector && !audio_selector)
3230 player->no_more_pad = TRUE;
3232 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3234 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3235 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3236 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3237 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3241 if (audio_selector) {
3242 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3243 if ((active_index != DEFAULT_TRACK) &&
3244 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3245 LOGW("failed to change audio track\n");
3246 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3249 // [link] input-selector :: audiobin
3250 srcpad = gst_element_get_static_pad(audio_selector, "src");
3252 LOGE("failed to get srcpad from selector\n");
3256 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3258 player->no_more_pad = TRUE;
3260 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3261 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3262 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3263 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3264 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3267 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3269 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3271 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3272 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3273 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3274 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3278 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3280 attrs = MMPLAYER_GET_ATTRS(player);
3282 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3283 if (mmf_attrs_commit(attrs))
3284 LOGE("failed to commit.\n");
3286 LOGE("cannot get content attribute");
3288 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3289 LOGD("There is no audio track : remove audiobin");
3291 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3292 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3294 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3295 MMPLAYER_FREEIF(player->pipeline->audiobin);
3298 if (player->num_dynamic_pad == 0)
3299 __mmplayer_pipeline_complete(NULL, player);
3302 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3304 __mmplayer_handle_text_decode_path(player, text_selector);
3311 gst_object_unref(GST_OBJECT(srcpad));
3315 if (player->gapless.reconfigure) {
3316 player->gapless.reconfigure = FALSE;
3317 MMPLAYER_PLAYBACK_UNLOCK(player);
3322 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3324 mm_player_t* player = NULL;
3325 MMHandleType attrs = 0;
3326 GstElement* pipeline = NULL;
3327 GstCaps* caps = NULL;
3328 gchar* caps_str = NULL;
3329 GstStructure* str = NULL;
3330 const gchar* name = NULL;
3331 GstPad* sinkpad = NULL;
3332 GstElement* sinkbin = NULL;
3333 gboolean reusing = FALSE;
3334 GstElement *text_selector = NULL;
3337 player = (mm_player_t*) data;
3339 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3340 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3342 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3344 attrs = MMPLAYER_GET_ATTRS(player);
3346 LOGE("cannot get content attribute\n");
3350 /* get mimetype from caps */
3351 caps = gst_pad_query_caps(pad, NULL);
3353 LOGE("cannot get caps from pad.\n");
3356 caps_str = gst_caps_to_string(caps);
3358 str = gst_caps_get_structure(caps, 0);
3360 LOGE("cannot get structure from caps.\n");
3364 name = gst_structure_get_name(str);
3366 LOGE("cannot get mimetype from structure.\n");
3370 //LOGD("detected mimetype : %s\n", name);
3372 if (strstr(name, "audio")) {
3373 if (player->pipeline->audiobin == NULL) {
3374 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3375 LOGE("failed to create audiobin. continuing without audio\n");
3379 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3380 LOGD("creating audiosink bin success\n");
3383 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3384 LOGD("reusing audiobin\n");
3385 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3388 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3389 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3391 player->audiosink_linked = 1;
3393 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3395 LOGE("failed to get pad from sinkbin\n");
3398 } else if (strstr(name, "video")) {
3399 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3400 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3401 player->set_mode.video_zc = TRUE;
3403 if (player->pipeline->videobin == NULL) {
3404 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3405 /* get video surface type */
3406 int surface_type = 0;
3407 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3408 LOGD("display_surface_type(%d)\n", surface_type);
3410 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3411 LOGD("not make videobin because it dose not want\n");
3415 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3416 /* mark video overlay for acquire */
3417 if (player->video_overlay_resource == NULL) {
3418 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3419 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3420 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3421 &player->video_overlay_resource)
3422 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3423 LOGE("could not mark video_overlay resource for acquire\n");
3429 player->interrupted_by_resource = FALSE;
3430 /* acquire resources for video overlay */
3431 if (mm_resource_manager_commit(player->resource_manager) !=
3432 MM_RESOURCE_MANAGER_ERROR_NONE) {
3433 LOGE("could not acquire resources for video playing\n");
3437 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3438 LOGE("failed to create videobin. continuing without video\n");
3442 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3443 LOGD("creating videosink bin success\n");
3446 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3447 LOGD("re-using videobin\n");
3448 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3451 player->videosink_linked = 1;
3453 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3455 LOGE("failed to get pad from sinkbin\n");
3458 } else if (strstr(name, "text")) {
3459 if (player->pipeline->textbin == NULL) {
3460 MMPlayerGstElement* mainbin = NULL;
3462 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3463 LOGE("failed to create text sink bin. continuing without text\n");
3467 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3468 LOGD("creating textsink bin success\n");
3470 /* FIXIT : track number shouldn't be hardcoded */
3471 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3473 player->textsink_linked = 1;
3474 LOGI("player->textsink_linked set to 1\n");
3476 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3478 LOGE("failed to get pad from sinkbin\n");
3482 mainbin = player->pipeline->mainbin;
3484 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3485 /* input selector */
3486 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3487 if (!text_selector) {
3488 LOGE("failed to create subtitle input selector element\n");
3491 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3493 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3494 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3497 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3498 LOGE("failed to set state(READY) to sinkbin\n");
3502 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3503 LOGW("failed to add subtitle input selector\n");
3507 LOGD("created element input-selector");
3510 LOGD("already having subtitle input selector");
3511 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3514 if (!player->textsink_linked) {
3515 LOGD("re-using textbin\n");
3518 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3520 player->textsink_linked = 1;
3521 LOGI("player->textsink_linked set to 1\n");
3523 LOGD("ignoring internal subtutle since external subtitle is available");
3526 LOGW("unknown type of elementary stream!ignoring it...\n");
3533 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3534 LOGE("failed to set state(READY) to sinkbin\n");
3538 /* Added for multi audio support to avoid adding audio bin again*/
3540 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3541 LOGE("failed to add sinkbin to pipeline\n");
3547 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3548 LOGE("failed to get pad from sinkbin\n");
3554 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3555 LOGE("failed to set state(PAUSED) to sinkbin\n");
3559 if (text_selector) {
3560 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3561 LOGE("failed to set state(PAUSED) to sinkbin\n");
3567 gst_object_unref(sinkpad);
3571 LOGD("[handle: %p] linking sink bin success", player);
3573 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3574 * streaming task. if the task blocked, then buffer will not flow to the next element
3575 *(autoplugging element). so this is special hack for streaming. please try to remove it
3577 /* dec stream count. we can remove fakesink if it's zero */
3578 if (player->num_dynamic_pad)
3579 player->num_dynamic_pad--;
3581 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3583 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3584 __mmplayer_pipeline_complete(NULL, player);
3588 MMPLAYER_FREEIF(caps_str);
3591 gst_caps_unref(caps);
3594 gst_object_unref(GST_OBJECT(sinkpad));
3596 /* flusing out new attributes */
3597 if (mmf_attrs_commit(attrs))
3598 LOGE("failed to comit attributes\n");
3604 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3606 int pro_value = 0; // in the case of expection, default will be returned.
3607 int dest_angle = rotation_angle;
3608 int rotation_type = -1;
3610 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3611 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3612 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3614 if (rotation_angle >= 360)
3615 dest_angle = rotation_angle - 360;
3617 /* chech if supported or not */
3618 if (dest_angle % 90) {
3619 LOGD("not supported rotation angle = %d", rotation_angle);
3625 * custom_convert - none (B)
3626 * videoflip - none (C)
3628 if (player->set_mode.video_zc) {
3629 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3630 rotation_type = ROTATION_USING_CUSTOM;
3632 rotation_type = ROTATION_USING_SINK;
3634 int surface_type = 0;
3635 rotation_type = ROTATION_USING_FLIP;
3637 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3638 LOGD("check display surface type attribute: %d", surface_type);
3640 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3641 rotation_type = ROTATION_USING_SINK;
3643 rotation_type = ROTATION_USING_FLIP; //C
3645 LOGD("using %d type for rotation", rotation_type);
3648 /* get property value for setting */
3649 switch (rotation_type) {
3650 case ROTATION_USING_SINK: // tizenwlsink
3652 switch (dest_angle) {
3656 pro_value = 3; // clockwise 90
3662 pro_value = 1; // counter-clockwise 90
3667 case ROTATION_USING_CUSTOM:
3669 gchar *ename = NULL;
3670 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3672 if (g_strrstr(ename, "fimcconvert")) {
3673 switch (dest_angle) {
3677 pro_value = 90; // clockwise 90
3683 pro_value = 270; // counter-clockwise 90
3689 case ROTATION_USING_FLIP: // videoflip
3691 switch (dest_angle) {
3695 pro_value = 1; // clockwise 90
3701 pro_value = 3; // counter-clockwise 90
3708 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3716 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3718 /* check video sinkbin is created */
3719 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3721 player->pipeline->videobin &&
3722 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3723 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3724 MM_ERROR_PLAYER_NOT_INITIALIZED);
3726 return MM_ERROR_NONE;
3730 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3732 int rotation_value = 0;
3733 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3737 /* check video sinkbin is created */
3738 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3741 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3743 /* get rotation value to set */
3744 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3745 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3746 LOGD("set video param : rotate %d", rotation_value);
3750 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3752 MMHandleType attrs = 0;
3756 /* check video sinkbin is created */
3757 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3760 attrs = MMPLAYER_GET_ATTRS(player);
3761 MMPLAYER_RETURN_IF_FAIL(attrs);
3763 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3764 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3765 LOGD("set video param : visible %d", visible);
3769 __mmplayer_video_param_set_display_method(mm_player_t* player)
3771 MMHandleType attrs = 0;
3772 int display_method = 0;
3775 /* check video sinkbin is created */
3776 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3779 attrs = MMPLAYER_GET_ATTRS(player);
3780 MMPLAYER_RETURN_IF_FAIL(attrs);
3782 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3783 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3784 LOGD("set video param : method %d", display_method);
3788 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3790 MMHandleType attrs = 0;
3791 void *handle = NULL;
3793 int wl_window_x = 0;
3794 int wl_window_y = 0;
3795 int wl_window_width = 0;
3796 int wl_window_height = 0;
3799 /* check video sinkbin is created */
3800 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3803 attrs = MMPLAYER_GET_ATTRS(player);
3804 MMPLAYER_RETURN_IF_FAIL(attrs);
3806 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3809 /*It should be set after setting window*/
3810 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3811 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3812 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3813 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3815 /* After setting window handle, set render rectangle */
3816 gst_video_overlay_set_render_rectangle(
3817 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3818 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3819 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3820 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3825 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3827 MMHandleType attrs = 0;
3828 void *handle = NULL;
3830 /* check video sinkbin is created */
3831 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3834 attrs = MMPLAYER_GET_ATTRS(player);
3835 MMPLAYER_RETURN_IF_FAIL(attrs);
3837 /* common case if using overlay surface */
3838 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3841 /* default is using wl_surface_id */
3842 unsigned int wl_surface_id = 0;
3843 wl_surface_id = *(int*)handle;
3844 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3845 gst_video_overlay_set_wl_window_wl_surface_id(
3846 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3849 /* FIXIT : is it error case? */
3850 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3855 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3857 bool update_all_param = FALSE;
3860 /* check video sinkbin is created */
3861 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3862 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3864 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3865 LOGE("can not find tizenwlsink");
3866 return MM_ERROR_PLAYER_INTERNAL;
3869 LOGD("param_name : %s", param_name);
3870 if (!g_strcmp0(param_name, "update_all_param"))
3871 update_all_param = TRUE;
3873 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3874 __mmplayer_video_param_set_display_overlay(player);
3875 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3876 __mmplayer_video_param_set_display_method(player);
3877 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3878 __mmplayer_video_param_set_render_rectangle(player);
3879 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3880 __mmplayer_video_param_set_display_visible(player);
3881 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3882 __mmplayer_video_param_set_display_rotation(player);
3884 return MM_ERROR_NONE;
3888 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3890 MMHandleType attrs = 0;
3891 int surface_type = 0;
3892 int ret = MM_ERROR_NONE;
3896 /* check video sinkbin is created */
3897 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3898 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3900 attrs = MMPLAYER_GET_ATTRS(player);
3902 LOGE("cannot get content attribute");
3903 return MM_ERROR_PLAYER_INTERNAL;
3905 LOGD("param_name : %s", param_name);
3907 /* update display surface */
3908 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3909 LOGD("check display surface type attribute: %d", surface_type);
3911 /* configuring display */
3912 switch (surface_type) {
3913 case MM_DISPLAY_SURFACE_OVERLAY:
3915 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3916 if (ret != MM_ERROR_NONE)
3924 return MM_ERROR_NONE;
3928 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3930 gboolean disable_overlay = FALSE;
3931 mm_player_t* player = (mm_player_t*) hplayer;
3932 int ret = MM_ERROR_NONE;
3935 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3936 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3937 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3938 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3940 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3941 LOGW("Display control is not supported");
3942 return MM_ERROR_PLAYER_INTERNAL;
3945 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3947 if (audio_only == (bool)disable_overlay) {
3948 LOGE("It's the same with current setting: (%d)", audio_only);
3949 return MM_ERROR_NONE;
3953 LOGE("disable overlay");
3954 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3956 /* release overlay resource */
3957 if (player->video_overlay_resource != NULL) {
3958 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3959 player->video_overlay_resource);
3960 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3961 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3964 player->video_overlay_resource = NULL;
3967 ret = mm_resource_manager_commit(player->resource_manager);
3968 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3969 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3973 /* mark video overlay for acquire */
3974 if (player->video_overlay_resource == NULL) {
3975 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3976 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3977 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3978 &player->video_overlay_resource);
3979 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3980 LOGE("could not prepare for video_overlay resource\n");
3985 player->interrupted_by_resource = FALSE;
3986 /* acquire resources for video overlay */
3987 ret = mm_resource_manager_commit(player->resource_manager);
3988 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3989 LOGE("could not acquire resources for video playing\n");
3993 LOGD("enable overlay");
3994 __mmplayer_video_param_set_display_overlay(player);
3995 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
4000 return MM_ERROR_NONE;
4004 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
4006 mm_player_t* player = (mm_player_t*) hplayer;
4007 gboolean disable_overlay = FALSE;
4011 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4012 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
4013 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4014 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4015 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4017 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4018 LOGW("Display control is not supported");
4019 return MM_ERROR_PLAYER_INTERNAL;
4022 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4024 *paudio_only = (bool)(disable_overlay);
4026 LOGD("audio_only : %d", *paudio_only);
4030 return MM_ERROR_NONE;
4034 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4036 GList* bucket = element_bucket;
4037 MMPlayerGstElement* element = NULL;
4038 MMPlayerGstElement* prv_element = NULL;
4039 gint successful_link_count = 0;
4043 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4045 prv_element = (MMPlayerGstElement*)bucket->data;
4046 bucket = bucket->next;
4048 for (; bucket; bucket = bucket->next) {
4049 element = (MMPlayerGstElement*)bucket->data;
4051 if (element && element->gst) {
4052 /* If next element is audio appsrc then make a separate audio pipeline */
4053 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4054 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4055 prv_element = element;
4059 if (prv_element && prv_element->gst) {
4060 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4061 LOGD("linking [%s] to [%s] success\n",
4062 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4063 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4064 successful_link_count++;
4066 LOGD("linking [%s] to [%s] failed\n",
4067 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4068 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4074 prv_element = element;
4079 return successful_link_count;
4083 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4085 GList* bucket = element_bucket;
4086 MMPlayerGstElement* element = NULL;
4087 int successful_add_count = 0;
4091 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4092 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4094 for (; bucket; bucket = bucket->next) {
4095 element = (MMPlayerGstElement*)bucket->data;
4097 if (element && element->gst) {
4098 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4099 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4100 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4101 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4104 successful_add_count++;
4110 return successful_add_count;
4113 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4115 mm_player_t* player = (mm_player_t*) data;
4116 GstCaps *caps = NULL;
4117 GstStructure *str = NULL;
4122 MMPLAYER_RETURN_IF_FAIL(pad)
4123 MMPLAYER_RETURN_IF_FAIL(unused)
4124 MMPLAYER_RETURN_IF_FAIL(data)
4126 caps = gst_pad_get_current_caps(pad);
4130 str = gst_caps_get_structure(caps, 0);
4134 name = gst_structure_get_name(str);
4138 LOGD("name = %s\n", name);
4140 if (strstr(name, "audio")) {
4141 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4143 if (player->audio_stream_changed_cb) {
4144 LOGE("call the audio stream changed cb\n");
4145 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4147 } else if (strstr(name, "video")) {
4148 if ((name = gst_structure_get_string(str, "format")))
4149 player->set_mode.video_zc = name[0] == 'S';
4151 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4153 if (player->video_stream_changed_cb) {
4154 LOGE("call the video stream changed cb\n");
4155 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4162 gst_caps_unref(caps);
4172 * This function is to create audio pipeline for playing.
4174 * @param player [in] handle of player
4176 * @return This function returns zero on success.
4178 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4180 /* macro for code readability. just for sinkbin-creation functions */
4181 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4183 x_bin[x_id].id = x_id;\
4184 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4185 if (!x_bin[x_id].gst) {\
4186 LOGE("failed to create %s \n", x_factory);\
4189 if (x_player->ini.set_dump_element_flag)\
4190 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4193 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4197 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4202 MMPLAYER_RETURN_IF_FAIL(player);
4204 if (player->audio_stream_buff_list) {
4205 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4206 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4209 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4210 __mmplayer_audio_stream_send_data(player, tmp);
4213 g_free(tmp->pcm_data);
4217 g_list_free(player->audio_stream_buff_list);
4218 player->audio_stream_buff_list = NULL;
4225 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4227 MMPlayerAudioStreamDataType audio_stream = { 0, };
4230 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4232 audio_stream.bitrate = a_buffer->bitrate;
4233 audio_stream.channel = a_buffer->channel;
4234 audio_stream.depth = a_buffer->depth;
4235 audio_stream.is_little_endian = a_buffer->is_little_endian;
4236 audio_stream.channel_mask = a_buffer->channel_mask;
4237 audio_stream.data_size = a_buffer->data_size;
4238 audio_stream.data = a_buffer->pcm_data;
4240 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4241 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4247 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4249 mm_player_t* player = (mm_player_t*) data;
4254 gint endianness = 0;
4255 guint64 channel_mask = 0;
4256 void *a_data = NULL;
4258 mm_player_audio_stream_buff_t *a_buffer = NULL;
4259 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4263 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4265 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4266 a_data = mapinfo.data;
4267 a_size = mapinfo.size;
4269 GstCaps *caps = gst_pad_get_current_caps(pad);
4270 GstStructure *structure = gst_caps_get_structure(caps, 0);
4272 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4273 gst_structure_get_int(structure, "rate", &rate);
4274 gst_structure_get_int(structure, "channels", &channel);
4275 gst_structure_get_int(structure, "depth", &depth);
4276 gst_structure_get_int(structure, "endianness", &endianness);
4277 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4278 gst_caps_unref(GST_CAPS(caps));
4280 /* In case of the sync is false, use buffer list. *
4281 * The num of buffer list depends on the num of audio channels */
4282 if (player->audio_stream_buff_list) {
4283 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4284 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4286 if (channel_mask == tmp->channel_mask) {
4287 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4288 if (tmp->data_size + a_size < tmp->buff_size) {
4289 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4290 tmp->data_size += a_size;
4292 /* send data to client */
4293 __mmplayer_audio_stream_send_data(player, tmp);
4295 if (a_size > tmp->buff_size) {
4296 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4297 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4298 if (tmp->pcm_data == NULL) {
4299 LOGE("failed to realloc data.");
4302 tmp->buff_size = a_size;
4304 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4305 memcpy(tmp->pcm_data, a_data, a_size);
4306 tmp->data_size = a_size;
4311 LOGE("data is empty in list.");
4317 /* create new audio stream data */
4318 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4319 if (a_buffer == NULL) {
4320 LOGE("failed to alloc data.");
4323 a_buffer->bitrate = rate;
4324 a_buffer->channel = channel;
4325 a_buffer->depth = depth;
4326 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4327 a_buffer->channel_mask = channel_mask;
4328 a_buffer->data_size = a_size;
4330 if (!player->audio_stream_sink_sync) {
4331 /* If sync is FALSE, use buffer list to reduce the IPC. */
4332 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4333 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4334 if (a_buffer->pcm_data == NULL) {
4335 LOGE("failed to alloc data.");
4339 memcpy(a_buffer->pcm_data, a_data, a_size);
4340 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4341 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4343 /* If sync is TRUE, send data directly. */
4344 a_buffer->pcm_data = a_data;
4345 __mmplayer_audio_stream_send_data(player, a_buffer);
4350 gst_buffer_unmap(buffer, &mapinfo);
4355 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4357 mm_player_t* player = (mm_player_t*)data;
4358 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4359 GstPad* sinkpad = NULL;
4360 GstElement *queue = NULL, *sink = NULL;
4363 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4365 queue = gst_element_factory_make("queue", NULL);
4366 if (queue == NULL) {
4367 LOGD("fail make queue\n");
4371 sink = gst_element_factory_make("fakesink", NULL);
4373 LOGD("fail make fakesink\n");
4377 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4379 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4380 LOGW("failed to link queue & sink\n");
4384 sinkpad = gst_element_get_static_pad(queue, "sink");
4386 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4387 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4391 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4393 gst_object_unref(sinkpad);
4394 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4395 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4397 gst_element_set_state(sink, GST_STATE_PAUSED);
4398 gst_element_set_state(queue, GST_STATE_PAUSED);
4400 MMPLAYER_SIGNAL_CONNECT(player,
4402 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4404 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4411 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4413 gst_object_unref(GST_OBJECT(queue));
4417 gst_object_unref(GST_OBJECT(sink));
4421 gst_object_unref(GST_OBJECT(sinkpad));
4428 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4430 #define MAX_PROPS_LEN 128
4431 gint latency_mode = 0;
4432 gchar *stream_type = NULL;
4433 gchar *latency = NULL;
4435 gchar stream_props[MAX_PROPS_LEN] = {0,};
4436 GstStructure *props = NULL;
4439 * It should be set after player creation through attribute.
4440 * But, it can not be changed during playing.
4443 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4444 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4447 LOGE("stream_type is null.\n");
4449 if (player->sound.focus_id)
4450 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4451 stream_type, stream_id, player->sound.focus_id);
4453 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4454 stream_type, stream_id);
4455 props = gst_structure_from_string(stream_props, NULL);
4456 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4457 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4458 stream_type, stream_id, player->sound.focus_id, stream_props);
4459 gst_structure_free(props);
4462 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4464 switch (latency_mode) {
4465 case AUDIO_LATENCY_MODE_LOW:
4466 latency = g_strndup("low", 3);
4468 case AUDIO_LATENCY_MODE_MID:
4469 latency = g_strndup("mid", 3);
4471 case AUDIO_LATENCY_MODE_HIGH:
4472 latency = g_strndup("high", 4);
4476 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4480 LOGD("audiosink property - latency=%s \n", latency);
4488 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4490 MMPlayerGstElement* first_element = NULL;
4491 MMPlayerGstElement* audiobin = NULL;
4492 MMHandleType attrs = 0;
4494 GstPad *ghostpad = NULL;
4495 GList* element_bucket = NULL;
4496 gboolean link_audio_sink_now = TRUE;
4502 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4505 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4507 LOGE("failed to allocate memory for audiobin\n");
4508 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4511 attrs = MMPLAYER_GET_ATTRS(player);
4514 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4515 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4516 if (!audiobin[MMPLAYER_A_BIN].gst) {
4517 LOGE("failed to create audiobin\n");
4522 player->pipeline->audiobin = audiobin;
4524 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4526 /* Adding audiotp plugin for reverse trickplay feature */
4527 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4530 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4532 /* replaygain volume */
4533 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4534 if (player->sound.rg_enable)
4535 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4537 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4540 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4542 if (player->set_mode.pcm_extraction) {
4543 // pcm extraction only and no sound output
4544 if (player->audio_stream_render_cb_ex) {
4545 char *caps_str = NULL;
4546 GstCaps* caps = NULL;
4547 gchar *format = NULL;
4550 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4552 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4554 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4556 caps = gst_caps_new_simple("audio/x-raw",
4557 "format", G_TYPE_STRING, format,
4558 "rate", G_TYPE_INT, player->pcm_samplerate,
4559 "channels", G_TYPE_INT, player->pcm_channel,
4561 caps_str = gst_caps_to_string(caps);
4562 LOGD("new caps : %s\n", caps_str);
4564 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4567 gst_caps_unref(caps);
4568 MMPLAYER_FREEIF(caps_str);
4570 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4572 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4573 /* raw pad handling signal */
4574 MMPLAYER_SIGNAL_CONNECT(player,
4575 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4576 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4577 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4579 int dst_samplerate = 0;
4580 int dst_channels = 0;
4582 char *caps_str = NULL;
4583 GstCaps* caps = NULL;
4585 /* get conf. values */
4586 mm_attrs_multiple_get(player->attrs,
4588 "pcm_extraction_samplerate", &dst_samplerate,
4589 "pcm_extraction_channels", &dst_channels,
4590 "pcm_extraction_depth", &dst_depth,
4594 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4595 caps = gst_caps_new_simple("audio/x-raw",
4596 "rate", G_TYPE_INT, dst_samplerate,
4597 "channels", G_TYPE_INT, dst_channels,
4598 "depth", G_TYPE_INT, dst_depth,
4600 caps_str = gst_caps_to_string(caps);
4601 LOGD("new caps : %s\n", caps_str);
4603 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4606 gst_caps_unref(caps);
4607 MMPLAYER_FREEIF(caps_str);
4610 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4613 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4617 //GstCaps* caps = NULL;
4620 /* for logical volume control */
4621 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4622 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4624 if (player->sound.mute) {
4625 LOGD("mute enabled\n");
4626 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4632 caps = gst_caps_from_string("audio/x-raw-int, "
4633 "endianness = (int) LITTLE_ENDIAN, "
4634 "signed = (boolean) true, "
4635 "width = (int) 16, "
4636 "depth = (int) 16");
4637 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4638 gst_caps_unref(caps);
4641 /* check if multi-channels */
4642 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4643 GstPad *srcpad = NULL;
4644 GstCaps *caps = NULL;
4646 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4647 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4648 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4649 GstStructure *str = gst_caps_get_structure(caps, 0);
4651 gst_structure_get_int(str, "channels", &channels);
4652 gst_caps_unref(caps);
4654 gst_object_unref(srcpad);
4658 /* audio effect element. if audio effect is enabled */
4659 if ((strcmp(player->ini.audioeffect_element, ""))
4661 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4662 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4664 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4666 if ((!player->bypass_audio_effect)
4667 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4668 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4669 if (!_mmplayer_audio_effect_custom_apply(player))
4670 LOGI("apply audio effect(custom) setting success\n");
4674 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4675 && (player->set_mode.rich_audio))
4676 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4679 /* create audio sink */
4680 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4681 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4682 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4684 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4685 if (player->is_360_feature_enabled &&
4686 player->is_content_spherical &&
4688 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4689 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4690 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4692 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4697 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4699 gst_caps_unref(acaps);
4701 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4703 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4704 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4706 player->is_openal_plugin_used = TRUE;
4708 if (player->video360_yaw_radians <= M_PI &&
4709 player->video360_yaw_radians >= -M_PI &&
4710 player->video360_pitch_radians <= M_PI_2 &&
4711 player->video360_pitch_radians >= -M_PI_2) {
4712 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4713 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4714 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4715 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4717 "source-orientation-y", player->video360_metadata.init_view_heading,
4718 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4721 if (player->is_360_feature_enabled && player->is_content_spherical)
4722 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4723 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4727 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4728 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4731 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4732 (player->videodec_linked && player->ini.use_system_clock)) {
4733 LOGD("system clock will be used.\n");
4734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4737 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4738 __mmplayer_gst_set_audiosink_property(player, attrs);
4741 if (audiobin[MMPLAYER_A_SINK].gst) {
4742 GstPad *sink_pad = NULL;
4743 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4744 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4745 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4746 gst_object_unref(GST_OBJECT(sink_pad));
4749 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4751 /* adding created elements to bin */
4752 LOGD("adding created elements to bin\n");
4753 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4754 LOGE("failed to add elements\n");
4758 /* linking elements in the bucket by added order. */
4759 LOGD("Linking elements in the bucket by added order.\n");
4760 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4761 LOGE("failed to link elements\n");
4765 /* get first element's sinkpad for creating ghostpad */
4766 first_element = (MMPlayerGstElement *)element_bucket->data;
4767 if (!first_element) {
4768 LOGE("failed to get first elem\n");
4772 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4774 LOGE("failed to get pad from first element of audiobin\n");
4778 ghostpad = gst_ghost_pad_new("sink", pad);
4780 LOGE("failed to create ghostpad\n");
4784 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4785 LOGE("failed to add ghostpad to audiobin\n");
4789 gst_object_unref(pad);
4791 g_list_free(element_bucket);
4794 return MM_ERROR_NONE;
4798 LOGD("ERROR : releasing audiobin\n");
4801 gst_object_unref(GST_OBJECT(pad));
4804 gst_object_unref(GST_OBJECT(ghostpad));
4807 g_list_free(element_bucket);
4809 /* release element which are not added to bin */
4810 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4811 /* NOTE : skip bin */
4812 if (audiobin[i].gst) {
4813 GstObject* parent = NULL;
4814 parent = gst_element_get_parent(audiobin[i].gst);
4817 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4818 audiobin[i].gst = NULL;
4820 gst_object_unref(GST_OBJECT(parent));
4824 /* release audiobin with it's childs */
4825 if (audiobin[MMPLAYER_A_BIN].gst)
4826 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4828 MMPLAYER_FREEIF(audiobin);
4830 player->pipeline->audiobin = NULL;
4832 return MM_ERROR_PLAYER_INTERNAL;
4835 static GstPadProbeReturn
4836 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4838 mm_player_t* player = (mm_player_t*) u_data;
4839 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4840 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4842 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4844 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4845 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4847 return GST_PAD_PROBE_OK;
4850 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4852 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4855 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4857 int ret = MM_ERROR_NONE;
4859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4860 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4862 MMPLAYER_VIDEO_BO_LOCK(player);
4864 if (player->video_bo_list) {
4865 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4866 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4867 if (tmp && tmp->bo == bo) {
4869 LOGD("release bo %p", bo);
4870 tbm_bo_unref(tmp->bo);
4871 MMPLAYER_VIDEO_BO_UNLOCK(player);
4872 MMPLAYER_VIDEO_BO_SIGNAL(player);
4877 /* hw codec is running or the list was reset for DRC. */
4878 LOGW("there is no bo list.");
4880 MMPLAYER_VIDEO_BO_UNLOCK(player);
4882 LOGW("failed to find bo %p", bo);
4887 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4892 MMPLAYER_RETURN_IF_FAIL(player);
4894 MMPLAYER_VIDEO_BO_LOCK(player);
4895 if (player->video_bo_list) {
4896 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4897 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4898 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4901 tbm_bo_unref(tmp->bo);
4905 g_list_free(player->video_bo_list);
4906 player->video_bo_list = NULL;
4908 player->video_bo_size = 0;
4909 MMPLAYER_VIDEO_BO_UNLOCK(player);
4916 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4919 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4920 gboolean ret = TRUE;
4922 /* check DRC, if it is, destroy the prev bo list to create again */
4923 if (player->video_bo_size != size) {
4924 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4925 __mmplayer_video_stream_destroy_bo_list(player);
4926 player->video_bo_size = size;
4929 MMPLAYER_VIDEO_BO_LOCK(player);
4931 if ((!player->video_bo_list) ||
4932 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4934 /* create bo list */
4936 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4938 if (player->video_bo_list) {
4939 /* if bo list did not created all, try it again. */
4940 idx = g_list_length(player->video_bo_list);
4941 LOGD("bo list exist(len: %d)", idx);
4944 for (; idx < player->ini.num_of_video_bo; idx++) {
4945 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4947 LOGE("Fail to alloc bo_info.");
4950 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4952 LOGE("Fail to tbm_bo_alloc.");
4956 bo_info->using = FALSE;
4957 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4960 /* update video num buffers */
4961 player->video_num_buffers = idx;
4962 if (idx == player->ini.num_of_video_bo)
4963 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4966 MMPLAYER_VIDEO_BO_UNLOCK(player);
4970 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4974 /* get bo from list*/
4975 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4976 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4977 if (tmp && (tmp->using == FALSE)) {
4978 LOGD("found bo %p to use", tmp->bo);
4980 MMPLAYER_VIDEO_BO_UNLOCK(player);
4981 return tbm_bo_ref(tmp->bo);
4985 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4986 MMPLAYER_VIDEO_BO_UNLOCK(player);
4990 if (player->ini.video_bo_timeout <= 0) {
4991 MMPLAYER_VIDEO_BO_WAIT(player);
4993 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4994 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
5001 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5003 mm_player_t* player = (mm_player_t*)data;
5005 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5007 /* send prerolled pkt */
5008 player->video_stream_prerolled = FALSE;
5010 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
5012 /* not to send prerolled pkt again */
5013 player->video_stream_prerolled = TRUE;
5017 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5019 mm_player_t* player = (mm_player_t*)data;
5020 GstCaps *caps = NULL;
5021 MMPlayerVideoStreamDataType *stream = NULL;
5022 MMVideoBuffer *video_buffer = NULL;
5023 GstMemory *dataBlock = NULL;
5024 GstMemory *metaBlock = NULL;
5025 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5026 GstStructure *structure = NULL;
5027 const gchar *string_format = NULL;
5028 unsigned int fourcc = 0;
5031 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5033 if (player->video_stream_prerolled) {
5034 player->video_stream_prerolled = FALSE;
5035 LOGD("skip the prerolled pkt not to send it again");
5039 caps = gst_pad_get_current_caps(pad);
5041 LOGE("Caps is NULL.");
5045 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5047 /* clear stream data structure */
5048 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5050 LOGE("failed to alloc mem for video data");
5054 structure = gst_caps_get_structure(caps, 0);
5055 gst_structure_get_int(structure, "width", &(stream->width));
5056 gst_structure_get_int(structure, "height", &(stream->height));
5057 string_format = gst_structure_get_string(structure, "format");
5059 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5060 stream->format = util_get_pixtype(fourcc);
5061 gst_caps_unref(caps);
5064 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5067 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5068 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5071 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5072 LOGE("Wrong condition!!");
5076 /* set size and timestamp */
5077 dataBlock = gst_buffer_peek_memory(buffer, 0);
5078 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5079 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
5081 /* check zero-copy */
5082 if (player->set_mode.video_zc &&
5083 player->set_mode.media_packet_video_stream &&
5084 gst_buffer_n_memory(buffer) > 1) {
5085 metaBlock = gst_buffer_peek_memory(buffer, 1);
5086 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5087 video_buffer = (MMVideoBuffer *)mapinfo.data;
5090 if (video_buffer) { /* hw codec */
5092 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5095 /* copy pointer of tbm bo, stride, elevation */
5096 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5097 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5101 LOGE("Not support video buffer format");
5104 memcpy(stream->stride, video_buffer->stride_width,
5105 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5106 memcpy(stream->elevation, video_buffer->stride_height,
5107 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5109 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5110 stream->internal_buffer = gst_buffer_ref(buffer);
5111 } else { /* sw codec */
5115 int ret = TBM_SURFACE_ERROR_NONE;
5116 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5117 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5119 unsigned char *src = NULL;
5120 unsigned char *dest = NULL;
5121 tbm_bo_handle thandle;
5122 tbm_surface_h surface;
5123 tbm_surface_info_s info;
5126 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5128 LOGE("fail to gst_memory_map");
5133 if (stream->format == MM_PIXEL_FORMAT_I420) {
5134 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5136 ret = tbm_surface_get_info(surface, &info);
5138 if (ret != TBM_SURFACE_ERROR_NONE) {
5139 tbm_surface_destroy(surface);
5142 tbm_surface_destroy(surface);
5144 src_stride[0] = GST_ROUND_UP_4(stream->width);
5145 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5146 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5147 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5148 stream->stride[0] = info.planes[0].stride;
5149 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5150 stream->stride[1] = info.planes[1].stride;
5151 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5152 stream->stride[2] = info.planes[2].stride;
5153 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5154 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5155 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5156 stream->stride[0] = stream->width * 4;
5157 stream->elevation[0] = stream->height;
5158 size = stream->stride[0] * stream->height;
5160 LOGE("Not support format %d", stream->format);
5164 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5165 if (!stream->bo[0]) {
5166 LOGE("Fail to tbm_bo_alloc!!");
5170 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5171 if (thandle.ptr && mapinfo.data) {
5172 if (stream->format == MM_PIXEL_FORMAT_I420) {
5173 for (i = 0; i < 3; i++) {
5174 src = mapinfo.data + src_offset[i];
5175 dest = thandle.ptr + info.planes[i].offset;
5178 for (j = 0; j < stream->height>>k; j++) {
5179 memcpy(dest, src, stream->width>>k);
5180 src += src_stride[i];
5181 dest += stream->stride[i];
5184 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5185 memcpy(thandle.ptr, mapinfo.data, size);
5187 LOGE("Not support format %d", stream->format);
5191 LOGE("data pointer is wrong. dest : %p, src : %p",
5192 thandle.ptr, mapinfo.data);
5195 tbm_bo_unmap(stream->bo[0]);
5198 if (player->video_stream_cb) { /* This has been already checked at the entry */
5199 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5200 LOGE("failed to send video stream data.");
5206 gst_memory_unmap(metaBlock, &mapinfo);
5208 gst_memory_unmap(dataBlock, &mapinfo);
5213 LOGE("release video stream resource.");
5216 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5218 tbm_bo_unref(stream->bo[i]);
5220 gst_memory_unmap(metaBlock, &mapinfo);
5222 /* unref gst buffer */
5223 if (stream->internal_buffer)
5224 gst_buffer_unref(stream->internal_buffer);
5225 } else if (dataBlock) {
5227 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5228 gst_memory_unmap(dataBlock, &mapinfo);
5236 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5238 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5239 GList* element_bucket = NULL;
5241 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5246 LOGD("do not need to add video filters.");
5247 return MM_ERROR_NONE;
5250 /* in case of sw codec except 360 playback,
5251 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5252 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5253 LOGD("using video converter: %s", video_csc);
5255 /* set video rotator */
5256 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5258 *bucket = element_bucket;
5260 return MM_ERROR_NONE;
5262 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5263 g_list_free(element_bucket);
5267 return MM_ERROR_PLAYER_INTERNAL;
5271 * This function is to create video pipeline.
5273 * @param player [in] handle of player
5274 * caps [in] src caps of decoder
5275 * surface_type [in] surface type for video rendering
5277 * @return This function returns zero on success.
5279 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5283 * - video overlay surface(arm/x86) : tizenwlsink
5286 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5290 GList*element_bucket = NULL;
5291 MMPlayerGstElement* first_element = NULL;
5292 MMPlayerGstElement* videobin = NULL;
5293 gchar *videosink_element = NULL;
5297 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5300 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5302 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5304 player->pipeline->videobin = videobin;
5306 attrs = MMPLAYER_GET_ATTRS(player);
5308 LOGE("cannot get content attribute");
5309 return MM_ERROR_PLAYER_INTERNAL;
5313 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5314 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5315 if (!videobin[MMPLAYER_V_BIN].gst) {
5316 LOGE("failed to create videobin");
5320 int enable_video_decoded_cb = 0;
5321 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5323 if (player->is_360_feature_enabled && player->is_content_spherical) {
5324 LOGD("video360 elem will be added.");
5326 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5327 "video-360", TRUE, player);
5329 /* Set spatial media metadata and/or user settings to the element.
5331 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5332 "projection-type", player->video360_metadata.projection_type, NULL);
5334 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5335 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5337 if (player->video360_metadata.full_pano_width_pixels &&
5338 player->video360_metadata.full_pano_height_pixels &&
5339 player->video360_metadata.cropped_area_image_width &&
5340 player->video360_metadata.cropped_area_image_height) {
5341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5342 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5343 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5344 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5345 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5346 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5347 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5351 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5352 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5353 "horizontal-fov", player->video360_horizontal_fov,
5354 "vertical-fov", player->video360_vertical_fov, NULL);
5357 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5358 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5359 "zoom", 1.0f / player->video360_zoom, NULL);
5362 if (player->video360_yaw_radians <= M_PI &&
5363 player->video360_yaw_radians >= -M_PI &&
5364 player->video360_pitch_radians <= M_PI_2 &&
5365 player->video360_pitch_radians >= -M_PI_2) {
5366 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5367 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5368 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5369 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5370 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5371 "pose-yaw", player->video360_metadata.init_view_heading,
5372 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5375 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5376 "passthrough", !player->is_video360_enabled, NULL);
5379 /* set video sink */
5380 switch (surface_type) {
5381 case MM_DISPLAY_SURFACE_OVERLAY:
5382 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5384 if (strlen(player->ini.videosink_element_overlay) > 0)
5385 videosink_element = player->ini.videosink_element_overlay;
5389 case MM_DISPLAY_SURFACE_NULL:
5390 if (strlen(player->ini.videosink_element_fake) > 0)
5391 videosink_element = player->ini.videosink_element_fake;
5395 case MM_DISPLAY_SURFACE_REMOTE:
5396 if (strlen(player->ini.videosink_element_fake) > 0)
5397 videosink_element = player->ini.videosink_element_fake;
5402 LOGE("unidentified surface type");
5405 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5407 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5409 /* additional setting for sink plug-in */
5410 switch (surface_type) {
5411 case MM_DISPLAY_SURFACE_OVERLAY:
5413 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5415 LOGD("selected videosink name: %s", videosink_element);
5417 /* support shard memory with S/W codec on HawkP */
5418 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5419 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5420 "use-tbm", use_tbm, NULL);
5426 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5429 LOGD("disable last-sample");
5430 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5434 if (player->set_mode.media_packet_video_stream) {
5436 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5438 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5440 MMPLAYER_SIGNAL_CONNECT(player,
5441 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5442 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5444 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5447 MMPLAYER_SIGNAL_CONNECT(player,
5448 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5449 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5451 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5456 case MM_DISPLAY_SURFACE_REMOTE:
5458 if (player->set_mode.media_packet_video_stream) {
5459 LOGE("add data probe at videosink");
5460 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5461 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5463 MMPLAYER_SIGNAL_CONNECT(player,
5464 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5465 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5467 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5470 MMPLAYER_SIGNAL_CONNECT(player,
5471 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5472 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5474 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5479 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5482 LOGD("disable last-sample");
5483 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5493 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5496 if (videobin[MMPLAYER_V_SINK].gst) {
5497 GstPad *sink_pad = NULL;
5498 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5500 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5501 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5502 gst_object_unref(GST_OBJECT(sink_pad));
5504 LOGW("failed to get sink pad from videosink\n");
5507 /* store it as it's sink element */
5508 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5510 /* adding created elements to bin */
5511 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5512 LOGE("failed to add elements\n");
5516 /* Linking elements in the bucket by added order */
5517 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5518 LOGE("failed to link elements\n");
5522 /* get first element's sinkpad for creating ghostpad */
5524 first_element = (MMPlayerGstElement *)element_bucket->data;
5525 if (!first_element) {
5526 LOGE("failed to get first element from bucket\n");
5530 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5532 LOGE("failed to get pad from first element\n");
5536 /* create ghostpad */
5537 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5538 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5539 LOGE("failed to add ghostpad to videobin\n");
5542 gst_object_unref(pad);
5544 /* done. free allocated variables */
5546 g_list_free(element_bucket);
5550 return MM_ERROR_NONE;
5553 LOGE("ERROR : releasing videobin\n");
5555 g_list_free(element_bucket);
5558 gst_object_unref(GST_OBJECT(pad));
5560 /* release videobin with it's childs */
5561 if (videobin[MMPLAYER_V_BIN].gst)
5562 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5565 MMPLAYER_FREEIF(videobin);
5567 player->pipeline->videobin = NULL;
5569 return MM_ERROR_PLAYER_INTERNAL;
5572 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5574 GList *element_bucket = NULL;
5575 MMPlayerGstElement *textbin = player->pipeline->textbin;
5577 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5578 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5579 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5580 "signal-handoffs", FALSE,
5583 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5584 MMPLAYER_SIGNAL_CONNECT(player,
5585 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5586 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5588 G_CALLBACK(__mmplayer_update_subtitle),
5591 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5592 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5593 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5595 if (!player->play_subtitle) {
5596 LOGD("add textbin sink as sink element of whole pipeline.\n");
5597 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5600 /* adding created elements to bin */
5601 LOGD("adding created elements to bin\n");
5602 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5603 LOGE("failed to add elements\n");
5607 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5608 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5609 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5611 /* linking elements in the bucket by added order. */
5612 LOGD("Linking elements in the bucket by added order.\n");
5613 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5614 LOGE("failed to link elements\n");
5618 /* done. free allocated variables */
5619 g_list_free(element_bucket);
5621 if (textbin[MMPLAYER_T_QUEUE].gst) {
5623 GstPad *ghostpad = NULL;
5625 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5627 LOGE("failed to get sink pad of text queue");
5631 ghostpad = gst_ghost_pad_new("text_sink", pad);
5632 gst_object_unref(pad);
5635 LOGE("failed to create ghostpad of textbin\n");
5639 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5640 LOGE("failed to add ghostpad to textbin\n");
5641 gst_object_unref(ghostpad);
5646 return MM_ERROR_NONE;
5649 g_list_free(element_bucket);
5651 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5652 LOGE("remove textbin sink from sink list");
5653 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5656 /* release element at __mmplayer_gst_create_text_sink_bin */
5657 return MM_ERROR_PLAYER_INTERNAL;
5660 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5662 MMPlayerGstElement *textbin = NULL;
5663 GList *element_bucket = NULL;
5664 int surface_type = 0;
5669 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5672 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5674 LOGE("failed to allocate memory for textbin\n");
5675 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5679 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5680 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5681 if (!textbin[MMPLAYER_T_BIN].gst) {
5682 LOGE("failed to create textbin\n");
5687 player->pipeline->textbin = textbin;
5690 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5691 LOGD("surface type for subtitle : %d", surface_type);
5692 switch (surface_type) {
5693 case MM_DISPLAY_SURFACE_OVERLAY:
5694 case MM_DISPLAY_SURFACE_NULL:
5695 case MM_DISPLAY_SURFACE_REMOTE:
5696 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5697 LOGE("failed to make plain text elements\n");
5708 return MM_ERROR_NONE;
5712 LOGD("ERROR : releasing textbin\n");
5714 g_list_free(element_bucket);
5716 /* release signal */
5717 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5719 /* release element which are not added to bin */
5720 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5721 /* NOTE : skip bin */
5722 if (textbin[i].gst) {
5723 GstObject* parent = NULL;
5724 parent = gst_element_get_parent(textbin[i].gst);
5727 gst_object_unref(GST_OBJECT(textbin[i].gst));
5728 textbin[i].gst = NULL;
5730 gst_object_unref(GST_OBJECT(parent));
5735 /* release textbin with it's childs */
5736 if (textbin[MMPLAYER_T_BIN].gst)
5737 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5739 MMPLAYER_FREEIF(player->pipeline->textbin);
5740 player->pipeline->textbin = NULL;
5743 return MM_ERROR_PLAYER_INTERNAL;
5748 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5750 MMPlayerGstElement* mainbin = NULL;
5751 MMPlayerGstElement* textbin = NULL;
5752 MMHandleType attrs = 0;
5753 GstElement *subsrc = NULL;
5754 GstElement *subparse = NULL;
5755 gchar *subtitle_uri = NULL;
5756 const gchar *charset = NULL;
5762 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5764 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5766 mainbin = player->pipeline->mainbin;
5768 attrs = MMPLAYER_GET_ATTRS(player);
5770 LOGE("cannot get content attribute\n");
5771 return MM_ERROR_PLAYER_INTERNAL;
5774 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5775 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5776 LOGE("subtitle uri is not proper filepath.\n");
5777 return MM_ERROR_PLAYER_INVALID_URI;
5780 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5781 LOGE("failed to get storage info of subtitle path");
5782 return MM_ERROR_PLAYER_INVALID_URI;
5785 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5787 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5788 player->subtitle_language_list = NULL;
5789 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5791 /* create the subtitle source */
5792 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5794 LOGE("failed to create filesrc element\n");
5797 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5799 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5800 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5802 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5803 LOGW("failed to add queue\n");
5804 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5805 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5806 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5811 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5813 LOGE("failed to create subparse element\n");
5817 charset = util_get_charset(subtitle_uri);
5819 LOGD("detected charset is %s\n", charset);
5820 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5823 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5824 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5826 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5827 LOGW("failed to add subparse\n");
5828 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5829 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5830 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5834 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5835 LOGW("failed to link subsrc and subparse\n");
5839 player->play_subtitle = TRUE;
5840 player->adjust_subtitle_pos = 0;
5842 LOGD("play subtitle using subtitle file\n");
5844 if (player->pipeline->textbin == NULL) {
5845 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5846 LOGE("failed to create text sink bin. continuing without text\n");
5850 textbin = player->pipeline->textbin;
5852 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5853 LOGW("failed to add textbin\n");
5855 /* release signal */
5856 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5858 /* release textbin with it's childs */
5859 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5860 MMPLAYER_FREEIF(player->pipeline->textbin);
5861 player->pipeline->textbin = textbin = NULL;
5865 LOGD("link text input selector and textbin ghost pad");
5867 player->textsink_linked = 1;
5868 player->external_text_idx = 0;
5869 LOGI("player->textsink_linked set to 1\n");
5871 textbin = player->pipeline->textbin;
5872 LOGD("text bin has been created. reuse it.");
5873 player->external_text_idx = 1;
5876 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5877 LOGW("failed to link subparse and textbin\n");
5881 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5883 LOGE("failed to get sink pad from textsink to probe data");
5887 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5888 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5890 gst_object_unref(pad);
5893 /* create dot. for debugging */
5894 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5897 return MM_ERROR_NONE;
5900 /* release text pipeline resource */
5901 player->textsink_linked = 0;
5903 /* release signal */
5904 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5906 if (player->pipeline->textbin) {
5907 LOGE("remove textbin");
5909 /* release textbin with it's childs */
5910 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5911 MMPLAYER_FREEIF(player->pipeline->textbin);
5912 player->pipeline->textbin = NULL;
5916 /* release subtitle elem */
5917 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5918 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5920 return MM_ERROR_PLAYER_INTERNAL;
5924 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5926 mm_player_t* player = (mm_player_t*) data;
5927 MMMessageParamType msg = {0, };
5928 GstClockTime duration = 0;
5929 gpointer text = NULL;
5930 guint text_size = 0;
5931 gboolean ret = TRUE;
5932 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5936 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5937 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5939 if (player->is_subtitle_force_drop) {
5940 LOGW("subtitle is dropped forcedly.");
5944 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5945 text = mapinfo.data;
5946 text_size = mapinfo.size;
5947 duration = GST_BUFFER_DURATION(buffer);
5949 if (player->set_mode.subtitle_off) {
5950 LOGD("subtitle is OFF.\n");
5954 if (!text || (text_size == 0)) {
5955 LOGD("There is no subtitle to be displayed.\n");
5959 msg.data = (void *) text;
5960 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5962 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5964 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5965 gst_buffer_unmap(buffer, &mapinfo);
5972 static GstPadProbeReturn
5973 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5975 mm_player_t *player = (mm_player_t *) u_data;
5976 GstClockTime cur_timestamp = 0;
5977 gint64 adjusted_timestamp = 0;
5978 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5980 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5982 if (player->set_mode.subtitle_off) {
5983 LOGD("subtitle is OFF.\n");
5987 if (player->adjust_subtitle_pos == 0) {
5988 LOGD("nothing to do");
5992 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5993 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5995 if (adjusted_timestamp < 0) {
5996 LOGD("adjusted_timestamp under zero");
6001 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
6002 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
6003 GST_TIME_ARGS(cur_timestamp),
6004 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
6006 return GST_PAD_PROBE_OK;
6008 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
6012 /* check player and subtitlebin are created */
6013 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6014 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6016 if (position == 0) {
6017 LOGD("nothing to do\n");
6019 return MM_ERROR_NONE;
6023 case MM_PLAYER_POS_FORMAT_TIME:
6025 /* check current postion */
6026 player->adjust_subtitle_pos = position;
6028 LOGD("save adjust_subtitle_pos in player") ;
6034 LOGW("invalid format.\n");
6036 return MM_ERROR_INVALID_ARGUMENT;
6042 return MM_ERROR_NONE;
6046 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6048 GstElement *appsrc = element;
6049 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6050 GstBuffer *buffer = NULL;
6051 GstFlowReturn ret = GST_FLOW_OK;
6054 MMPLAYER_RETURN_IF_FAIL(element);
6055 MMPLAYER_RETURN_IF_FAIL(buf);
6057 buffer = gst_buffer_new();
6059 if (buf->offset >= buf->len) {
6060 LOGD("call eos appsrc\n");
6061 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6065 if (buf->len - buf->offset < size)
6066 len = buf->len - buf->offset;
6068 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6069 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6070 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6072 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6073 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6079 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6081 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6083 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6085 buf->offset = (int)size;
6090 static GstBusSyncReply
6091 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6093 mm_player_t *player = (mm_player_t *)data;
6094 GstBusSyncReply reply = GST_BUS_DROP;
6096 if (!(player->pipeline && player->pipeline->mainbin)) {
6097 LOGE("player pipeline handle is null");
6098 return GST_BUS_PASS;
6101 if (!__mmplayer_check_useful_message(player, message)) {
6102 gst_message_unref(message);
6103 return GST_BUS_DROP;
6106 switch (GST_MESSAGE_TYPE(message)) {
6107 case GST_MESSAGE_STATE_CHANGED:
6108 /* post directly for fast launch */
6109 if (player->sync_handler) {
6110 __mmplayer_gst_callback(message, player);
6111 reply = GST_BUS_DROP;
6113 reply = GST_BUS_PASS;
6115 case GST_MESSAGE_TAG:
6116 __mmplayer_gst_extract_tag_from_msg(player, message);
6120 GstTagList *tags = NULL;
6122 gst_message_parse_tag(message, &tags);
6124 LOGE("TAGS received from element \"%s\".\n",
6125 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6127 gst_tag_list_foreach(tags, print_tag, NULL);
6128 gst_tag_list_free(tags);
6136 case GST_MESSAGE_DURATION_CHANGED:
6137 __mmplayer_gst_handle_duration(player, message);
6139 case GST_MESSAGE_ASYNC_DONE:
6140 /* NOTE:Don't call gst_callback directly
6141 * because previous frame can be showed even though this message is received for seek.
6144 reply = GST_BUS_PASS;
6148 if (reply == GST_BUS_DROP)
6149 gst_message_unref(message);
6155 __mmplayer_gst_create_decoder(mm_player_t *player,
6156 MMPlayerTrackType track,
6158 enum MainElementID elemId,
6161 gboolean ret = TRUE;
6162 GstPad *sinkpad = NULL;
6166 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6168 player->pipeline->mainbin, FALSE);
6169 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6170 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6171 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6173 GstElement *decodebin = NULL;
6174 GstCaps *dec_caps = NULL;
6176 /* create decodebin */
6177 decodebin = gst_element_factory_make("decodebin", name);
6180 LOGE("error : fail to create decodebin for %d decoder\n", track);
6185 /* raw pad handling signal */
6186 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6187 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6189 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6190 before looking for any elements that can handle that stream.*/
6191 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6192 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6194 /* This signal is emitted when a element is added to the bin.*/
6195 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6196 G_CALLBACK(__mmplayer_gst_element_added), player);
6198 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6199 LOGE("failed to add new decodebin\n");
6204 dec_caps = gst_pad_query_caps(srcpad, NULL);
6206 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6207 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6208 gst_caps_unref(dec_caps);
6211 player->pipeline->mainbin[elemId].id = elemId;
6212 player->pipeline->mainbin[elemId].gst = decodebin;
6214 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6216 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6217 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6218 gst_object_unref(GST_OBJECT(decodebin));
6221 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6222 LOGE("failed to sync second level decodebin state with parent\n");
6224 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6228 gst_object_unref(GST_OBJECT(sinkpad));
6237 * This function is to create audio or video pipeline for playing.
6239 * @param player [in] handle of player
6241 * @return This function returns zero on success.
6246 __mmplayer_gst_create_pipeline(mm_player_t* player)
6249 MMPlayerGstElement *mainbin = NULL;
6250 MMHandleType attrs = 0;
6251 GstElement* element = NULL;
6252 GstElement* elem_src_audio = NULL;
6253 GstElement* elem_src_subtitle = NULL;
6254 GstElement* es_video_queue = NULL;
6255 GstElement* es_audio_queue = NULL;
6256 GstElement* es_subtitle_queue = NULL;
6257 GList* element_bucket = NULL;
6258 gboolean need_state_holder = TRUE;
6260 #ifdef SW_CODEC_ONLY
6261 int surface_type = 0;
6265 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6267 /* get profile attribute */
6268 attrs = MMPLAYER_GET_ATTRS(player);
6270 LOGE("cannot get content attribute\n");
6274 /* create pipeline handles */
6275 if (player->pipeline) {
6276 LOGW("pipeline should be released before create new one\n");
6280 player->video360_metadata.is_spherical = -1;
6281 player->is_openal_plugin_used = FALSE;
6283 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6284 if (player->pipeline == NULL)
6287 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6289 /* create mainbin */
6290 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6291 if (mainbin == NULL)
6294 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6296 /* create pipeline */
6297 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6298 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6299 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6300 LOGE("failed to create pipeline\n");
6303 player->demux_pad_index = 0;
6304 player->subtitle_language_list = NULL;
6306 player->is_subtitle_force_drop = FALSE;
6307 player->last_multiwin_status = FALSE;
6309 _mmplayer_track_initialize(player);
6310 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6312 /* create source element */
6313 switch (player->profile.uri_type) {
6314 /* rtsp streamming */
6315 case MM_PLAYER_URI_TYPE_URL_RTSP:
6319 element = gst_element_factory_make("rtspsrc", "rtsp source");
6322 LOGE("failed to create streaming source element\n");
6330 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6332 SECURE_LOGD("user_agent : %s\n", user_agent);
6334 /* setting property to streaming source */
6335 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6337 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6339 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6340 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6341 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6342 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6347 case MM_PLAYER_URI_TYPE_URL_HTTP:
6349 gchar *user_agent, *cookies, **cookie_list;
6350 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6351 user_agent = cookies = NULL;
6353 gint mode = MM_PLAYER_PD_MODE_NONE;
6355 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6357 player->pd_mode = mode;
6359 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6361 if (!MMPLAYER_IS_HTTP_PD(player)) {
6362 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6364 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6367 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6370 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6371 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6373 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6374 LOGD("get timeout from ini\n");
6375 http_timeout = player->ini.http_timeout;
6379 SECURE_LOGD("location : %s\n", player->profile.uri);
6380 SECURE_LOGD("cookies : %s\n", cookies);
6381 SECURE_LOGD("user_agent : %s\n", user_agent);
6382 LOGD("timeout : %d\n", http_timeout);
6384 /* setting property to streaming source */
6385 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6386 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6387 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6389 /* parsing cookies */
6390 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6391 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6392 g_strfreev(cookie_list);
6395 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6397 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6398 LOGW("it's dash. and it's still experimental feature.");
6400 // progressive download
6401 gchar* location = NULL;
6403 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6406 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6408 MMPLAYER_FREEIF(player->pd_file_save_path);
6410 LOGD("PD Location : %s\n", path);
6413 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6414 LOGE("failed to get storage info");
6417 player->pd_file_save_path = g_strdup(path);
6419 LOGE("can't find pd location so, it should be set \n");
6424 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6426 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6430 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6431 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6433 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6434 g_object_get(element, "location", &location, NULL);
6435 LOGD("PD_LOCATION [%s].\n", location);
6443 case MM_PLAYER_URI_TYPE_FILE:
6445 LOGD("using filesrc for 'file://' handler.\n");
6446 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6447 LOGE("failed to get storage info");
6451 element = gst_element_factory_make("filesrc", "source");
6453 LOGE("failed to create filesrc\n");
6457 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6461 case MM_PLAYER_URI_TYPE_SS:
6463 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6464 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6466 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6470 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6471 LOGD("get timeout from ini\n");
6472 http_timeout = player->ini.http_timeout;
6475 /* setting property to streaming source */
6476 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6477 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6480 case MM_PLAYER_URI_TYPE_MS_BUFF:
6482 LOGD("MS buff src is selected\n");
6484 if (player->v_stream_caps) {
6485 element = gst_element_factory_make("appsrc", "video_appsrc");
6487 LOGF("failed to create video app source element[appsrc].\n");
6491 if (player->a_stream_caps) {
6492 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6493 if (!elem_src_audio) {
6494 LOGF("failed to create audio app source element[appsrc].\n");
6498 } else if (player->a_stream_caps) {
6499 /* no video, only audio pipeline*/
6500 element = gst_element_factory_make("appsrc", "audio_appsrc");
6502 LOGF("failed to create audio app source element[appsrc].\n");
6507 if (player->s_stream_caps) {
6508 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6509 if (!elem_src_subtitle) {
6510 LOGF("failed to create subtitle app source element[appsrc].\n");
6515 LOGD("setting app sources properties.\n");
6516 LOGD("location : %s\n", player->profile.uri);
6518 if (player->v_stream_caps && element) {
6519 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6520 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6521 "caps", player->v_stream_caps, NULL);
6523 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6524 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6525 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6526 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6528 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6529 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6530 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6531 G_CALLBACK(__gst_seek_video_data), player);
6533 if (player->a_stream_caps && elem_src_audio) {
6534 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6535 "caps", player->a_stream_caps, NULL);
6537 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6538 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6539 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6540 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6542 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6543 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6544 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6545 G_CALLBACK(__gst_seek_audio_data), player);
6547 } else if (player->a_stream_caps && element) {
6548 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6549 "caps", player->a_stream_caps, NULL);
6551 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6552 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6553 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6554 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6556 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6557 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6558 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6559 G_CALLBACK(__gst_seek_audio_data), player);
6562 if (player->s_stream_caps && elem_src_subtitle) {
6563 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6564 "caps", player->s_stream_caps, NULL);
6566 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6567 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6568 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6569 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6571 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6573 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6574 G_CALLBACK(__gst_seek_subtitle_data), player);
6577 if (player->v_stream_caps && element) {
6578 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6579 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6580 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6581 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6583 if (player->a_stream_caps && elem_src_audio) {
6584 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6585 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6586 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6587 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6589 } else if (player->a_stream_caps && element) {
6590 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6591 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6592 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6593 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6596 if (player->s_stream_caps && elem_src_subtitle)
6597 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6598 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6600 need_state_holder = FALSE;
6602 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6603 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6604 LOGE("failed to commit\n");
6608 case MM_PLAYER_URI_TYPE_MEM:
6610 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6612 LOGD("mem src is selected\n");
6614 element = gst_element_factory_make("appsrc", "mem-source");
6616 LOGE("failed to create appsrc element\n");
6620 g_object_set(element, "stream-type", stream_type, NULL);
6621 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6622 g_object_set(element, "blocksize", (guint64)20480, NULL);
6624 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6625 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6626 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6627 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6630 case MM_PLAYER_URI_TYPE_URL:
6633 case MM_PLAYER_URI_TYPE_TEMP:
6636 case MM_PLAYER_URI_TYPE_NONE:
6641 /* check source element is OK */
6643 LOGE("no source element was created.\n");
6647 /* take source element */
6648 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6649 mainbin[MMPLAYER_M_SRC].gst = element;
6650 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6652 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6653 player->streamer = __mm_player_streaming_create();
6654 __mm_player_streaming_initialize(player->streamer);
6657 if (MMPLAYER_IS_HTTP_PD(player)) {
6658 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6660 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6661 element = gst_element_factory_make("queue2", "queue2");
6663 LOGE("failed to create http streaming buffer element\n");
6668 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6669 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6670 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6672 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6674 player->streamer->is_pd_mode = TRUE;
6676 __mm_player_streaming_set_queue2(player->streamer,
6679 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6682 player->ini.http_buffering_limit,
6683 MUXED_BUFFER_TYPE_MEM_QUEUE,
6687 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6688 if (player->v_stream_caps) {
6689 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6690 if (!es_video_queue) {
6691 LOGE("create es_video_queue for es player failed\n");
6694 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6695 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6696 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6697 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6699 /* Adding audio appsrc to bucket */
6700 if (player->a_stream_caps && elem_src_audio) {
6701 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6702 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6703 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6705 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6706 if (!es_audio_queue) {
6707 LOGE("create es_audio_queue for es player failed\n");
6710 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6712 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6713 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6714 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6716 } else if (player->a_stream_caps) {
6717 /* Only audio stream, no video */
6718 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6719 if (!es_audio_queue) {
6720 LOGE("create es_audio_queue for es player failed\n");
6723 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6724 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6725 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6728 if (player->s_stream_caps && elem_src_subtitle) {
6729 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6730 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6731 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6733 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6734 if (!es_subtitle_queue) {
6735 LOGE("create es_subtitle_queue for es player failed\n");
6738 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6739 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6740 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6744 /* create autoplugging element if src element is not a rtsp src */
6745 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6746 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6748 enum MainElementID elemId = MMPLAYER_M_NUM;
6750 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6751 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6752 elemId = MMPLAYER_M_AUTOPLUG;
6753 element = __mmplayer_create_decodebin(player);
6755 /* default size of mq in decodebin is 2M
6756 * but it can cause blocking issue during seeking depends on content. */
6757 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6759 need_state_holder = FALSE;
6761 elemId = MMPLAYER_M_TYPEFIND;
6762 element = gst_element_factory_make("typefind", "typefinder");
6763 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6764 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6768 /* check autoplug element is OK */
6770 LOGE("can not create element(%d)\n", elemId);
6774 mainbin[elemId].id = elemId;
6775 mainbin[elemId].gst = element;
6777 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6780 /* add elements to pipeline */
6781 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6782 LOGE("Failed to add elements to pipeline\n");
6787 /* linking elements in the bucket by added order. */
6788 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6789 LOGE("Failed to link some elements\n");
6794 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6795 if (need_state_holder) {
6797 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6798 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6800 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6801 LOGE("fakesink element could not be created\n");
6804 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6806 /* take ownership of fakesink. we are reusing it */
6807 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6810 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6811 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6812 LOGE("failed to add fakesink to bin\n");
6817 /* now we have completed mainbin. take it */
6818 player->pipeline->mainbin = mainbin;
6820 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6821 GstPad *srcpad = NULL;
6823 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6824 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6826 __mmplayer_gst_create_decoder(player,
6827 MM_PLAYER_TRACK_TYPE_VIDEO,
6829 MMPLAYER_M_AUTOPLUG_V_DEC,
6832 gst_object_unref(GST_OBJECT(srcpad));
6837 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6838 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6840 __mmplayer_gst_create_decoder(player,
6841 MM_PLAYER_TRACK_TYPE_AUDIO,
6843 MMPLAYER_M_AUTOPLUG_A_DEC,
6846 gst_object_unref(GST_OBJECT(srcpad));
6851 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6852 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6855 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6856 if (__mmplayer_check_subtitle(player)) {
6857 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6858 LOGE("fail to create text pipeline");
6861 /* connect bus callback */
6862 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6864 LOGE("cannot get bus from pipeline.\n");
6868 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6870 player->context.thread_default = g_main_context_get_thread_default();
6872 if (player->context.thread_default == NULL) {
6873 player->context.thread_default = g_main_context_default();
6874 LOGD("thread-default context is the global default context");
6876 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6878 /* set sync handler to get tag synchronously */
6879 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6882 gst_object_unref(GST_OBJECT(bus));
6883 g_list_free(element_bucket);
6885 /* create gst bus_msb_cb thread */
6886 g_mutex_init(&player->bus_msg_thread_mutex);
6887 g_cond_init(&player->bus_msg_thread_cond);
6888 player->bus_msg_thread_exit = FALSE;
6889 player->bus_msg_thread =
6890 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6891 if (!player->bus_msg_thread) {
6892 LOGE("failed to create gst BUS msg thread");
6893 g_mutex_clear(&player->bus_msg_thread_mutex);
6894 g_cond_clear(&player->bus_msg_thread_cond);
6900 return MM_ERROR_NONE;
6903 __mmplayer_gst_destroy_pipeline(player);
6904 g_list_free(element_bucket);
6907 /* release element which are not added to bin */
6908 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6909 /* NOTE : skip pipeline */
6910 if (mainbin[i].gst) {
6911 GstObject* parent = NULL;
6912 parent = gst_element_get_parent(mainbin[i].gst);
6915 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6916 mainbin[i].gst = NULL;
6918 gst_object_unref(GST_OBJECT(parent));
6922 /* release pipeline with it's childs */
6923 if (mainbin[MMPLAYER_M_PIPE].gst)
6924 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6926 MMPLAYER_FREEIF(mainbin);
6929 MMPLAYER_FREEIF(player->pipeline);
6930 return MM_ERROR_PLAYER_INTERNAL;
6934 __mmplayer_reset_gapless_state(mm_player_t* player)
6937 MMPLAYER_RETURN_IF_FAIL(player
6939 && player->pipeline->audiobin
6940 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6942 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6949 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6952 int ret = MM_ERROR_NONE;
6956 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6958 /* cleanup stuffs */
6959 MMPLAYER_FREEIF(player->type);
6960 player->have_dynamic_pad = FALSE;
6961 player->no_more_pad = FALSE;
6962 player->num_dynamic_pad = 0;
6963 player->demux_pad_index = 0;
6964 player->use_deinterleave = FALSE;
6965 player->max_audio_channels = 0;
6966 player->video_share_api_delta = 0;
6967 player->video_share_clock_delta = 0;
6968 player->video_hub_download_mode = 0;
6970 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6971 player->subtitle_language_list = NULL;
6972 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6974 __mmplayer_reset_gapless_state(player);
6976 if (player->streamer) {
6977 __mm_player_streaming_deinitialize(player->streamer);
6978 __mm_player_streaming_destroy(player->streamer);
6979 player->streamer = NULL;
6982 /* cleanup unlinked mime type */
6983 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6984 MMPLAYER_FREEIF(player->unlinked_video_mime);
6985 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6987 /* cleanup running stuffs */
6988 __mmplayer_cancel_eos_timer(player);
6990 /* cleanup gst stuffs */
6991 if (player->pipeline) {
6992 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6993 GstTagList* tag_list = player->pipeline->tag_list;
6995 /* first we need to disconnect all signal hander */
6996 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6999 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7000 MMPlayerGstElement* videobin = player->pipeline->videobin;
7001 MMPlayerGstElement* textbin = player->pipeline->textbin;
7002 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7003 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7004 gst_object_unref(bus);
7006 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7007 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7008 if (ret != MM_ERROR_NONE) {
7009 LOGE("fail to change state to NULL\n");
7010 return MM_ERROR_PLAYER_INTERNAL;
7013 LOGW("succeeded in chaning state to NULL\n");
7015 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7018 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7019 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7021 /* free avsysaudiosink
7022 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7023 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7025 MMPLAYER_FREEIF(audiobin);
7026 MMPLAYER_FREEIF(videobin);
7027 MMPLAYER_FREEIF(textbin);
7028 MMPLAYER_FREEIF(mainbin);
7032 gst_tag_list_free(tag_list);
7034 MMPLAYER_FREEIF(player->pipeline);
7036 MMPLAYER_FREEIF(player->album_art);
7038 if (player->v_stream_caps) {
7039 gst_caps_unref(player->v_stream_caps);
7040 player->v_stream_caps = NULL;
7042 if (player->a_stream_caps) {
7043 gst_caps_unref(player->a_stream_caps);
7044 player->a_stream_caps = NULL;
7047 if (player->s_stream_caps) {
7048 gst_caps_unref(player->s_stream_caps);
7049 player->s_stream_caps = NULL;
7051 _mmplayer_track_destroy(player);
7053 if (player->sink_elements)
7054 g_list_free(player->sink_elements);
7055 player->sink_elements = NULL;
7057 if (player->bufmgr) {
7058 tbm_bufmgr_deinit(player->bufmgr);
7059 player->bufmgr = NULL;
7062 LOGW("finished destroy pipeline\n");
7069 static int __gst_realize(mm_player_t* player)
7072 int ret = MM_ERROR_NONE;
7076 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7078 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7080 ret = __mmplayer_gst_create_pipeline(player);
7082 LOGE("failed to create pipeline\n");
7086 /* set pipeline state to READY */
7087 /* NOTE : state change to READY must be performed sync. */
7088 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7089 ret = __mmplayer_gst_set_state(player,
7090 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7092 if (ret != MM_ERROR_NONE) {
7093 /* return error if failed to set state */
7094 LOGE("failed to set READY state");
7098 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7100 /* create dot before error-return. for debugging */
7101 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7108 static int __gst_unrealize(mm_player_t* player)
7110 int ret = MM_ERROR_NONE;
7114 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7116 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7117 MMPLAYER_PRINT_STATE(player);
7119 /* release miscellaneous information */
7120 __mmplayer_release_misc(player);
7122 /* destroy pipeline */
7123 ret = __mmplayer_gst_destroy_pipeline(player);
7124 if (ret != MM_ERROR_NONE) {
7125 LOGE("failed to destory pipeline\n");
7129 /* release miscellaneous information.
7130 these info needs to be released after pipeline is destroyed. */
7131 __mmplayer_release_misc_post(player);
7133 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7140 static int __gst_pending_seek(mm_player_t* player)
7142 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7143 int ret = MM_ERROR_NONE;
7147 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7149 if (!player->pending_seek.is_pending) {
7150 LOGD("pending seek is not reserved. nothing to do.\n");
7154 /* check player state if player could pending seek or not. */
7155 current_state = MMPLAYER_CURRENT_STATE(player);
7157 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7158 LOGW("try to pending seek in %s state, try next time. \n",
7159 MMPLAYER_STATE_GET_NAME(current_state));
7163 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7165 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7167 if (MM_ERROR_NONE != ret)
7168 LOGE("failed to seek pending postion. just keep staying current position.\n");
7170 player->pending_seek.is_pending = FALSE;
7177 static int __gst_start(mm_player_t* player)
7179 gboolean sound_extraction = 0;
7180 int ret = MM_ERROR_NONE;
7181 gboolean async = FALSE;
7185 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7187 /* get sound_extraction property */
7188 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7190 /* NOTE : if SetPosition was called before Start. do it now */
7191 /* streaming doesn't support it. so it should be always sync */
7192 /* !!create one more api to check if there is pending seek rather than checking variables */
7193 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7194 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7195 ret = __gst_pause(player, FALSE);
7196 if (ret != MM_ERROR_NONE) {
7197 LOGE("failed to set state to PAUSED for pending seek\n");
7201 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7203 if (sound_extraction) {
7204 LOGD("setting pcm extraction\n");
7206 ret = __mmplayer_set_pcm_extraction(player);
7207 if (MM_ERROR_NONE != ret) {
7208 LOGW("failed to set pcm extraction\n");
7212 if (MM_ERROR_NONE != __gst_pending_seek(player))
7213 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7217 LOGD("current state before doing transition");
7218 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7219 MMPLAYER_PRINT_STATE(player);
7221 /* set pipeline state to PLAYING */
7222 if (player->es_player_push_mode)
7224 /* set pipeline state to PLAYING */
7225 ret = __mmplayer_gst_set_state(player,
7226 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7228 if (ret == MM_ERROR_NONE) {
7229 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7231 LOGE("failed to set state to PLAYING");
7235 /* generating debug info before returning error */
7236 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7243 static int __gst_stop(mm_player_t* player)
7245 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7246 MMHandleType attrs = 0;
7247 gboolean rewind = FALSE;
7249 int ret = MM_ERROR_NONE;
7250 gboolean async = FALSE;
7254 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7255 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7257 LOGD("current state before doing transition");
7258 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7259 MMPLAYER_PRINT_STATE(player);
7261 attrs = MMPLAYER_GET_ATTRS(player);
7263 LOGE("cannot get content attribute\n");
7264 return MM_ERROR_PLAYER_INTERNAL;
7267 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7268 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7270 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7271 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7274 if (player->es_player_push_mode)
7277 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7279 /* return if set_state has failed */
7280 if (ret != MM_ERROR_NONE) {
7281 LOGE("failed to set state.\n");
7287 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7288 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7289 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7290 LOGW("failed to rewind\n");
7291 ret = MM_ERROR_PLAYER_SEEK;
7296 player->sent_bos = FALSE;
7298 if (player->es_player_push_mode) //for cloudgame
7301 /* wait for seek to complete */
7302 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7303 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7304 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7306 LOGE("fail to stop player.\n");
7307 ret = MM_ERROR_PLAYER_INTERNAL;
7308 __mmplayer_dump_pipeline_state(player);
7311 /* generate dot file if enabled */
7312 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7319 int __gst_pause(mm_player_t* player, gboolean async)
7321 int ret = MM_ERROR_NONE;
7325 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7326 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7328 LOGD("current state before doing transition");
7329 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7330 MMPLAYER_PRINT_STATE(player);
7332 /* set pipeline status to PAUSED */
7333 ret = __mmplayer_gst_set_state(player,
7334 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7336 if (FALSE == async) {
7337 if (ret != MM_ERROR_NONE) {
7338 GstMessage *msg = NULL;
7339 GTimer *timer = NULL;
7340 gdouble MAX_TIMEOUT_SEC = 3;
7342 LOGE("failed to set state to PAUSED");
7344 if (player->msg_posted) {
7345 LOGE("error msg is already posted.");
7349 timer = g_timer_new();
7350 g_timer_start(timer);
7352 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7355 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7357 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7358 GError *error = NULL;
7360 /* parse error code */
7361 gst_message_parse_error(msg, &error, NULL);
7363 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7364 /* Note : the streaming error from the streaming source is handled
7365 * using __mmplayer_handle_streaming_error.
7367 __mmplayer_handle_streaming_error(player, msg);
7370 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7372 if (error->domain == GST_STREAM_ERROR)
7373 ret = __gst_handle_stream_error(player, error, msg);
7374 else if (error->domain == GST_RESOURCE_ERROR)
7375 ret = __gst_handle_resource_error(player, error->code, NULL);
7376 else if (error->domain == GST_LIBRARY_ERROR)
7377 ret = __gst_handle_library_error(player, error->code);
7378 else if (error->domain == GST_CORE_ERROR)
7379 ret = __gst_handle_core_error(player, error->code);
7381 g_error_free(error);
7383 player->msg_posted = TRUE;
7385 gst_message_unref(msg);
7387 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7389 gst_object_unref(bus);
7390 g_timer_stop(timer);
7391 g_timer_destroy(timer);
7395 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7396 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7398 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7400 } else if (ret == MM_ERROR_NONE) {
7402 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7406 /* generate dot file before returning error */
7407 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7414 int __gst_resume(mm_player_t* player, gboolean async)
7416 int ret = MM_ERROR_NONE;
7421 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7422 MM_ERROR_PLAYER_NOT_INITIALIZED);
7424 LOGD("current state before doing transition");
7425 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7426 MMPLAYER_PRINT_STATE(player);
7428 /* generate dot file before returning error */
7429 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7432 LOGD("do async state transition to PLAYING.\n");
7434 /* set pipeline state to PLAYING */
7435 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7437 ret = __mmplayer_gst_set_state(player,
7438 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7439 if (ret != MM_ERROR_NONE) {
7440 LOGE("failed to set state to PLAYING\n");
7443 if (async == FALSE) {
7444 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7445 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7446 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7450 /* generate dot file before returning error */
7451 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7459 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7461 gint64 dur_nsec = 0;
7462 gint64 pos_nsec = 0;
7463 gboolean ret = TRUE;
7464 gboolean accurated = FALSE;
7465 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7468 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7469 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7471 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7472 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7475 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7476 /* check duration */
7477 /* NOTE : duration cannot be zero except live streaming.
7478 * Since some element could have some timing problemn with quering duration, try again.
7480 if (player->duration == 0) {
7481 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7482 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7483 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7484 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7485 player->pending_seek.is_pending = TRUE;
7486 player->pending_seek.format = format;
7487 player->pending_seek.pos = position;
7488 player->doing_seek = FALSE;
7489 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7490 return MM_ERROR_NONE;
7495 player->duration = dur_nsec;
7498 LOGD("playback rate: %f\n", player->playback_rate);
7500 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7502 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7504 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7508 case MM_PLAYER_POS_FORMAT_TIME:
7510 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7511 GstQuery *query = NULL;
7512 gboolean seekable = FALSE;
7514 /* check position is valid or not */
7515 if (position > player->duration)
7518 query = gst_query_new_seeking(GST_FORMAT_TIME);
7519 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7520 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7521 gst_query_unref(query);
7524 LOGW("non-seekable content");
7525 player->doing_seek = FALSE;
7526 return MM_ERROR_PLAYER_NO_OP;
7529 LOGW("failed to get seeking query");
7530 gst_query_unref(query); /* keep seeking operation */
7533 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7535 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7536 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7537 This causes problem is position calculation during normal pause resume scenarios also.
7538 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7539 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7540 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7541 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7542 LOGW("getting current position failed in seek\n");
7544 player->last_position = pos_nsec;
7545 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7548 if (player->doing_seek) {
7549 LOGD("not completed seek");
7550 return MM_ERROR_PLAYER_DOING_SEEK;
7554 if (!internal_called)
7555 player->doing_seek = TRUE;
7557 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7558 gint64 cur_time = 0;
7560 /* get current position */
7561 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7564 GstEvent *event = gst_event_new_seek(1.0,
7566 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7567 GST_SEEK_TYPE_SET, cur_time,
7568 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7570 __gst_send_event_to_sink(player, event);
7572 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7573 __gst_pause(player, FALSE);
7576 pos_nsec = position;
7578 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7579 that's why set position through property. */
7580 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7581 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7582 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7583 (!player->videodec_linked) && (!player->audiodec_linked)) {
7585 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7586 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7587 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7588 player->doing_seek = FALSE;
7589 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7591 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7592 GST_FORMAT_TIME, seek_flags,
7593 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7597 LOGE("failed to set position.");
7603 case MM_PLAYER_POS_FORMAT_PERCENT:
7605 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7607 if (player->doing_seek) {
7608 LOGD("not completed seek");
7609 return MM_ERROR_PLAYER_DOING_SEEK;
7612 if (!internal_called)
7613 player->doing_seek = TRUE;
7615 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7616 pos_nsec = (gint64)((position * player->duration) / 100);
7617 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7618 GST_FORMAT_TIME, seek_flags,
7619 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7621 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7631 /* NOTE : store last seeking point to overcome some bad operation
7632 * (returning zero when getting current position) of some elements
7634 player->last_position = pos_nsec;
7636 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7637 if (player->playback_rate > 1.0)
7638 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7641 return MM_ERROR_NONE;
7644 player->pending_seek.is_pending = TRUE;
7645 player->pending_seek.format = format;
7646 player->pending_seek.pos = position;
7648 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7649 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7650 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7651 player->pending_seek.pos);
7653 return MM_ERROR_NONE;
7656 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7657 return MM_ERROR_INVALID_ARGUMENT;
7660 player->doing_seek = FALSE;
7661 return MM_ERROR_PLAYER_SEEK;
7664 #define TRICKPLAY_OFFSET GST_MSECOND
7667 __gst_get_position(mm_player_t* player, int format, gint64* position)
7669 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7670 gint64 pos_nsec = 0;
7671 gboolean ret = TRUE;
7673 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7674 MM_ERROR_PLAYER_NOT_INITIALIZED);
7676 current_state = MMPLAYER_CURRENT_STATE(player);
7678 /* NOTE : query position except paused state to overcome some bad operation
7679 * please refer to below comments in details
7681 if (current_state != MM_PLAYER_STATE_PAUSED)
7682 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7684 /* NOTE : get last point to overcome some bad operation of some elements
7685 *(returning zero when getting current position in paused state
7686 * and when failed to get postion during seeking
7688 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7689 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7691 if (player->playback_rate < 0.0)
7692 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7694 pos_nsec = player->last_position;
7697 pos_nsec = player->last_position;
7699 player->last_position = pos_nsec;
7701 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7704 if (player->duration > 0 && pos_nsec > player->duration)
7705 pos_nsec = player->duration;
7707 player->last_position = pos_nsec;
7711 case MM_PLAYER_POS_FORMAT_TIME:
7712 *position = pos_nsec;
7715 case MM_PLAYER_POS_FORMAT_PERCENT:
7717 if (player->duration <= 0) {
7718 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7721 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7722 *position = (gint64)(pos_nsec * 100 / player->duration);
7727 return MM_ERROR_PLAYER_INTERNAL;
7730 return MM_ERROR_NONE;
7734 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7736 #define STREAMING_IS_FINISHED 0
7737 #define BUFFERING_MAX_PER 100
7738 #define DEFAULT_PER_VALUE -1
7739 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7741 MMPlayerGstElement *mainbin = NULL;
7742 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7743 gint64 buffered_total = 0;
7744 gint64 position = 0;
7745 gint buffered_sec = -1;
7746 GstBufferingMode mode = GST_BUFFERING_STREAM;
7747 gint64 content_size_time = player->duration;
7748 guint64 content_size_bytes = player->http_content_size;
7750 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7752 player->pipeline->mainbin,
7753 MM_ERROR_PLAYER_NOT_INITIALIZED);
7755 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7760 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7761 /* and rtsp is not ready yet. */
7762 LOGW("it's only used for http streaming case.\n");
7763 return MM_ERROR_PLAYER_NO_OP;
7766 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7767 LOGW("Time format is not supported yet.\n");
7768 return MM_ERROR_INVALID_ARGUMENT;
7771 if (content_size_time <= 0 || content_size_bytes <= 0) {
7772 LOGW("there is no content size.");
7773 return MM_ERROR_NONE;
7776 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7777 LOGW("fail to get current position.");
7778 return MM_ERROR_NONE;
7781 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7782 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7784 mainbin = player->pipeline->mainbin;
7785 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7787 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7788 GstQuery *query = NULL;
7789 gint byte_in_rate = 0, byte_out_rate = 0;
7790 gint64 estimated_total = 0;
7792 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7793 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7794 LOGW("fail to get buffering query from queue2");
7796 gst_query_unref(query);
7797 return MM_ERROR_NONE;
7800 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7801 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7803 if (mode == GST_BUFFERING_STREAM) {
7804 /* using only queue in case of push mode(ts / mp3) */
7805 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7806 GST_FORMAT_BYTES, &buffered_total)) {
7807 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7808 stop_per = 100 * buffered_total / content_size_bytes;
7811 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7813 guint num_of_ranges = 0;
7814 gint64 start_byte = 0, stop_byte = 0;
7816 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7817 if (estimated_total != STREAMING_IS_FINISHED) {
7818 /* buffered size info from queue2 */
7819 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7820 for (idx = 0; idx < num_of_ranges; idx++) {
7821 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7822 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7824 buffered_total += (stop_byte - start_byte);
7827 stop_per = BUFFERING_MAX_PER;
7829 gst_query_unref(query);
7832 if (stop_per == DEFAULT_PER_VALUE) {
7833 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7835 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7837 /* buffered size info from multiqueue */
7838 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7839 guint curr_size_bytes = 0;
7840 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7841 "curr-size-bytes", &curr_size_bytes, NULL);
7842 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7843 buffered_total += curr_size_bytes;
7846 if (avg_byterate > 0)
7847 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7848 else if (player->total_maximum_bitrate > 0)
7849 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7850 else if (player->total_bitrate > 0)
7851 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7853 if (buffered_sec >= 0)
7854 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7858 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7859 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7861 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7862 buffered_total, buffered_sec, *start_pos, *stop_pos);
7864 return MM_ERROR_NONE;
7868 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7873 LOGW("set_message_callback is called with invalid player handle\n");
7874 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7877 player->msg_cb = callback;
7878 player->msg_cb_param = user_param;
7880 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7884 return MM_ERROR_NONE;
7887 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7889 int ret = MM_ERROR_PLAYER_INVALID_URI;
7894 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7895 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7896 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7898 memset(data, 0, sizeof(MMPlayerParseProfile));
7900 if ((path = strstr(uri, "es_buff://"))) {
7902 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7903 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7904 ret = MM_ERROR_NONE;
7906 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7908 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7909 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7910 ret = MM_ERROR_NONE;
7912 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7915 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7916 tmp = g_ascii_strdown(uri, strlen(uri));
7918 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7919 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7921 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7923 ret = MM_ERROR_NONE;
7926 } else if ((path = strstr(uri, "rtspu://"))) {
7928 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7929 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7930 ret = MM_ERROR_NONE;
7932 } else if ((path = strstr(uri, "rtspr://"))) {
7933 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7934 char *separater = strstr(path, "*");
7938 char *urgent = separater + strlen("*");
7940 if ((urgent_len = strlen(urgent))) {
7941 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7942 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7943 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7944 ret = MM_ERROR_NONE;
7947 } else if ((path = strstr(uri, "mms://"))) {
7949 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7950 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7951 ret = MM_ERROR_NONE;
7953 } else if ((path = strstr(uri, "mem://"))) {
7956 char *buffer = NULL;
7957 char *seperator = strchr(path, ',');
7958 char ext[100] = {0,}, size[100] = {0,};
7961 if ((buffer = strstr(path, "ext="))) {
7962 buffer += strlen("ext=");
7964 if (strlen(buffer)) {
7965 strncpy(ext, buffer, 99);
7967 if ((seperator = strchr(ext, ','))
7968 || (seperator = strchr(ext, ' '))
7969 || (seperator = strchr(ext, '\0'))) {
7970 seperator[0] = '\0';
7975 if ((buffer = strstr(path, "size="))) {
7976 buffer += strlen("size=");
7978 if (strlen(buffer) > 0) {
7979 strncpy(size, buffer, 99);
7981 if ((seperator = strchr(size, ','))
7982 || (seperator = strchr(size, ' '))
7983 || (seperator = strchr(size, '\0'))) {
7984 seperator[0] = '\0';
7987 mem_size = atoi(size);
7992 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7993 if (mem_size && param) {
7994 if (data->input_mem.buf)
7995 free(data->input_mem.buf);
7996 data->input_mem.buf = malloc(mem_size);
7998 if (data->input_mem.buf) {
7999 memcpy(data->input_mem.buf, param, mem_size);
8000 data->input_mem.len = mem_size;
8001 ret = MM_ERROR_NONE;
8003 LOGE("failed to alloc mem %d", mem_size);
8004 ret = MM_ERROR_PLAYER_INTERNAL;
8007 data->input_mem.offset = 0;
8008 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8012 gchar *location = NULL;
8015 if ((path = strstr(uri, "file://"))) {
8017 location = g_filename_from_uri(uri, NULL, &err);
8019 if (!location || (err != NULL)) {
8020 LOGE("Invalid URI '%s' for filesrc: %s", path,
8021 (err != NULL) ? err->message : "unknown error");
8023 if (err) g_error_free(err);
8024 if (location) g_free(location);
8026 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8030 LOGD("path from uri: %s", location);
8033 path = (location != NULL) ? (location) : ((char*)uri);
8034 int file_stat = MM_ERROR_NONE;
8036 file_stat = util_exist_file_path(path);
8038 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8039 if (file_stat == MM_ERROR_NONE) {
8040 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8042 if (util_is_sdp_file(path)) {
8043 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8044 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8046 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8048 ret = MM_ERROR_NONE;
8049 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8050 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8052 LOGE("invalid uri, could not play..\n");
8053 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8056 if (location) g_free(location);
8060 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8061 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8062 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8063 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8065 /* dump parse result */
8066 SECURE_LOGW("incomming uri : %s\n", uri);
8067 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8068 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8076 __mmplayer_can_do_interrupt(mm_player_t *player)
8078 if (!player || !player->pipeline || !player->attrs) {
8079 LOGW("not initialized");
8083 if (player->set_mode.pcm_extraction) {
8084 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8088 /* check if seeking */
8089 if (player->doing_seek) {
8090 MMMessageParamType msg_param;
8091 memset(&msg_param, 0, sizeof(MMMessageParamType));
8092 msg_param.code = MM_ERROR_PLAYER_SEEK;
8093 player->doing_seek = FALSE;
8094 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8098 /* check other thread */
8099 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8100 LOGW("locked already, cmd state : %d", player->cmd);
8102 /* check application command */
8103 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8104 LOGW("playing.. should wait cmd lock then, will be interrupted");
8106 /* lock will be released at mrp_resource_release_cb() */
8107 MMPLAYER_CMD_LOCK(player);
8110 LOGW("nothing to do");
8113 LOGW("can interrupt immediately");
8117 FAILED: /* with CMD UNLOCKED */
8120 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8125 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8128 mm_player_t *player = NULL;
8132 if (user_data == NULL) {
8133 LOGE("- user_data is null\n");
8136 player = (mm_player_t *)user_data;
8138 /* do something to release resource here.
8139 * player stop and interrupt forwarding */
8140 if (!__mmplayer_can_do_interrupt(player)) {
8141 LOGW("no need to interrupt, so leave");
8143 MMMessageParamType msg = {0, };
8146 player->interrupted_by_resource = TRUE;
8148 /* get last play position */
8149 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8150 LOGW("failed to get play position.");
8152 msg.union_type = MM_MSG_UNION_TIME;
8153 msg.time.elapsed = pos;
8154 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8156 LOGD("video resource conflict so, resource will be freed by unrealizing");
8157 if (_mmplayer_unrealize((MMHandleType)player))
8158 LOGW("failed to unrealize");
8160 /* lock is called in __mmplayer_can_do_interrupt() */
8161 MMPLAYER_CMD_UNLOCK(player);
8164 if (res == player->video_overlay_resource)
8165 player->video_overlay_resource = FALSE;
8167 player->video_decoder_resource = FALSE;
8175 _mmplayer_create_player(MMHandleType handle)
8177 int ret = MM_ERROR_PLAYER_INTERNAL;
8178 bool enabled = false;
8180 mm_player_t* player = MM_PLAYER_CAST(handle);
8184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8186 /* initialize player state */
8187 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8188 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8189 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8190 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8192 /* check current state */
8193 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8195 /* construct attributes */
8196 player->attrs = _mmplayer_construct_attribute(handle);
8198 if (!player->attrs) {
8199 LOGE("Failed to construct attributes\n");
8203 /* initialize gstreamer with configured parameter */
8204 if (!__mmplayer_init_gstreamer(player)) {
8205 LOGE("Initializing gstreamer failed\n");
8206 _mmplayer_deconstruct_attribute(handle);
8210 /* create lock. note that g_tread_init() has already called in gst_init() */
8211 g_mutex_init(&player->fsink_lock);
8213 /* create update tag lock */
8214 g_mutex_init(&player->update_tag_lock);
8216 /* create next play mutex */
8217 g_mutex_init(&player->next_play_thread_mutex);
8219 /* create next play cond */
8220 g_cond_init(&player->next_play_thread_cond);
8222 /* create next play thread */
8223 player->next_play_thread =
8224 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8225 if (!player->next_play_thread) {
8226 LOGE("failed to create next play thread");
8227 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8228 g_mutex_clear(&player->next_play_thread_mutex);
8229 g_cond_clear(&player->next_play_thread_cond);
8233 player->bus_msg_q = g_queue_new();
8234 if (!player->bus_msg_q) {
8235 LOGE("failed to create queue for bus_msg");
8236 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8240 ret = _mmplayer_initialize_video_capture(player);
8241 if (ret != MM_ERROR_NONE) {
8242 LOGE("failed to initialize video capture\n");
8246 /* initialize resource manager */
8247 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8248 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8249 &player->resource_manager)) {
8250 LOGE("failed to initialize resource manager\n");
8254 if (MMPLAYER_IS_HTTP_PD(player)) {
8255 player->pd_downloader = NULL;
8256 player->pd_file_save_path = NULL;
8259 /* create video bo lock and cond */
8260 g_mutex_init(&player->video_bo_mutex);
8261 g_cond_init(&player->video_bo_cond);
8263 /* create media stream callback mutex */
8264 g_mutex_init(&player->media_stream_cb_lock);
8266 /* create subtitle info lock and cond */
8267 g_mutex_init(&player->subtitle_info_mutex);
8268 g_cond_init(&player->subtitle_info_cond);
8270 player->streaming_type = STREAMING_SERVICE_NONE;
8272 /* give default value of audio effect setting */
8273 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8274 player->sound.rg_enable = false;
8275 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8277 player->play_subtitle = FALSE;
8278 player->use_deinterleave = FALSE;
8279 player->max_audio_channels = 0;
8280 player->video_share_api_delta = 0;
8281 player->video_share_clock_delta = 0;
8282 player->has_closed_caption = FALSE;
8283 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8284 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8285 player->pending_resume = FALSE;
8286 if (player->ini.dump_element_keyword[0][0] == '\0')
8287 player->ini.set_dump_element_flag = FALSE;
8289 player->ini.set_dump_element_flag = TRUE;
8291 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8292 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8293 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8295 /* Set video360 settings to their defaults for just-created player.
8298 player->is_360_feature_enabled = FALSE;
8299 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8300 LOGI("spherical feature info: %d", enabled);
8302 player->is_360_feature_enabled = TRUE;
8304 LOGE("failed to get spherical feature info");
8307 player->is_content_spherical = FALSE;
8308 player->is_video360_enabled = TRUE;
8309 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8310 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8311 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8312 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8313 player->video360_zoom = 1.0f;
8314 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8315 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8317 /* set player state to null */
8318 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8319 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8321 return MM_ERROR_NONE;
8325 g_mutex_clear(&player->fsink_lock);
8327 /* free update tag lock */
8328 g_mutex_clear(&player->update_tag_lock);
8330 g_queue_free(player->bus_msg_q);
8332 /* free next play thread */
8333 if (player->next_play_thread) {
8334 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8335 player->next_play_thread_exit = TRUE;
8336 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8337 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8339 g_thread_join(player->next_play_thread);
8340 player->next_play_thread = NULL;
8342 g_mutex_clear(&player->next_play_thread_mutex);
8343 g_cond_clear(&player->next_play_thread_cond);
8346 /* release attributes */
8347 _mmplayer_deconstruct_attribute(handle);
8355 __mmplayer_init_gstreamer(mm_player_t* player)
8357 static gboolean initialized = FALSE;
8358 static const int max_argc = 50;
8360 gchar** argv = NULL;
8361 gchar** argv2 = NULL;
8367 LOGD("gstreamer already initialized.\n");
8372 argc = malloc(sizeof(int));
8373 argv = malloc(sizeof(gchar*) * max_argc);
8374 argv2 = malloc(sizeof(gchar*) * max_argc);
8376 if (!argc || !argv || !argv2)
8379 memset(argv, 0, sizeof(gchar*) * max_argc);
8380 memset(argv2, 0, sizeof(gchar*) * max_argc);
8384 argv[0] = g_strdup("mmplayer");
8387 for (i = 0; i < 5; i++) {
8388 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8389 if (strlen(player->ini.gst_param[i]) > 0) {
8390 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8395 /* we would not do fork for scanning plugins */
8396 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8399 /* check disable registry scan */
8400 if (player->ini.skip_rescan) {
8401 argv[*argc] = g_strdup("--gst-disable-registry-update");
8405 /* check disable segtrap */
8406 if (player->ini.disable_segtrap) {
8407 argv[*argc] = g_strdup("--gst-disable-segtrap");
8411 LOGD("initializing gstreamer with following parameter\n");
8412 LOGD("argc : %d\n", *argc);
8415 for (i = 0; i < arg_count; i++) {
8417 LOGD("argv[%d] : %s\n", i, argv2[i]);
8420 /* initializing gstreamer */
8421 if (!gst_init_check(argc, &argv, &err)) {
8422 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8429 for (i = 0; i < arg_count; i++) {
8430 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8431 MMPLAYER_FREEIF(argv2[i]);
8434 MMPLAYER_FREEIF(argv);
8435 MMPLAYER_FREEIF(argv2);
8436 MMPLAYER_FREEIF(argc);
8446 for (i = 0; i < arg_count; i++) {
8447 LOGD("free[%d] : %s\n", i, argv2[i]);
8448 MMPLAYER_FREEIF(argv2[i]);
8451 MMPLAYER_FREEIF(argv);
8452 MMPLAYER_FREEIF(argv2);
8453 MMPLAYER_FREEIF(argc);
8459 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8461 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8463 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8464 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8465 MMPLAYER_FREEIF(player->pd_file_save_path);
8468 return MM_ERROR_NONE;
8472 __mmplayer_check_async_state_transition(mm_player_t* player)
8474 GstState element_state = GST_STATE_VOID_PENDING;
8475 GstState element_pending_state = GST_STATE_VOID_PENDING;
8476 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8477 GstElement * element = NULL;
8478 gboolean async = FALSE;
8480 /* check player handle */
8481 MMPLAYER_RETURN_IF_FAIL(player &&
8483 player->pipeline->mainbin &&
8484 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8487 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8489 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8490 LOGD("don't need to check the pipeline state");
8494 MMPLAYER_PRINT_STATE(player);
8496 /* wait for state transition */
8497 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8498 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8500 if (ret == GST_STATE_CHANGE_FAILURE) {
8501 LOGE(" [%s] state : %s pending : %s \n",
8502 GST_ELEMENT_NAME(element),
8503 gst_element_state_get_name(element_state),
8504 gst_element_state_get_name(element_pending_state));
8506 /* dump state of all element */
8507 __mmplayer_dump_pipeline_state(player);
8512 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8517 _mmplayer_destroy(MMHandleType handle)
8519 mm_player_t* player = MM_PLAYER_CAST(handle);
8523 /* check player handle */
8524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526 /* destroy can called at anytime */
8527 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8529 /* check async state transition */
8530 __mmplayer_check_async_state_transition(player);
8532 __mmplayer_destroy_streaming_ext(player);
8534 /* release next play thread */
8535 if (player->next_play_thread) {
8536 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8537 player->next_play_thread_exit = TRUE;
8538 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8539 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8541 LOGD("waitting for next play thread exit\n");
8542 g_thread_join(player->next_play_thread);
8543 g_mutex_clear(&player->next_play_thread_mutex);
8544 g_cond_clear(&player->next_play_thread_cond);
8545 LOGD("next play thread released\n");
8548 _mmplayer_release_video_capture(player);
8550 /* de-initialize resource manager */
8551 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8552 player->resource_manager))
8553 LOGE("failed to deinitialize resource manager\n");
8555 /* release pipeline */
8556 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8557 LOGE("failed to destory pipeline\n");
8558 return MM_ERROR_PLAYER_INTERNAL;
8561 g_queue_free(player->bus_msg_q);
8563 /* release subtitle info lock and cond */
8564 g_mutex_clear(&player->subtitle_info_mutex);
8565 g_cond_clear(&player->subtitle_info_cond);
8567 __mmplayer_release_dump_list(player->dump_list);
8569 /* release miscellaneous information */
8570 __mmplayer_release_misc(player);
8572 /* release miscellaneous information.
8573 these info needs to be released after pipeline is destroyed. */
8574 __mmplayer_release_misc_post(player);
8576 /* release attributes */
8577 _mmplayer_deconstruct_attribute(handle);
8580 g_mutex_clear(&player->fsink_lock);
8583 g_mutex_clear(&player->update_tag_lock);
8585 /* release video bo lock and cond */
8586 g_mutex_clear(&player->video_bo_mutex);
8587 g_cond_clear(&player->video_bo_cond);
8589 /* release media stream callback lock */
8590 g_mutex_clear(&player->media_stream_cb_lock);
8594 return MM_ERROR_NONE;
8598 __mmplayer_realize_streaming_ext(mm_player_t* player)
8600 int ret = MM_ERROR_NONE;
8603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8605 if (MMPLAYER_IS_HTTP_PD(player)) {
8606 gboolean bret = FALSE;
8608 player->pd_downloader = _mmplayer_create_pd_downloader();
8609 if (!player->pd_downloader) {
8610 LOGE("Unable to create PD Downloader...");
8611 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8614 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8616 if (FALSE == bret) {
8617 LOGE("Unable to create PD Downloader...");
8618 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8627 _mmplayer_realize(MMHandleType hplayer)
8629 mm_player_t* player = (mm_player_t*)hplayer;
8632 MMHandleType attrs = 0;
8633 int ret = MM_ERROR_NONE;
8637 /* check player handle */
8638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8640 /* check current state */
8641 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8643 attrs = MMPLAYER_GET_ATTRS(player);
8645 LOGE("fail to get attributes.\n");
8646 return MM_ERROR_PLAYER_INTERNAL;
8648 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8649 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8651 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8652 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8654 if (ret != MM_ERROR_NONE) {
8655 LOGE("failed to parse profile\n");
8660 if (uri && (strstr(uri, "es_buff://"))) {
8661 if (strstr(uri, "es_buff://push_mode"))
8662 player->es_player_push_mode = TRUE;
8664 player->es_player_push_mode = FALSE;
8667 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8668 LOGW("mms protocol is not supported format.\n");
8669 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8672 if (MMPLAYER_IS_STREAMING(player))
8673 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8675 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8677 player->smooth_streaming = FALSE;
8678 player->videodec_linked = 0;
8679 player->videosink_linked = 0;
8680 player->audiodec_linked = 0;
8681 player->audiosink_linked = 0;
8682 player->textsink_linked = 0;
8683 player->is_external_subtitle_present = FALSE;
8684 player->is_external_subtitle_added_now = FALSE;
8685 /* set the subtitle ON default */
8686 player->is_subtitle_off = FALSE;
8688 /* realize pipeline */
8689 ret = __gst_realize(player);
8690 if (ret != MM_ERROR_NONE)
8691 LOGE("fail to realize the player.\n");
8693 ret = __mmplayer_realize_streaming_ext(player);
8695 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8703 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8706 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8708 /* destroy can called at anytime */
8709 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8710 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8713 return MM_ERROR_NONE;
8717 _mmplayer_unrealize(MMHandleType hplayer)
8719 mm_player_t* player = (mm_player_t*)hplayer;
8720 int ret = MM_ERROR_NONE;
8724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8726 MMPLAYER_CMD_UNLOCK(player);
8727 /* destroy the gst bus msg thread which is created during realize.
8728 this funct have to be called before getting cmd lock. */
8729 _mmplayer_bus_msg_thread_destroy(player);
8730 MMPLAYER_CMD_LOCK(player);
8732 /* check current state */
8733 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8735 /* check async state transition */
8736 __mmplayer_check_async_state_transition(player);
8738 __mmplayer_unrealize_streaming_ext(player);
8740 /* unrealize pipeline */
8741 ret = __gst_unrealize(player);
8743 /* set asm stop if success */
8744 if (MM_ERROR_NONE == ret) {
8745 if (!player->interrupted_by_resource) {
8746 if (player->video_decoder_resource != NULL) {
8747 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8748 player->video_decoder_resource);
8749 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8750 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8752 player->video_decoder_resource = NULL;
8755 if (player->video_overlay_resource != NULL) {
8756 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8757 player->video_overlay_resource);
8758 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8759 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8761 player->video_overlay_resource = NULL;
8764 ret = mm_resource_manager_commit(player->resource_manager);
8765 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8766 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8769 LOGE("failed and don't change asm state to stop");
8777 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8779 mm_player_t* player = (mm_player_t*)hplayer;
8781 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8783 return __gst_set_message_callback(player, callback, user_param);
8787 _mmplayer_get_state(MMHandleType hplayer, int* state)
8789 mm_player_t *player = (mm_player_t*)hplayer;
8791 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8793 *state = MMPLAYER_CURRENT_STATE(player);
8795 return MM_ERROR_NONE;
8800 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8802 mm_player_t* player = (mm_player_t*) hplayer;
8803 GstElement* vol_element = NULL;
8808 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8810 LOGD("volume [L]=%f:[R]=%f\n",
8811 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8813 /* invalid factor range or not */
8814 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8815 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8816 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8817 return MM_ERROR_INVALID_ARGUMENT;
8821 /* not support to set other value into each channel */
8822 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8823 return MM_ERROR_INVALID_ARGUMENT;
8825 /* Save volume to handle. Currently the first array element will be saved. */
8826 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8828 /* check pipeline handle */
8829 if (!player->pipeline || !player->pipeline->audiobin) {
8830 LOGD("audiobin is not created yet\n");
8831 LOGD("but, current stored volume will be set when it's created.\n");
8833 /* NOTE : stored volume will be used in create_audiobin
8834 * returning MM_ERROR_NONE here makes application to able to
8835 * set volume at anytime.
8837 return MM_ERROR_NONE;
8840 /* setting volume to volume element */
8841 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8844 LOGD("volume is set [%f]\n", player->sound.volume);
8845 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8850 return MM_ERROR_NONE;
8855 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8857 mm_player_t* player = (mm_player_t*) hplayer;
8862 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8863 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8865 /* returning stored volume */
8866 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8867 volume->level[i] = player->sound.volume;
8871 return MM_ERROR_NONE;
8875 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8877 mm_player_t* player = (mm_player_t*) hplayer;
8878 GstElement* vol_element = NULL;
8882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8884 /* mute value shoud 0 or 1 */
8885 if (mute != 0 && mute != 1) {
8886 LOGE("bad mute value\n");
8888 /* FIXIT : definitly, we need _BAD_PARAM error code */
8889 return MM_ERROR_INVALID_ARGUMENT;
8892 player->sound.mute = mute;
8894 /* just hold mute value if pipeline is not ready */
8895 if (!player->pipeline || !player->pipeline->audiobin) {
8896 LOGD("pipeline is not ready. holding mute value\n");
8897 return MM_ERROR_NONE;
8900 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8902 /* NOTE : volume will only created when the bt is enabled */
8904 LOGD("mute : %d\n", mute);
8905 g_object_set(vol_element, "mute", mute, NULL);
8907 LOGD("volume elemnet is not created. using volume in audiosink\n");
8911 return MM_ERROR_NONE;
8915 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8917 mm_player_t* player = (mm_player_t*) hplayer;
8921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8922 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8924 /* just hold mute value if pipeline is not ready */
8925 if (!player->pipeline || !player->pipeline->audiobin) {
8926 LOGD("pipeline is not ready. returning stored value\n");
8927 *pmute = player->sound.mute;
8928 return MM_ERROR_NONE;
8931 *pmute = player->sound.mute;
8935 return MM_ERROR_NONE;
8939 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8941 mm_player_t* player = (mm_player_t*) hplayer;
8945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8947 player->video_stream_changed_cb = callback;
8948 player->video_stream_changed_cb_user_param = user_param;
8949 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8953 return MM_ERROR_NONE;
8957 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8959 mm_player_t* player = (mm_player_t*) hplayer;
8963 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8965 player->audio_stream_changed_cb = callback;
8966 player->audio_stream_changed_cb_user_param = user_param;
8967 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8971 return MM_ERROR_NONE;
8975 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8977 mm_player_t* player = (mm_player_t*) hplayer;
8981 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8983 player->audio_stream_render_cb_ex = callback;
8984 player->audio_stream_cb_user_param = user_param;
8985 player->audio_stream_sink_sync = sync;
8986 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);
8990 return MM_ERROR_NONE;
8994 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8996 mm_player_t* player = (mm_player_t*) hplayer;
9000 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9002 if (callback && !player->bufmgr)
9003 player->bufmgr = tbm_bufmgr_init(-1);
9005 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9006 player->video_stream_cb = callback;
9007 player->video_stream_cb_user_param = user_param;
9009 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9013 return MM_ERROR_NONE;
9017 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9019 mm_player_t* player = (mm_player_t*) hplayer;
9023 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9025 player->audio_stream_cb = callback;
9026 player->audio_stream_cb_user_param = user_param;
9027 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9031 return MM_ERROR_NONE;
9035 __mmplayer_start_streaming_ext(mm_player_t *player)
9037 gint ret = MM_ERROR_NONE;
9040 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9042 if (MMPLAYER_IS_HTTP_PD(player)) {
9043 if (!player->pd_downloader) {
9044 ret = __mmplayer_realize_streaming_ext(player);
9046 if (ret != MM_ERROR_NONE) {
9047 LOGE("failed to realize streaming ext\n");
9052 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9053 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9055 LOGE("ERROR while starting PD...\n");
9056 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9058 ret = MM_ERROR_NONE;
9067 _mmplayer_start(MMHandleType hplayer)
9069 mm_player_t* player = (mm_player_t*) hplayer;
9070 gint ret = MM_ERROR_NONE;
9074 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9076 /* check current state */
9077 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9079 /* NOTE : we should check and create pipeline again if not created as we destroy
9080 * whole pipeline when stopping in streamming playback
9082 if (!player->pipeline) {
9083 ret = __gst_realize(player);
9084 if (MM_ERROR_NONE != ret) {
9085 LOGE("failed to realize before starting. only in streamming\n");
9091 ret = __mmplayer_start_streaming_ext(player);
9092 if (ret != MM_ERROR_NONE) {
9093 LOGE("failed to start streaming ext 0x%X", ret);
9097 /* start pipeline */
9098 ret = __gst_start(player);
9099 if (ret != MM_ERROR_NONE)
9100 LOGE("failed to start player.\n");
9107 /* NOTE: post "not supported codec message" to application
9108 * when one codec is not found during AUTOPLUGGING in MSL.
9109 * So, it's separated with error of __mmplayer_gst_callback().
9110 * And, if any codec is not found, don't send message here.
9111 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9114 __mmplayer_handle_missed_plugin(mm_player_t* player)
9116 MMMessageParamType msg_param;
9117 memset(&msg_param, 0, sizeof(MMMessageParamType));
9118 gboolean post_msg_direct = FALSE;
9122 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9124 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9125 player->not_supported_codec, player->can_support_codec);
9127 if (player->not_found_demuxer) {
9128 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9129 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9131 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9132 MMPLAYER_FREEIF(msg_param.data);
9134 return MM_ERROR_NONE;
9137 if (player->not_supported_codec) {
9138 if (player->can_support_codec) {
9139 // There is one codec to play
9140 post_msg_direct = TRUE;
9142 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9143 post_msg_direct = TRUE;
9146 if (post_msg_direct) {
9147 MMMessageParamType msg_param;
9148 memset(&msg_param, 0, sizeof(MMMessageParamType));
9150 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9151 LOGW("not found AUDIO codec, posting error code to application.\n");
9153 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9154 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9155 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9156 LOGW("not found VIDEO codec, posting error code to application.\n");
9158 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9159 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9162 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9164 MMPLAYER_FREEIF(msg_param.data);
9166 return MM_ERROR_NONE;
9168 // no any supported codec case
9169 LOGW("not found any codec, posting error code to application.\n");
9171 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9172 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9173 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9175 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9176 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9179 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9181 MMPLAYER_FREEIF(msg_param.data);
9187 return MM_ERROR_NONE;
9190 static void __mmplayer_check_pipeline(mm_player_t* player)
9192 GstState element_state = GST_STATE_VOID_PENDING;
9193 GstState element_pending_state = GST_STATE_VOID_PENDING;
9195 int ret = MM_ERROR_NONE;
9197 if (player->gapless.reconfigure) {
9198 LOGW("pipeline is under construction.\n");
9200 MMPLAYER_PLAYBACK_LOCK(player);
9201 MMPLAYER_PLAYBACK_UNLOCK(player);
9203 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9205 /* wait for state transition */
9206 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9208 if (ret == GST_STATE_CHANGE_FAILURE)
9209 LOGE("failed to change pipeline state within %d sec\n", timeout);
9213 /* NOTE : it should be able to call 'stop' anytime*/
9215 _mmplayer_stop(MMHandleType hplayer)
9217 mm_player_t* player = (mm_player_t*)hplayer;
9218 int ret = MM_ERROR_NONE;
9222 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9224 /* check current state */
9225 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9227 /* check pipline building state */
9228 __mmplayer_check_pipeline(player);
9229 __mmplayer_reset_gapless_state(player);
9231 /* NOTE : application should not wait for EOS after calling STOP */
9232 __mmplayer_cancel_eos_timer(player);
9234 __mmplayer_unrealize_streaming_ext(player);
9237 player->doing_seek = FALSE;
9240 ret = __gst_stop(player);
9242 if (ret != MM_ERROR_NONE)
9243 LOGE("failed to stop player.\n");
9251 _mmplayer_pause(MMHandleType hplayer)
9253 mm_player_t* player = (mm_player_t*)hplayer;
9254 gint64 pos_nsec = 0;
9255 gboolean async = FALSE;
9256 gint ret = MM_ERROR_NONE;
9260 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9262 /* check current state */
9263 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9265 /* check pipline building state */
9266 __mmplayer_check_pipeline(player);
9268 switch (MMPLAYER_CURRENT_STATE(player)) {
9269 case MM_PLAYER_STATE_READY:
9271 /* check prepare async or not.
9272 * In the case of streaming playback, it's recommned to avoid blocking wait.
9274 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9275 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9277 /* Changing back sync of rtspsrc to async */
9278 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9279 LOGD("async prepare working mode for rtsp");
9285 case MM_PLAYER_STATE_PLAYING:
9287 /* NOTE : store current point to overcome some bad operation
9288 *(returning zero when getting current position in paused state) of some
9291 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9292 LOGW("getting current position failed in paused\n");
9294 player->last_position = pos_nsec;
9296 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9297 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9298 This causes problem is position calculation during normal pause resume scenarios also.
9299 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9300 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9301 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9302 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9308 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9309 LOGD("doing async pause in case of ms buff src");
9313 /* pause pipeline */
9314 ret = __gst_pause(player, async);
9316 if (ret != MM_ERROR_NONE)
9317 LOGE("failed to pause player. ret : 0x%x\n", ret);
9319 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9320 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9321 LOGE("failed to update display_rotation");
9330 _mmplayer_resume(MMHandleType hplayer)
9332 mm_player_t* player = (mm_player_t*)hplayer;
9333 int ret = MM_ERROR_NONE;
9334 gboolean async = FALSE;
9338 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9340 /* Changing back sync mode rtspsrc to async */
9341 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9342 LOGD("async resume for rtsp case");
9346 /* check current state */
9347 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9349 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
9350 LOGD("force resume even during buffering");
9351 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
9354 ret = __gst_resume(player, async);
9356 if (ret != MM_ERROR_NONE)
9357 LOGE("failed to resume player.\n");
9365 __mmplayer_set_pcm_extraction(mm_player_t* player)
9367 gint64 start_nsec = 0;
9368 gint64 end_nsec = 0;
9369 gint64 dur_nsec = 0;
9370 gint64 dur_msec = 0;
9371 int required_start = 0;
9372 int required_end = 0;
9377 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9379 mm_attrs_multiple_get(player->attrs,
9381 "pcm_extraction_start_msec", &required_start,
9382 "pcm_extraction_end_msec", &required_end,
9385 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9387 if (required_start == 0 && required_end == 0) {
9388 LOGD("extracting entire stream");
9389 return MM_ERROR_NONE;
9390 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9391 LOGD("invalid range for pcm extraction");
9392 return MM_ERROR_INVALID_ARGUMENT;
9396 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9398 LOGE("failed to get duration");
9399 return MM_ERROR_PLAYER_INTERNAL;
9401 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9403 if (dur_msec < required_end) {
9405 LOGD("invalid end pos for pcm extraction");
9406 return MM_ERROR_INVALID_ARGUMENT;
9409 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9410 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9412 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9415 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9416 GST_SEEK_TYPE_SET, start_nsec,
9417 GST_SEEK_TYPE_SET, end_nsec))) {
9418 LOGE("failed to seek for pcm extraction\n");
9420 return MM_ERROR_PLAYER_SEEK;
9423 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9427 return MM_ERROR_NONE;
9431 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9433 mm_player_t* player = (mm_player_t*)hplayer;
9434 gint64 pos_nsec = 0;
9435 int ret = MM_ERROR_NONE;
9437 signed long long start = 0, stop = 0;
9438 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9441 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9442 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9444 /* The sound of video is not supported under 0.0 and over 2.0. */
9445 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9446 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9449 _mmplayer_set_mute(hplayer, mute);
9451 if (player->playback_rate == rate)
9452 return MM_ERROR_NONE;
9454 /* If the position is reached at start potion during fast backward, EOS is posted.
9455 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9457 player->playback_rate = rate;
9459 current_state = MMPLAYER_CURRENT_STATE(player);
9461 if (current_state != MM_PLAYER_STATE_PAUSED)
9462 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9464 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9466 if ((current_state == MM_PLAYER_STATE_PAUSED)
9467 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9468 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9469 pos_nsec = player->last_position;
9474 stop = GST_CLOCK_TIME_NONE;
9476 start = GST_CLOCK_TIME_NONE;
9480 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9481 player->playback_rate,
9483 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9484 GST_SEEK_TYPE_SET, start,
9485 GST_SEEK_TYPE_SET, stop)) {
9486 LOGE("failed to set speed playback\n");
9487 return MM_ERROR_PLAYER_SEEK;
9490 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9494 return MM_ERROR_NONE;;
9498 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9500 mm_player_t* player = (mm_player_t*)hplayer;
9501 int ret = MM_ERROR_NONE;
9505 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9507 /* check pipline building state */
9508 __mmplayer_check_pipeline(player);
9510 ret = __gst_set_position(player, format, position, FALSE);
9518 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9520 mm_player_t* player = (mm_player_t*)hplayer;
9521 int ret = MM_ERROR_NONE;
9523 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9525 ret = __gst_get_position(player, format, position);
9531 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9533 mm_player_t* player = (mm_player_t*)hplayer;
9534 int ret = MM_ERROR_NONE;
9536 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9537 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9539 *duration = player->duration;
9544 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9546 mm_player_t* player = (mm_player_t*)hplayer;
9547 int ret = MM_ERROR_NONE;
9549 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9551 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9557 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9559 mm_player_t* player = (mm_player_t*)hplayer;
9560 int ret = MM_ERROR_NONE;
9564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9566 ret = __gst_adjust_subtitle_position(player, format, position);
9574 __mmplayer_is_midi_type(gchar* str_caps)
9576 if ((g_strrstr(str_caps, "audio/midi")) ||
9577 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9578 (g_strrstr(str_caps, "application/x-smaf")) ||
9579 (g_strrstr(str_caps, "audio/x-imelody")) ||
9580 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9581 (g_strrstr(str_caps, "audio/xmf")) ||
9582 (g_strrstr(str_caps, "audio/mxmf"))) {
9591 __mmplayer_is_only_mp3_type(gchar *str_caps)
9593 if (g_strrstr(str_caps, "application/x-id3") ||
9594 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9600 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9602 GstStructure* caps_structure = NULL;
9603 gint samplerate = 0;
9607 MMPLAYER_RETURN_IF_FAIL(player && caps);
9609 caps_structure = gst_caps_get_structure(caps, 0);
9611 /* set stream information */
9612 gst_structure_get_int(caps_structure, "rate", &samplerate);
9613 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9615 gst_structure_get_int(caps_structure, "channels", &channels);
9616 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9618 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9622 __mmplayer_update_content_type_info(mm_player_t* player)
9625 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9627 if (__mmplayer_is_midi_type(player->type)) {
9628 player->bypass_audio_effect = TRUE;
9629 } else if (g_strrstr(player->type, "application/x-hls")) {
9630 /* If it can't know exact type when it parses uri because of redirection case,
9631 * it will be fixed by typefinder or when doing autoplugging.
9633 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9634 if (player->streamer) {
9635 player->streamer->is_adaptive_streaming = TRUE;
9636 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9637 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9639 } else if (g_strrstr(player->type, "application/dash+xml")) {
9640 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9641 if (player->streamer) {
9642 player->streamer->is_adaptive_streaming = TRUE;
9643 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9647 LOGD("uri type : %d", player->profile.uri_type);
9652 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9653 GstCaps *caps, gpointer data)
9655 mm_player_t* player = (mm_player_t*)data;
9660 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9662 /* store type string */
9663 MMPLAYER_FREEIF(player->type);
9664 player->type = gst_caps_to_string(caps);
9666 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9667 player, player->type, probability, gst_caps_get_size(caps));
9670 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9671 (g_strrstr(player->type, "audio/x-raw-int"))) {
9672 LOGE("not support media format\n");
9674 if (player->msg_posted == FALSE) {
9675 MMMessageParamType msg_param;
9676 memset(&msg_param, 0, sizeof(MMMessageParamType));
9678 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9679 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9681 /* don't post more if one was sent already */
9682 player->msg_posted = TRUE;
9687 __mmplayer_update_content_type_info(player);
9689 pad = gst_element_get_static_pad(tf, "src");
9691 LOGE("fail to get typefind src pad.\n");
9695 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9696 gboolean async = FALSE;
9697 LOGE("failed to autoplug %s\n", player->type);
9699 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9701 if (async && player->msg_posted == FALSE)
9702 __mmplayer_handle_missed_plugin(player);
9708 gst_object_unref(GST_OBJECT(pad));
9716 __mmplayer_create_decodebin(mm_player_t* player)
9718 GstElement *decodebin = NULL;
9722 /* create decodebin */
9723 decodebin = gst_element_factory_make("decodebin", NULL);
9726 LOGE("fail to create decodebin\n");
9730 /* raw pad handling signal */
9731 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9732 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9734 /* no-more-pad pad handling signal */
9735 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9736 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9738 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9739 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9741 /* This signal is emitted when a pad for which there is no further possible
9742 decoding is added to the decodebin.*/
9743 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9744 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9746 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9747 before looking for any elements that can handle that stream.*/
9748 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9749 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9751 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9752 before looking for any elements that can handle that stream.*/
9753 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9754 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9756 /* This signal is emitted once decodebin has finished decoding all the data.*/
9757 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9758 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9760 /* This signal is emitted when a element is added to the bin.*/
9761 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9762 G_CALLBACK(__mmplayer_gst_element_added), player);
9769 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9771 MMPlayerGstElement* mainbin = NULL;
9772 GstElement* decodebin = NULL;
9773 GstElement* queue2 = NULL;
9774 GstPad* sinkpad = NULL;
9775 GstPad* qsrcpad = NULL;
9776 gint64 dur_bytes = 0L;
9778 guint max_buffer_size_bytes = 0;
9779 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9782 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9784 mainbin = player->pipeline->mainbin;
9786 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9787 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9788 LOGD("creating http streaming buffering queue(queue2)\n");
9790 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9791 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9793 queue2 = gst_element_factory_make("queue2", "queue2");
9795 LOGE("failed to create buffering queue element\n");
9799 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9800 LOGE("failed to add buffering queue\n");
9804 sinkpad = gst_element_get_static_pad(queue2, "sink");
9805 qsrcpad = gst_element_get_static_pad(queue2, "src");
9807 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9808 LOGE("failed to link buffering queue");
9812 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9813 LOGE("fail to get duration");
9815 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9817 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9819 if (dur_bytes > 0) {
9820 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9821 type = MUXED_BUFFER_TYPE_FILE;
9823 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9824 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9830 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
9831 * skip the pull mode(file or ring buffering) setting. */
9832 if (!g_strrstr(player->type, "video/mpegts")) {
9833 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9834 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9836 __mm_player_streaming_set_queue2(player->streamer,
9839 max_buffer_size_bytes,
9840 player->ini.http_buffering_time,
9841 1.0, /* no meaning */
9842 player->ini.http_buffering_limit, /* no meaning */
9844 player->http_file_buffering_path,
9845 (guint64)dur_bytes);
9848 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9849 LOGE("failed to sync queue2 state with parent\n");
9855 gst_object_unref(GST_OBJECT(sinkpad));
9857 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9858 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9862 /* create decodebin */
9863 decodebin = __mmplayer_create_decodebin(player);
9866 LOGE("can not create autoplug element\n");
9870 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9871 LOGE("failed to add decodebin\n");
9875 /* to force caps on the decodebin element and avoid reparsing stuff by
9876 * typefind. It also avoids a deadlock in the way typefind activates pads in
9877 * the state change */
9878 g_object_set(decodebin, "sink-caps", caps, NULL);
9880 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9882 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9883 LOGE("failed to link decodebin\n");
9887 gst_object_unref(GST_OBJECT(sinkpad));
9889 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9890 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9892 /* set decodebin property about buffer in streaming playback. *
9893 * in case of HLS/DASH, it does not need to have big buffer *
9894 * because it is kind of adaptive streaming. */
9895 if (!MMPLAYER_IS_HTTP_PD(player) &&
9896 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
9897 gdouble high_percent = 0.0;
9899 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9900 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
9902 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
9903 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
9905 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9906 "high-percent", (gint)high_percent,
9907 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
9908 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
9909 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
9910 "max-size-buffers", 0, NULL); // disable or automatic
9913 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9914 LOGE("failed to sync decodebin state with parent\n");
9925 gst_object_unref(GST_OBJECT(sinkpad));
9928 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9929 * You need to explicitly set elements to the NULL state before
9930 * dropping the final reference, to allow them to clean up.
9932 gst_element_set_state(queue2, GST_STATE_NULL);
9934 /* And, it still has a parent "player".
9935 * You need to let the parent manage the object instead of unreffing the object directly.
9937 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9938 gst_object_unref(queue2);
9943 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9944 * You need to explicitly set elements to the NULL state before
9945 * dropping the final reference, to allow them to clean up.
9947 gst_element_set_state(decodebin, GST_STATE_NULL);
9949 /* And, it still has a parent "player".
9950 * You need to let the parent manage the object instead of unreffing the object directly.
9953 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9954 gst_object_unref(decodebin);
9962 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9966 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9967 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9969 LOGD("class : %s, mime : %s \n", factory_class, mime);
9971 /* add missing plugin */
9972 /* NOTE : msl should check missing plugin for image mime type.
9973 * Some motion jpeg clips can have playable audio track.
9974 * So, msl have to play audio after displaying popup written video format not supported.
9976 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9977 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9978 LOGD("not found demuxer\n");
9979 player->not_found_demuxer = TRUE;
9980 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9986 if (!g_strrstr(factory_class, "Demuxer")) {
9987 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9988 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9989 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9991 /* check that clip have multi tracks or not */
9992 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9993 LOGD("video plugin is already linked\n");
9995 LOGW("add VIDEO to missing plugin\n");
9996 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9997 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9999 } else if (g_str_has_prefix(mime, "audio")) {
10000 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10001 LOGD("audio plugin is already linked\n");
10003 LOGW("add AUDIO to missing plugin\n");
10004 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10005 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10013 return MM_ERROR_NONE;
10018 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10020 mm_player_t* player = (mm_player_t*)data;
10024 MMPLAYER_RETURN_IF_FAIL(player);
10026 /* remove fakesink. */
10027 if (!__mmplayer_gst_remove_fakesink(player,
10028 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10029 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10030 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10031 * source element are not same. To overcome this situation, this function will called
10032 * several places and several times. Therefore, this is not an error case.
10037 LOGD("[handle: %p] pipeline has completely constructed", player);
10039 if ((player->ini.async_start) &&
10040 (player->msg_posted == FALSE) &&
10041 (player->cmd >= MMPLAYER_COMMAND_START))
10042 __mmplayer_handle_missed_plugin(player);
10044 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10048 __mmplayer_verify_next_play_path(mm_player_t *player)
10050 MMHandleType attrs = 0;
10051 MMPlayerParseProfile profile;
10052 gint uri_idx = 0, check_cnt = 0;
10054 gint mode = MM_PLAYER_PD_MODE_NONE;
10058 guint num_of_list = 0;
10059 static int profile_tv = -1;
10063 LOGD("checking for gapless play");
10065 if (player->pipeline->textbin) {
10066 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10070 attrs = MMPLAYER_GET_ATTRS(player);
10072 LOGE("fail to get attributes.\n");
10076 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10078 if (__builtin_expect(profile_tv == -1, 0)) {
10080 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10081 switch (*profileName) {
10091 /* gapless playback is not supported in case of video at TV profile. */
10092 if (profile_tv && video) {
10093 LOGW("not support video gapless playback");
10097 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10098 if (mode == TRUE) {
10104 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10105 LOGE("can not get play count\n");
10107 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10108 LOGE("can not get gapless mode\n");
10110 if (video && !gapless) {
10111 LOGW("not enabled video gapless playback");
10115 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10119 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10123 num_of_list = g_list_length(player->uri_info.uri_list);
10125 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10127 if (num_of_list == 0) {
10128 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10129 LOGE("can not get profile_uri\n");
10134 LOGE("uri list is empty.\n");
10138 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10139 LOGD("add original path : %s ", uri);
10145 uri_idx = player->uri_info.uri_idx;
10150 if (check_cnt > num_of_list) {
10151 LOGE("there is no valid uri.");
10155 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10157 if (uri_idx < num_of_list-1) {
10160 if ((count <= 1) && (count != -1)) {
10161 LOGD("no repeat.");
10163 } else if (count > 1) {
10164 /* decrease play count */
10165 /* we succeeded to rewind. update play count and then wait for next EOS */
10168 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10170 /* commit attribute */
10171 if (mmf_attrs_commit(attrs))
10172 LOGE("failed to commit attribute\n");
10175 /* count < 0 : repeat continually */
10179 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10180 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10183 LOGW("next uri does not exist\n");
10187 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10188 LOGE("failed to parse profile\n");
10192 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10193 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10194 LOGW("uri type is not supported(%d).", profile.uri_type);
10201 player->uri_info.uri_idx = uri_idx;
10202 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10204 if (mmf_attrs_commit(player->attrs)) {
10205 LOGE("failed to commit.\n");
10209 LOGD("next uri %s(%d)\n", uri, uri_idx);
10215 LOGE("unable to play next path. EOS will be posted soon.\n");
10220 __mmplayer_initialize_next_play(mm_player_t *player)
10226 player->smooth_streaming = FALSE;
10227 player->videodec_linked = 0;
10228 player->audiodec_linked = 0;
10229 player->videosink_linked = 0;
10230 player->audiosink_linked = 0;
10231 player->textsink_linked = 0;
10232 player->is_external_subtitle_present = FALSE;
10233 player->is_external_subtitle_added_now = FALSE;
10234 player->not_supported_codec = MISSING_PLUGIN_NONE;
10235 player->can_support_codec = FOUND_PLUGIN_NONE;
10236 player->pending_seek.is_pending = FALSE;
10237 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10238 player->pending_seek.pos = 0;
10239 player->msg_posted = FALSE;
10240 player->has_many_types = FALSE;
10241 player->no_more_pad = FALSE;
10242 player->not_found_demuxer = 0;
10243 player->doing_seek = FALSE;
10244 player->max_audio_channels = 0;
10245 player->is_subtitle_force_drop = FALSE;
10246 player->play_subtitle = FALSE;
10247 player->adjust_subtitle_pos = 0;
10249 player->total_bitrate = 0;
10250 player->total_maximum_bitrate = 0;
10252 _mmplayer_track_initialize(player);
10253 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10255 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10256 player->bitrate[i] = 0;
10257 player->maximum_bitrate[i] = 0;
10260 if (player->v_stream_caps) {
10261 gst_caps_unref(player->v_stream_caps);
10262 player->v_stream_caps = NULL;
10265 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10267 /* clean found parsers */
10268 if (player->parsers) {
10269 GList *parsers = player->parsers;
10270 for (; parsers; parsers = g_list_next(parsers)) {
10271 gchar *name = parsers->data;
10272 MMPLAYER_FREEIF(name);
10274 g_list_free(player->parsers);
10275 player->parsers = NULL;
10278 /* clean found audio decoders */
10279 if (player->audio_decoders) {
10280 GList *a_dec = player->audio_decoders;
10281 for (; a_dec; a_dec = g_list_next(a_dec)) {
10282 gchar *name = a_dec->data;
10283 MMPLAYER_FREEIF(name);
10285 g_list_free(player->audio_decoders);
10286 player->audio_decoders = NULL;
10293 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10295 MMPlayerGstElement *mainbin = NULL;
10296 MMMessageParamType msg_param = {0,};
10297 GstElement *element = NULL;
10298 MMHandleType attrs = 0;
10300 enum MainElementID elemId = MMPLAYER_M_NUM;
10304 if ((player == NULL) ||
10305 (player->pipeline == NULL) ||
10306 (player->pipeline->mainbin == NULL)) {
10307 LOGE("player is null.\n");
10311 mainbin = player->pipeline->mainbin;
10312 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10314 attrs = MMPLAYER_GET_ATTRS(player);
10316 LOGE("fail to get attributes.\n");
10320 /* Initialize Player values */
10321 __mmplayer_initialize_next_play(player);
10323 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10325 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10326 LOGE("failed to parse profile\n");
10327 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10331 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10332 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10333 LOGE("it's dash or hls. not support.");
10334 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10339 switch (player->profile.uri_type) {
10341 case MM_PLAYER_URI_TYPE_FILE:
10343 LOGD("using filesrc for 'file://' handler.\n");
10344 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10345 LOGE("failed to get storage info");
10349 element = gst_element_factory_make("filesrc", "source");
10352 LOGE("failed to create filesrc\n");
10356 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10359 case MM_PLAYER_URI_TYPE_URL_HTTP:
10361 gchar *user_agent, *cookies, **cookie_list;
10362 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10363 user_agent = cookies = NULL;
10364 cookie_list = NULL;
10366 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10368 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10371 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10373 /* get attribute */
10374 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10375 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10377 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10378 LOGD("get timeout from ini\n");
10379 http_timeout = player->ini.http_timeout;
10382 /* get attribute */
10383 SECURE_LOGD("location : %s\n", player->profile.uri);
10384 SECURE_LOGD("cookies : %s\n", cookies);
10385 SECURE_LOGD("user_agent : %s\n", user_agent);
10386 LOGD("timeout : %d\n", http_timeout);
10388 /* setting property to streaming source */
10389 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10390 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10391 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10393 /* parsing cookies */
10394 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10395 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10397 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10401 LOGE("not support uri type %d\n", player->profile.uri_type);
10406 LOGE("no source element was created.\n");
10410 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10411 LOGE("failed to add source element to pipeline\n");
10412 gst_object_unref(GST_OBJECT(element));
10417 /* take source element */
10418 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10419 mainbin[MMPLAYER_M_SRC].gst = element;
10423 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10424 if (player->streamer == NULL) {
10425 player->streamer = __mm_player_streaming_create();
10426 __mm_player_streaming_initialize(player->streamer);
10429 elemId = MMPLAYER_M_TYPEFIND;
10430 element = gst_element_factory_make("typefind", "typefinder");
10431 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10432 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10434 elemId = MMPLAYER_M_AUTOPLUG;
10435 element = __mmplayer_create_decodebin(player);
10438 /* check autoplug element is OK */
10440 LOGE("can not create element(%d)\n", elemId);
10444 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10445 LOGE("failed to add sinkbin to pipeline\n");
10446 gst_object_unref(GST_OBJECT(element));
10451 mainbin[elemId].id = elemId;
10452 mainbin[elemId].gst = element;
10454 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10455 LOGE("Failed to link src - autoplug(or typefind)\n");
10459 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10460 LOGE("Failed to change state of src element\n");
10464 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10465 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10466 LOGE("Failed to change state of decodebin\n");
10470 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10471 LOGE("Failed to change state of src element\n");
10476 player->gapless.stream_changed = TRUE;
10477 player->gapless.running = TRUE;
10483 MMPLAYER_PLAYBACK_UNLOCK(player);
10485 if (!player->msg_posted) {
10486 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10487 player->msg_posted = TRUE;
10494 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10496 mm_player_selector_t *selector = &player->selector[type];
10497 MMPlayerGstElement *sinkbin = NULL;
10498 enum MainElementID selectorId = MMPLAYER_M_NUM;
10499 enum MainElementID sinkId = MMPLAYER_M_NUM;
10500 GstPad *srcpad = NULL;
10501 GstPad *sinkpad = NULL;
10502 gboolean send_notice = FALSE;
10505 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10507 LOGD("type %d", type);
10510 case MM_PLAYER_TRACK_TYPE_AUDIO:
10511 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10512 sinkId = MMPLAYER_A_BIN;
10513 sinkbin = player->pipeline->audiobin;
10515 case MM_PLAYER_TRACK_TYPE_VIDEO:
10516 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10517 sinkId = MMPLAYER_V_BIN;
10518 sinkbin = player->pipeline->videobin;
10519 send_notice = TRUE;
10521 case MM_PLAYER_TRACK_TYPE_TEXT:
10522 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10523 sinkId = MMPLAYER_T_BIN;
10524 sinkbin = player->pipeline->textbin;
10527 LOGE("requested type is not supportable");
10532 if (player->pipeline->mainbin[selectorId].gst) {
10535 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10537 if (selector->event_probe_id != 0)
10538 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10539 selector->event_probe_id = 0;
10541 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10542 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10544 if (srcpad && sinkpad) {
10545 /* after getting drained signal there is no data flows, so no need to do pad_block */
10546 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10547 gst_pad_unlink(srcpad, sinkpad);
10549 /* send custom event to sink pad to handle it at video sink */
10551 LOGD("send custom event to sinkpad");
10552 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10553 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10554 gst_pad_send_event(sinkpad, event);
10558 gst_object_unref(sinkpad);
10561 gst_object_unref(srcpad);
10564 LOGD("selector release");
10566 /* release and unref requests pad from the selector */
10567 for (n = 0; n < selector->channels->len; n++) {
10568 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10569 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10571 g_ptr_array_set_size(selector->channels, 0);
10573 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10574 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10576 player->pipeline->mainbin[selectorId].gst = NULL;
10584 __mmplayer_deactivate_old_path(mm_player_t *player)
10587 MMPLAYER_RETURN_IF_FAIL(player);
10589 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10590 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10591 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10592 LOGE("deactivate selector error");
10596 _mmplayer_track_destroy(player);
10597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10599 if (player->streamer) {
10600 __mm_player_streaming_deinitialize(player->streamer);
10601 __mm_player_streaming_destroy(player->streamer);
10602 player->streamer = NULL;
10605 MMPLAYER_PLAYBACK_LOCK(player);
10606 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10613 if (!player->msg_posted) {
10614 MMMessageParamType msg = {0,};
10617 msg.code = MM_ERROR_PLAYER_INTERNAL;
10618 LOGE("next_uri_play> deactivate error");
10620 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10621 player->msg_posted = TRUE;
10626 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10628 int result = MM_ERROR_NONE;
10629 mm_player_t* player = (mm_player_t*) hplayer;
10632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10635 player->http_file_buffering_path = (gchar*)file_path;
10636 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10642 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10644 int result = MM_ERROR_NONE;
10645 mm_player_t* player = (mm_player_t*) hplayer;
10648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10650 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10651 if (mmf_attrs_commit(player->attrs)) {
10652 LOGE("failed to commit the original uri.\n");
10653 result = MM_ERROR_PLAYER_INTERNAL;
10655 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10656 LOGE("failed to add the original uri in the uri list.\n");
10663 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10665 mm_player_t* player = (mm_player_t*) hplayer;
10666 guint num_of_list = 0;
10670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10671 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10673 if (player->pipeline && player->pipeline->textbin) {
10674 LOGE("subtitle path is enabled.\n");
10675 return MM_ERROR_PLAYER_INVALID_STATE;
10678 num_of_list = g_list_length(player->uri_info.uri_list);
10680 if (is_first_path == TRUE) {
10681 if (num_of_list == 0) {
10682 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10683 LOGD("add original path : %s", uri);
10685 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10686 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10688 LOGD("change original path : %s", uri);
10691 MMHandleType attrs = 0;
10692 attrs = MMPLAYER_GET_ATTRS(player);
10694 if (num_of_list == 0) {
10695 char *original_uri = NULL;
10698 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10700 if (!original_uri) {
10701 LOGE("there is no original uri.");
10702 return MM_ERROR_PLAYER_INVALID_STATE;
10705 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10706 player->uri_info.uri_idx = 0;
10708 LOGD("add original path at first : %s(%d)", original_uri);
10712 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10713 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10717 return MM_ERROR_NONE;
10720 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10722 mm_player_t* player = (mm_player_t*) hplayer;
10723 char *next_uri = NULL;
10724 guint num_of_list = 0;
10727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10729 num_of_list = g_list_length(player->uri_info.uri_list);
10731 if (num_of_list > 0) {
10732 gint uri_idx = player->uri_info.uri_idx;
10734 if (uri_idx < num_of_list-1)
10739 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10740 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10742 *uri = g_strdup(next_uri);
10746 return MM_ERROR_NONE;
10750 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10751 GstCaps *caps, gpointer data)
10753 mm_player_t* player = (mm_player_t*)data;
10754 const gchar* klass = NULL;
10755 const gchar* mime = NULL;
10756 gchar* caps_str = NULL;
10758 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10759 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10760 caps_str = gst_caps_to_string(caps);
10762 LOGW("unknown type of caps : %s from %s",
10763 caps_str, GST_ELEMENT_NAME(elem));
10765 MMPLAYER_FREEIF(caps_str);
10767 /* There is no available codec. */
10768 __mmplayer_check_not_supported_codec(player, klass, mime);
10772 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10773 GstCaps * caps, gpointer data)
10775 mm_player_t* player = (mm_player_t*)data;
10776 const char* mime = NULL;
10777 gboolean ret = TRUE;
10779 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10780 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10782 if (g_str_has_prefix(mime, "audio")) {
10783 GstStructure* caps_structure = NULL;
10784 gint samplerate = 0;
10786 gchar *caps_str = NULL;
10788 caps_structure = gst_caps_get_structure(caps, 0);
10789 gst_structure_get_int(caps_structure, "rate", &samplerate);
10790 gst_structure_get_int(caps_structure, "channels", &channels);
10792 if ((channels > 0 && samplerate == 0)) {
10793 LOGD("exclude audio...");
10797 caps_str = gst_caps_to_string(caps);
10798 /* set it directly because not sent by TAG */
10799 if (g_strrstr(caps_str, "mobile-xmf"))
10800 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10801 MMPLAYER_FREEIF(caps_str);
10802 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10803 MMMessageParamType msg_param;
10804 memset(&msg_param, 0, sizeof(MMMessageParamType));
10805 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10806 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10807 LOGD("video file is not supported on this device");
10809 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10810 LOGD("already video linked");
10813 LOGD("found new stream");
10820 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10822 int ret = MM_ERROR_NONE;
10824 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10826 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10827 GstStructure* str = NULL;
10829 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10831 LOGD("audio codec type: %d", codec_type);
10832 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10833 /* sw codec will be skipped */
10834 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10835 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10836 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10837 ret = MM_ERROR_PLAYER_INTERNAL;
10841 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10842 /* hw codec will be skipped */
10843 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10844 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10845 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10846 ret = MM_ERROR_PLAYER_INTERNAL;
10851 str = gst_caps_get_structure(caps, 0);
10853 gst_structure_get_int(str, "channels", &channels);
10855 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10856 if (player->max_audio_channels < channels)
10857 player->max_audio_channels = channels;
10859 /* set stream information */
10860 if (!player->audiodec_linked)
10861 __mmplayer_set_audio_attrs(player, caps);
10863 /* update codec info */
10864 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10865 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10866 player->audiodec_linked = 1;
10868 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10870 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10872 LOGD("video codec type: %d", codec_type);
10873 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10874 /* sw codec is skipped */
10875 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10876 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10877 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10878 ret = MM_ERROR_PLAYER_INTERNAL;
10882 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10883 /* hw codec is skipped */
10884 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10885 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10886 ret = MM_ERROR_PLAYER_INTERNAL;
10891 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10892 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10894 /* mark video decoder for acquire */
10895 if (player->video_decoder_resource == NULL) {
10896 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10897 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10898 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10899 &player->video_decoder_resource)
10900 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10901 LOGE("could not mark video_decoder resource for acquire");
10902 ret = MM_ERROR_PLAYER_INTERNAL;
10906 LOGW("video decoder resource is already acquired, skip it.");
10907 ret = MM_ERROR_PLAYER_INTERNAL;
10911 player->interrupted_by_resource = FALSE;
10912 /* acquire resources for video playing */
10913 if (mm_resource_manager_commit(player->resource_manager)
10914 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10915 LOGE("could not acquire resources for video decoding\n");
10916 ret = MM_ERROR_PLAYER_INTERNAL;
10921 /* update codec info */
10922 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10923 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10924 player->videodec_linked = 1;
10932 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10933 GstCaps* caps, GstElementFactory* factory, gpointer data)
10935 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10936 We are defining our own and will be removed when it actually exposed */
10938 GST_AUTOPLUG_SELECT_TRY,
10939 GST_AUTOPLUG_SELECT_EXPOSE,
10940 GST_AUTOPLUG_SELECT_SKIP
10941 } GstAutoplugSelectResult;
10943 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10944 mm_player_t* player = (mm_player_t*)data;
10946 gchar* factory_name = NULL;
10947 gchar* caps_str = NULL;
10948 const gchar* klass = NULL;
10951 factory_name = GST_OBJECT_NAME(factory);
10952 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10953 caps_str = gst_caps_to_string(caps);
10955 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10957 /* store type string */
10958 if (player->type == NULL) {
10959 player->type = gst_caps_to_string(caps);
10960 __mmplayer_update_content_type_info(player);
10963 /* filtering exclude keyword */
10964 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10965 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10966 LOGW("skipping [%s] by exculde keyword [%s]\n",
10967 factory_name, player->ini.exclude_element_keyword[idx]);
10969 result = GST_AUTOPLUG_SELECT_SKIP;
10974 /* exclude webm format */
10975 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10976 * because webm format is not supportable.
10977 * If webm is disabled in "autoplug-continue", there is no state change
10978 * failure or error because the decodebin will expose the pad directly.
10979 * It make MSL invoke _prepare_async_callback.
10980 * So, we need to disable webm format in "autoplug-select" */
10981 if (caps_str && strstr(caps_str, "webm")) {
10982 LOGW("webm is not supported");
10983 result = GST_AUTOPLUG_SELECT_SKIP;
10987 /* check factory class for filtering */
10988 /* NOTE : msl don't need to use image plugins.
10989 * So, those plugins should be skipped for error handling.
10991 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10992 LOGD("skipping [%s] by not required\n", factory_name);
10993 result = GST_AUTOPLUG_SELECT_SKIP;
10997 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10998 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10999 // TO CHECK : subtitle if needed, add subparse exception.
11000 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11001 result = GST_AUTOPLUG_SELECT_SKIP;
11005 if (g_strrstr(factory_name, "mpegpsdemux")) {
11006 LOGD("skipping PS container - not support\n");
11007 result = GST_AUTOPLUG_SELECT_SKIP;
11011 if (g_strrstr(factory_name, "mssdemux"))
11012 player->smooth_streaming = TRUE;
11014 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11015 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11018 GstStructure *str = NULL;
11019 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11021 /* don't make video because of not required */
11022 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11023 (player->set_mode.media_packet_video_stream == FALSE)) {
11024 LOGD("no video because it's not required. -> return expose");
11025 result = GST_AUTOPLUG_SELECT_EXPOSE;
11029 /* get w/h for omx state-tune */
11030 /* FIXME: deprecated? */
11031 str = gst_caps_get_structure(caps, 0);
11032 gst_structure_get_int(str, "width", &width);
11035 if (player->v_stream_caps) {
11036 gst_caps_unref(player->v_stream_caps);
11037 player->v_stream_caps = NULL;
11040 player->v_stream_caps = gst_caps_copy(caps);
11041 LOGD("take caps for video state tune");
11042 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11046 if (g_strrstr(klass, "Codec/Decoder")) {
11047 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11048 LOGD("skipping %s codec", factory_name);
11049 result = GST_AUTOPLUG_SELECT_SKIP;
11055 MMPLAYER_FREEIF(caps_str);
11061 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11064 //mm_player_t* player = (mm_player_t*)data;
11065 GstCaps* caps = NULL;
11067 LOGD("[Decodebin2] pad-removed signal\n");
11069 caps = gst_pad_query_caps(new_pad, NULL);
11071 gchar* caps_str = NULL;
11072 caps_str = gst_caps_to_string(caps);
11074 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11076 MMPLAYER_FREEIF(caps_str);
11077 gst_caps_unref(caps);
11082 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11084 mm_player_t* player = (mm_player_t*)data;
11085 GstIterator *iter = NULL;
11086 GValue item = { 0, };
11087 GstPad *pad = NULL;
11088 gboolean done = FALSE;
11089 gboolean is_all_drained = TRUE;
11092 MMPLAYER_RETURN_IF_FAIL(player);
11094 LOGD("__mmplayer_gst_decode_drained");
11096 if (player->use_deinterleave == TRUE) {
11097 LOGD("group playing mode.");
11101 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11102 LOGW("Fail to get cmd lock");
11106 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11107 !__mmplayer_verify_next_play_path(player)) {
11108 LOGD("decoding is finished.");
11109 __mmplayer_reset_gapless_state(player);
11110 MMPLAYER_CMD_UNLOCK(player);
11114 player->gapless.reconfigure = TRUE;
11116 /* check decodebin src pads whether they received EOS or not */
11117 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11120 switch (gst_iterator_next(iter, &item)) {
11121 case GST_ITERATOR_OK:
11122 pad = g_value_get_object(&item);
11123 if (pad && !GST_PAD_IS_EOS(pad)) {
11124 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11125 is_all_drained = FALSE;
11128 g_value_reset(&item);
11130 case GST_ITERATOR_RESYNC:
11131 gst_iterator_resync(iter);
11133 case GST_ITERATOR_ERROR:
11134 case GST_ITERATOR_DONE:
11139 g_value_unset(&item);
11140 gst_iterator_free(iter);
11142 if (!is_all_drained) {
11143 LOGD("Wait util the all pads get EOS.");
11144 MMPLAYER_CMD_UNLOCK(player);
11149 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11150 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11152 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11153 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11154 __mmplayer_deactivate_old_path(player);
11155 MMPLAYER_CMD_UNLOCK(player);
11161 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11163 mm_player_t* player = (mm_player_t*)data;
11164 const gchar* klass = NULL;
11165 gchar* factory_name = NULL;
11167 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11168 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11170 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11172 if (__mmplayer_add_dump_buffer_probe(player, element))
11173 LOGD("add buffer probe");
11176 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11177 gchar* selected = NULL;
11178 selected = g_strdup(GST_ELEMENT_NAME(element));
11179 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11183 if (g_strrstr(klass, "Parser")) {
11184 gchar* selected = NULL;
11186 selected = g_strdup(factory_name);
11187 player->parsers = g_list_append(player->parsers, selected);
11190 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11191 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11192 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11194 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11195 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11197 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11198 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11199 "max-video-width", player->adaptive_info.limit.width,
11200 "max-video-height", player->adaptive_info.limit.height, NULL);
11202 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11203 /* FIXIT : first value will be overwritten if there's more
11204 * than 1 demuxer/parser
11207 //LOGD("plugged element is demuxer. take it\n");
11208 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11209 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11211 /*Added for multi audio support */ // Q. del?
11212 if (g_strrstr(klass, "Demux")) {
11213 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11214 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11218 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11219 int surface_type = 0;
11221 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11224 // to support trust-zone only
11225 if (g_strrstr(factory_name, "asfdemux")) {
11226 LOGD("set file-location %s\n", player->profile.uri);
11227 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11229 if (player->video_hub_download_mode == TRUE)
11230 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11231 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11232 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11233 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11234 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11235 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11236 (__mmplayer_is_only_mp3_type(player->type))) {
11237 LOGD("[mpegaudioparse] set streaming pull mode.");
11238 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11240 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11241 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11244 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11245 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11246 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
11248 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11249 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11251 if (!MMPLAYER_IS_HTTP_PD(player) &&
11252 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11253 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
11254 (MMPLAYER_IS_DASH_STREAMING(player)))) {
11255 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11256 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
11257 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11265 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11268 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11270 if (MMPLAYER_IS_STREAMING(player))
11273 /* This callback can be set to music player only. */
11274 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11275 LOGW("audio callback is not supported for video");
11279 if (player->audio_stream_cb) {
11280 GstPad *pad = NULL;
11282 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11285 LOGE("failed to get sink pad from audiosink to probe data\n");
11288 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11289 __mmplayer_audio_stream_probe, player, NULL);
11291 gst_object_unref(pad);
11295 LOGE("There is no audio callback to configure.\n");
11305 __mmplayer_release_misc(mm_player_t* player)
11308 bool cur_mode = player->set_mode.rich_audio;
11311 MMPLAYER_RETURN_IF_FAIL(player);
11313 player->video_stream_cb = NULL;
11314 player->video_stream_cb_user_param = NULL;
11315 player->video_stream_prerolled = FALSE;
11317 player->audio_stream_cb = NULL;
11318 player->audio_stream_render_cb_ex = NULL;
11319 player->audio_stream_cb_user_param = NULL;
11320 player->audio_stream_sink_sync = false;
11322 player->video_stream_changed_cb = NULL;
11323 player->video_stream_changed_cb_user_param = NULL;
11325 player->audio_stream_changed_cb = NULL;
11326 player->audio_stream_changed_cb_user_param = NULL;
11328 player->sent_bos = FALSE;
11329 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11331 player->doing_seek = FALSE;
11333 player->total_bitrate = 0;
11334 player->total_maximum_bitrate = 0;
11336 player->not_found_demuxer = 0;
11338 player->last_position = 0;
11339 player->duration = 0;
11340 player->http_content_size = 0;
11341 player->not_supported_codec = MISSING_PLUGIN_NONE;
11342 player->can_support_codec = FOUND_PLUGIN_NONE;
11343 player->pending_seek.is_pending = FALSE;
11344 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11345 player->pending_seek.pos = 0;
11346 player->msg_posted = FALSE;
11347 player->has_many_types = FALSE;
11348 player->max_audio_channels = 0;
11349 player->video_share_api_delta = 0;
11350 player->video_share_clock_delta = 0;
11351 player->is_subtitle_force_drop = FALSE;
11352 player->play_subtitle = FALSE;
11353 player->adjust_subtitle_pos = 0;
11354 player->last_multiwin_status = FALSE;
11355 player->has_closed_caption = FALSE;
11356 player->set_mode.media_packet_video_stream = FALSE;
11357 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11358 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11360 player->set_mode.rich_audio = cur_mode;
11362 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11363 player->bitrate[i] = 0;
11364 player->maximum_bitrate[i] = 0;
11367 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11369 /* remove media stream cb(appsrc cb) */
11370 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11371 player->media_stream_buffer_status_cb[i] = NULL;
11372 player->media_stream_seek_data_cb[i] = NULL;
11373 player->buffer_cb_user_param[i] = NULL;
11374 player->seek_cb_user_param[i] = NULL;
11376 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11378 /* free memory related to audio effect */
11379 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11381 if (player->adaptive_info.var_list) {
11382 g_list_free_full(player->adaptive_info.var_list, g_free);
11383 player->adaptive_info.var_list = NULL;
11386 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11387 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11388 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11390 /* Reset video360 settings to their defaults in case if the pipeline is to be
11393 player->video360_metadata.is_spherical = -1;
11394 player->is_openal_plugin_used = FALSE;
11396 player->is_content_spherical = FALSE;
11397 player->is_video360_enabled = TRUE;
11398 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11399 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11400 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11401 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11402 player->video360_zoom = 1.0f;
11403 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11404 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11406 player->sound.rg_enable = false;
11412 __mmplayer_release_misc_post(mm_player_t* player)
11414 char *original_uri = NULL;
11417 /* player->pipeline is already released before. */
11419 MMPLAYER_RETURN_IF_FAIL(player);
11421 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11423 /* clean found parsers */
11424 if (player->parsers) {
11425 GList *parsers = player->parsers;
11426 for (; parsers; parsers = g_list_next(parsers)) {
11427 gchar *name = parsers->data;
11428 MMPLAYER_FREEIF(name);
11430 g_list_free(player->parsers);
11431 player->parsers = NULL;
11434 /* clean found audio decoders */
11435 if (player->audio_decoders) {
11436 GList *a_dec = player->audio_decoders;
11437 for (; a_dec; a_dec = g_list_next(a_dec)) {
11438 gchar *name = a_dec->data;
11439 MMPLAYER_FREEIF(name);
11441 g_list_free(player->audio_decoders);
11442 player->audio_decoders = NULL;
11445 /* clean the uri list except original uri */
11446 if (player->uri_info.uri_list) {
11447 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11449 if (player->attrs) {
11450 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11451 LOGD("restore original uri = %s\n", original_uri);
11453 if (mmf_attrs_commit(player->attrs))
11454 LOGE("failed to commit the original uri.\n");
11457 GList *uri_list = player->uri_info.uri_list;
11458 for (; uri_list; uri_list = g_list_next(uri_list)) {
11459 gchar *uri = uri_list->data;
11460 MMPLAYER_FREEIF(uri);
11462 g_list_free(player->uri_info.uri_list);
11463 player->uri_info.uri_list = NULL;
11466 /* clear the audio stream buffer list */
11467 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11469 /* clear the video stream bo list */
11470 __mmplayer_video_stream_destroy_bo_list(player);
11471 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11473 if (player->profile.input_mem.buf) {
11474 free(player->profile.input_mem.buf);
11475 player->profile.input_mem.buf = NULL;
11477 player->profile.input_mem.len = 0;
11478 player->profile.input_mem.offset = 0;
11480 player->uri_info.uri_idx = 0;
11484 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11486 GstElement *element = NULL;
11489 LOGD("creating %s to plug\n", name);
11491 element = gst_element_factory_make(name, NULL);
11493 LOGE("failed to create queue\n");
11497 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11498 LOGE("failed to set state READY to %s\n", name);
11499 gst_object_unref(element);
11503 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11504 LOGE("failed to add %s\n", name);
11505 gst_object_unref(element);
11509 sinkpad = gst_element_get_static_pad(element, "sink");
11511 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11512 LOGE("failed to link %s\n", name);
11513 gst_object_unref(sinkpad);
11514 gst_object_unref(element);
11518 LOGD("linked %s to pipeline successfully\n", name);
11520 gst_object_unref(sinkpad);
11526 __mmplayer_check_subtitle(mm_player_t* player)
11528 MMHandleType attrs = 0;
11529 char *subtitle_uri = NULL;
11533 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11535 /* get subtitle attribute */
11536 attrs = MMPLAYER_GET_ATTRS(player);
11540 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11541 if (!subtitle_uri || !strlen(subtitle_uri))
11544 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11545 player->is_external_subtitle_present = TRUE;
11553 __mmplayer_can_extract_pcm(mm_player_t* player)
11555 MMHandleType attrs = 0;
11556 gboolean sound_extraction = FALSE;
11558 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11560 attrs = MMPLAYER_GET_ATTRS(player);
11562 LOGE("fail to get attributes.");
11566 /* get sound_extraction property */
11567 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11569 if (!sound_extraction) {
11570 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11578 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11581 MMMessageParamType msg_param;
11582 gchar *msg_src_element = NULL;
11583 GstStructure *s = NULL;
11584 guint error_id = 0;
11585 gchar *error_string = NULL;
11589 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11590 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11592 s = gst_structure_copy(gst_message_get_structure(message));
11595 if (!gst_structure_get_uint(s, "error_id", &error_id))
11596 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11598 switch (error_id) {
11599 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11600 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11602 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11603 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11605 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11606 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11608 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11609 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11611 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11612 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11614 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11615 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11617 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11618 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11620 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11621 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11623 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11624 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11626 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11627 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11629 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11630 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11632 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11633 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11635 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11636 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11638 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11639 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11641 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11642 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11644 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11645 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11647 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11648 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11650 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11651 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11653 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11654 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11656 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11657 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11659 case MMPLAYER_STREAMING_ERROR_GONE:
11660 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11662 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11663 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11665 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11666 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11668 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11669 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11671 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11672 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11674 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11675 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11677 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11678 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11680 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11681 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11683 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11684 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11686 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11687 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11689 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11690 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11692 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11693 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11695 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11696 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11698 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11699 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11701 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11702 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11704 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11705 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11707 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11708 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11710 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11711 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11713 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11714 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11716 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11717 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11719 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11720 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11722 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11723 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11725 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11726 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11728 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11729 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11731 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11732 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11736 gst_structure_free(s);
11737 return MM_ERROR_PLAYER_STREAMING_FAIL;
11741 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11743 msg_param.data = (void *) error_string;
11745 if (message->src) {
11746 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11748 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11749 msg_src_element, msg_param.code, (char*)msg_param.data);
11752 /* post error to application */
11753 if (!player->msg_posted) {
11754 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11756 /* don't post more if one was sent already */
11757 player->msg_posted = TRUE;
11759 LOGD("skip error post because it's sent already.\n");
11761 gst_structure_free(s);
11763 g_free(error_string);
11770 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11772 MMPLAYER_RETURN_IF_FAIL(player);
11774 /* post now if delay is zero */
11775 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11776 LOGD("eos delay is zero. posting EOS now\n");
11777 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11779 if (player->set_mode.pcm_extraction)
11780 __mmplayer_cancel_eos_timer(player);
11785 /* cancel if existing */
11786 __mmplayer_cancel_eos_timer(player);
11788 /* init new timeout */
11789 /* NOTE : consider give high priority to this timer */
11790 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11792 player->eos_timer = g_timeout_add(delay_in_ms,
11793 __mmplayer_eos_timer_cb, player);
11795 player->context.global_default = g_main_context_default();
11796 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11798 /* check timer is valid. if not, send EOS now */
11799 if (player->eos_timer == 0) {
11800 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11801 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11806 __mmplayer_cancel_eos_timer(mm_player_t* player)
11808 MMPLAYER_RETURN_IF_FAIL(player);
11810 if (player->eos_timer) {
11811 LOGD("cancel eos timer");
11812 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11813 player->eos_timer = 0;
11820 __mmplayer_eos_timer_cb(gpointer u_data)
11822 mm_player_t* player = NULL;
11823 MMHandleType attrs = 0;
11826 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11828 player = (mm_player_t*) u_data;
11829 attrs = MMPLAYER_GET_ATTRS(player);
11831 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11834 gint ret_value = 0;
11835 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11836 if (ret_value != MM_ERROR_NONE)
11837 LOGE("seeking to 0 failed in repeat play");
11840 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11843 /* we are returning FALSE as we need only one posting */
11847 /* sending event to one of sinkelements */
11849 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11851 GstEvent * event2 = NULL;
11852 GList *sinks = NULL;
11853 gboolean res = FALSE;
11856 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11857 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11859 /* While adding subtitles in live feeds seek is getting called.
11860 Adding defensive check in framework layer.*/
11861 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11862 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11863 LOGE("Should not send seek event during live playback");
11868 if (player->play_subtitle)
11869 event2 = gst_event_copy((const GstEvent *)event);
11871 sinks = player->sink_elements;
11873 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11875 if (GST_IS_ELEMENT(sink)) {
11876 /* keep ref to the event */
11877 gst_event_ref(event);
11879 if ((res = gst_element_send_event(sink, event))) {
11880 LOGD("sending event[%s] to sink element [%s] success!\n",
11881 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11883 /* rtsp case, asyn_done is not called after seek during pause state */
11884 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11885 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11886 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11887 LOGD("RTSP seek completed, after pause state..\n");
11888 player->doing_seek = FALSE;
11889 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11895 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11896 sinks = g_list_next(sinks);
11903 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11904 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11907 sinks = g_list_next(sinks);
11910 /* Note : Textbin is not linked to the video or audio bin.
11911 * It needs to send the event to the text sink seperatelly.
11913 if (player->play_subtitle && player->pipeline) {
11914 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11916 if (GST_IS_ELEMENT(text_sink)) {
11917 /* keep ref to the event */
11918 gst_event_ref(event2);
11920 if ((res = gst_element_send_event(text_sink, event2)))
11921 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11922 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11924 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11925 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11927 gst_event_unref(event2);
11931 gst_event_unref(event);
11939 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11943 MMPLAYER_RETURN_IF_FAIL(player);
11944 MMPLAYER_RETURN_IF_FAIL(sink);
11946 player->sink_elements =
11947 g_list_append(player->sink_elements, sink);
11953 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11957 MMPLAYER_RETURN_IF_FAIL(player);
11958 MMPLAYER_RETURN_IF_FAIL(sink);
11960 player->sink_elements =
11961 g_list_remove(player->sink_elements, sink);
11967 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11968 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11969 gint64 cur, GstSeekType stop_type, gint64 stop)
11971 GstEvent* event = NULL;
11972 gboolean result = FALSE;
11976 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11978 if (player->pipeline && player->pipeline->textbin)
11979 __mmplayer_drop_subtitle(player, FALSE);
11981 event = gst_event_new_seek(rate, format, flags, cur_type,
11982 cur, stop_type, stop);
11984 result = __gst_send_event_to_sink(player, event);
11991 /* NOTE : be careful with calling this api. please refer to below glib comment
11992 * glib comment : Note that there is a bug in GObject that makes this function much
11993 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11994 * will no longer be called, but, the signal handler is not currently disconnected.
11995 * If the instance is itself being freed at the same time than this doesn't matter,
11996 * since the signal will automatically be removed, but if instance persists,
11997 * then the signal handler will leak. You should not remove the signal yourself
11998 * because in a future versions of GObject, the handler will automatically be
12001 * It's possible to work around this problem in a way that will continue to work
12002 * with future versions of GObject by checking that the signal handler is still
12003 * connected before disconnected it:
12005 * if (g_signal_handler_is_connected(instance, id))
12006 * g_signal_handler_disconnect(instance, id);
12009 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12011 GList* sig_list = NULL;
12012 MMPlayerSignalItem* item = NULL;
12016 MMPLAYER_RETURN_IF_FAIL(player);
12018 LOGD("release signals type : %d", type);
12020 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12021 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12022 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12023 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12024 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12025 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12029 sig_list = player->signals[type];
12031 for (; sig_list; sig_list = sig_list->next) {
12032 item = sig_list->data;
12034 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12035 if (g_signal_handler_is_connected(item->obj, item->sig))
12036 g_signal_handler_disconnect(item->obj, item->sig);
12039 MMPLAYER_FREEIF(item);
12042 g_list_free(player->signals[type]);
12043 player->signals[type] = NULL;
12050 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12052 mm_player_t* player = 0;
12053 int prev_display_surface_type = 0;
12054 void *prev_display_overlay = NULL;
12055 const gchar *klass = NULL;
12056 gchar *cur_videosink_name = NULL;
12059 int num_of_dec = 2; /* DEC1, DEC2 */
12063 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12064 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12066 player = MM_PLAYER_CAST(handle);
12068 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12069 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12071 return MM_ERROR_INVALID_ARGUMENT;
12074 /* load previous attributes */
12075 if (player->attrs) {
12076 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12077 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12078 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12079 if (prev_display_surface_type == surface_type) {
12080 LOGD("incoming display surface type is same as previous one, do nothing..");
12082 return MM_ERROR_NONE;
12085 LOGE("failed to load attributes");
12087 return MM_ERROR_PLAYER_INTERNAL;
12090 /* check videosink element is created */
12091 if (!player->pipeline || !player->pipeline->videobin ||
12092 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12093 LOGD("videosink element is not yet ready");
12095 /* videobin is not created yet, so we just set attributes related to display surface */
12096 LOGD("store display attribute for given surface type(%d)", surface_type);
12097 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12098 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12099 if (mmf_attrs_commit(player->attrs)) {
12100 LOGE("failed to commit attribute");
12102 return MM_ERROR_PLAYER_INTERNAL;
12105 return MM_ERROR_NONE;
12107 /* get player command status */
12108 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12109 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12111 return MM_ERROR_PLAYER_INVALID_STATE;
12114 /* surface change */
12115 for (i = 0 ; i < num_of_dec ; i++) {
12116 if (player->pipeline->mainbin &&
12117 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12118 GstElementFactory *decfactory;
12119 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12121 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12122 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12123 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12124 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12128 LOGW("success to changing display surface(%d)", surface_type);
12130 return MM_ERROR_NONE;
12132 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12133 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12137 LOGW("success to changing display surface(%d)", surface_type);
12139 return MM_ERROR_NONE;
12142 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12143 ret = MM_ERROR_PLAYER_INTERNAL;
12152 /* rollback to previous attributes */
12153 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12154 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12155 if (mmf_attrs_commit(player->attrs)) {
12156 LOGE("failed to commit attributes to rollback");
12158 return MM_ERROR_PLAYER_INTERNAL;
12164 /* NOTE : It does not support some use cases, eg using colorspace converter */
12166 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12168 GstPad *src_pad_dec = NULL;
12169 GstPad *sink_pad_videosink = NULL;
12170 GstPad *sink_pad_videobin = NULL;
12171 GstClock *clock = NULL;
12172 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12173 int ret = MM_ERROR_NONE;
12174 gboolean is_audiobin_created = TRUE;
12178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12179 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12180 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12182 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12183 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12185 /* get information whether if audiobin is created */
12186 if (!player->pipeline->audiobin ||
12187 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12188 LOGW("audiobin is null, this video content may not have audio data");
12189 is_audiobin_created = FALSE;
12192 /* get current state of player */
12193 previous_state = MMPLAYER_CURRENT_STATE(player);
12194 LOGD("previous state(%d)", previous_state);
12197 /* get src pad of decoder and block it */
12198 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12199 if (!src_pad_dec) {
12200 LOGE("failed to get src pad from decode in mainbin");
12201 return MM_ERROR_PLAYER_INTERNAL;
12204 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12205 LOGW("trying to block pad(video)");
12206 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12207 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12210 LOGE("failed to set block pad(video)");
12211 return MM_ERROR_PLAYER_INTERNAL;
12213 LOGW("pad is blocked(video)");
12215 /* no data flows, so no need to do pad_block */
12216 if (player->doing_seek)
12217 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12219 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12223 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12224 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12225 LOGE("failed to remove previous ghost_pad for videobin");
12226 return MM_ERROR_PLAYER_INTERNAL;
12229 /* change state of videobin to NULL */
12230 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12231 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12232 if (ret != GST_STATE_CHANGE_SUCCESS) {
12233 LOGE("failed to change state of videobin to NULL");
12234 return MM_ERROR_PLAYER_INTERNAL;
12237 /* unlink between decoder and videobin and remove previous videosink from videobin */
12238 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12239 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12240 LOGE("failed to remove former videosink from videobin");
12241 return MM_ERROR_PLAYER_INTERNAL;
12244 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12246 /* create a new videosink and add it to videobin */
12247 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12248 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12249 LOGE("failed to create videosink element\n");
12251 return MM_ERROR_PLAYER_INTERNAL;
12253 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12254 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12255 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12257 /* save attributes */
12258 if (player->attrs) {
12259 /* set a new display surface type */
12260 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12261 /* set a new diplay overlay */
12262 switch (surface_type) {
12263 case MM_DISPLAY_SURFACE_OVERLAY:
12264 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12265 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12268 LOGE("invalid type(%d) for changing display surface", surface_type);
12270 return MM_ERROR_INVALID_ARGUMENT;
12272 if (mmf_attrs_commit(player->attrs)) {
12273 LOGE("failed to commit");
12275 return MM_ERROR_PLAYER_INTERNAL;
12278 LOGE("player->attrs is null, failed to save attributes");
12280 return MM_ERROR_PLAYER_INTERNAL;
12283 /* update video param */
12284 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12285 LOGE("failed to update video param");
12286 return MM_ERROR_PLAYER_INTERNAL;
12289 /* change state of videobin to READY */
12290 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12291 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12292 if (ret != GST_STATE_CHANGE_SUCCESS) {
12293 LOGE("failed to change state of videobin to READY");
12294 return MM_ERROR_PLAYER_INTERNAL;
12297 /* change ghostpad */
12298 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12299 if (!sink_pad_videosink) {
12300 LOGE("failed to get sink pad from videosink element");
12301 return MM_ERROR_PLAYER_INTERNAL;
12303 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12304 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12305 LOGE("failed to set active to ghost_pad");
12306 return MM_ERROR_PLAYER_INTERNAL;
12308 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12309 LOGE("failed to change ghostpad for videobin");
12310 return MM_ERROR_PLAYER_INTERNAL;
12312 gst_object_unref(sink_pad_videosink);
12314 /* link decoder with videobin */
12315 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12316 if (!sink_pad_videobin) {
12317 LOGE("failed to get sink pad from videobin");
12318 return MM_ERROR_PLAYER_INTERNAL;
12320 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12321 LOGE("failed to link");
12322 return MM_ERROR_PLAYER_INTERNAL;
12324 gst_object_unref(sink_pad_videobin);
12326 /* clock setting for a new videosink plugin */
12327 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12328 so we set it from audiosink plugin or pipeline(system clock) */
12329 if (!is_audiobin_created) {
12330 LOGW("audiobin is not created, get clock from pipeline..");
12331 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12333 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12337 GstClockTime base_time;
12338 LOGD("set the clock to videosink");
12339 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12340 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12342 LOGD("got clock of videosink");
12343 now = gst_clock_get_time(clock);
12344 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12345 LOGD("at time %" GST_TIME_FORMAT ", base %"
12346 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12348 LOGE("failed to get clock of videosink after setting clock");
12349 return MM_ERROR_PLAYER_INTERNAL;
12352 LOGW("failed to get clock, maybe it is the time before first playing");
12354 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12355 /* change state of videobin to PAUSED */
12356 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12357 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12358 if (ret != GST_STATE_CHANGE_FAILURE) {
12359 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12361 LOGE("failed to change state of videobin to PLAYING");
12362 return MM_ERROR_PLAYER_INTERNAL;
12365 /* release blocked and unref src pad of video decoder */
12367 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12368 LOGE("failed to set pad blocked FALSE(video)");
12369 return MM_ERROR_PLAYER_INTERNAL;
12372 LOGW("pad is unblocked(video)");
12374 if (player->doing_seek)
12375 LOGW("not completed seek(%d)", player->doing_seek);
12376 /* change state of videobin to PAUSED */
12377 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12378 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12379 if (ret != GST_STATE_CHANGE_FAILURE) {
12380 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12382 LOGE("failed to change state of videobin to PLAYING");
12383 return MM_ERROR_PLAYER_INTERNAL;
12386 /* already skipped pad block */
12387 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12390 /* do get/set position for new videosink plugin */
12392 gint64 position = 0;
12394 LOGD("do get/set position for new videosink plugin");
12395 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12396 LOGE("failed to get position");
12397 return MM_ERROR_PLAYER_INTERNAL;
12399 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12400 /* accurate seek */
12401 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12402 LOGE("failed to set position");
12403 return MM_ERROR_PLAYER_INTERNAL;
12406 /* key unit seek */
12407 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12408 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12409 GST_SEEK_TYPE_SET, position,
12410 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12412 LOGE("failed to set position");
12413 return MM_ERROR_PLAYER_INTERNAL;
12419 gst_object_unref(src_pad_dec);
12420 LOGD("success to change sink");
12424 return MM_ERROR_NONE;
12428 /* Note : if silent is true, then subtitle would not be displayed. :*/
12429 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12431 mm_player_t* player = (mm_player_t*) hplayer;
12435 /* check player handle */
12436 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12438 player->set_mode.subtitle_off = silent;
12440 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12444 return MM_ERROR_NONE;
12447 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12449 MMPlayerGstElement* mainbin = NULL;
12450 MMPlayerGstElement* textbin = NULL;
12451 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12452 GstState current_state = GST_STATE_VOID_PENDING;
12453 GstState element_state = GST_STATE_VOID_PENDING;
12454 GstState element_pending_state = GST_STATE_VOID_PENDING;
12456 GstEvent *event = NULL;
12457 int result = MM_ERROR_NONE;
12459 GstClock *curr_clock = NULL;
12460 GstClockTime base_time, start_time, curr_time;
12465 /* check player handle */
12466 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12467 player->pipeline &&
12468 player->pipeline->mainbin &&
12469 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12471 mainbin = player->pipeline->mainbin;
12472 textbin = player->pipeline->textbin;
12474 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12476 // sync clock with current pipeline
12477 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12478 curr_time = gst_clock_get_time(curr_clock);
12480 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12481 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12483 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12484 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12486 if (current_state > GST_STATE_READY) {
12487 // sync state with current pipeline
12488 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12489 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12490 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12492 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12493 if (GST_STATE_CHANGE_FAILURE == ret) {
12494 LOGE("fail to state change.\n");
12495 result = MM_ERROR_PLAYER_INTERNAL;
12500 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12501 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12504 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12505 gst_object_unref(curr_clock);
12508 // seek to current position
12509 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12510 result = MM_ERROR_PLAYER_INVALID_STATE;
12511 LOGE("gst_element_query_position failed, invalid state\n");
12515 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12516 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);
12518 __gst_send_event_to_sink(player, event);
12520 result = MM_ERROR_PLAYER_INTERNAL;
12521 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12525 /* sync state with current pipeline */
12526 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12527 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12528 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12530 return MM_ERROR_NONE;
12533 /* release text pipeline resource */
12534 player->textsink_linked = 0;
12536 /* release signal */
12537 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12539 /* release textbin with it's childs */
12540 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12541 MMPLAYER_FREEIF(player->pipeline->textbin);
12542 player->pipeline->textbin = NULL;
12544 /* release subtitle elem */
12545 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12546 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12552 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12554 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12555 GstState current_state = GST_STATE_VOID_PENDING;
12557 MMHandleType attrs = 0;
12558 MMPlayerGstElement* mainbin = NULL;
12559 MMPlayerGstElement* textbin = NULL;
12561 gchar* subtitle_uri = NULL;
12562 int result = MM_ERROR_NONE;
12563 const gchar *charset = NULL;
12567 /* check player handle */
12568 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12569 player->pipeline &&
12570 player->pipeline->mainbin &&
12571 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12572 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12574 mainbin = player->pipeline->mainbin;
12575 textbin = player->pipeline->textbin;
12577 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12578 if (current_state < GST_STATE_READY) {
12579 result = MM_ERROR_PLAYER_INVALID_STATE;
12580 LOGE("Pipeline is not in proper state\n");
12584 attrs = MMPLAYER_GET_ATTRS(player);
12586 LOGE("cannot get content attribute\n");
12587 result = MM_ERROR_PLAYER_INTERNAL;
12591 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12592 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12593 LOGE("subtitle uri is not proper filepath\n");
12594 result = MM_ERROR_PLAYER_INVALID_URI;
12598 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12599 LOGE("failed to get storage info of subtitle path");
12600 result = MM_ERROR_PLAYER_INVALID_URI;
12604 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12605 LOGD("new subtitle file path is [%s]\n", filepath);
12607 if (!strcmp(filepath, subtitle_uri)) {
12608 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12611 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12612 if (mmf_attrs_commit(player->attrs)) {
12613 LOGE("failed to commit.\n");
12618 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12619 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12620 player->subtitle_language_list = NULL;
12621 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12623 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12624 if (ret != GST_STATE_CHANGE_SUCCESS) {
12625 LOGE("failed to change state of textbin to READY");
12626 result = MM_ERROR_PLAYER_INTERNAL;
12630 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12631 if (ret != GST_STATE_CHANGE_SUCCESS) {
12632 LOGE("failed to change state of subparse to READY");
12633 result = MM_ERROR_PLAYER_INTERNAL;
12637 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12638 if (ret != GST_STATE_CHANGE_SUCCESS) {
12639 LOGE("failed to change state of filesrc to READY");
12640 result = MM_ERROR_PLAYER_INTERNAL;
12644 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12646 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12648 charset = util_get_charset(filepath);
12650 LOGD("detected charset is %s\n", charset);
12651 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12654 result = _mmplayer_sync_subtitle_pipeline(player);
12661 /* API to switch between external subtitles */
12662 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12664 int result = MM_ERROR_NONE;
12665 mm_player_t* player = (mm_player_t*)hplayer;
12670 /* check player handle */
12671 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12673 /* filepath can be null in idle state */
12675 /* check file path */
12676 if ((path = strstr(filepath, "file://")))
12677 result = util_exist_file_path(path + 7);
12679 result = util_exist_file_path(filepath);
12681 if (result != MM_ERROR_NONE) {
12682 LOGE("invalid subtitle path 0x%X", result);
12683 return result; /* file not found or permission denied */
12687 if (!player->pipeline) {
12689 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12690 if (mmf_attrs_commit(player->attrs)) {
12691 LOGE("failed to commit"); /* subtitle path will not be created */
12692 return MM_ERROR_PLAYER_INTERNAL;
12695 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12696 /* check filepath */
12697 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12699 if (!__mmplayer_check_subtitle(player)) {
12700 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12701 if (mmf_attrs_commit(player->attrs)) {
12702 LOGE("failed to commit");
12703 return MM_ERROR_PLAYER_INTERNAL;
12706 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12707 LOGE("fail to create text pipeline");
12708 return MM_ERROR_PLAYER_INTERNAL;
12711 result = _mmplayer_sync_subtitle_pipeline(player);
12713 result = __mmplayer_change_external_subtitle_language(player, filepath);
12716 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12717 player->is_external_subtitle_added_now = TRUE;
12719 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12720 if (!player->subtitle_language_list) {
12721 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12722 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12723 LOGW("subtitle language list is not updated yet");
12725 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12733 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12735 int result = MM_ERROR_NONE;
12736 gchar* change_pad_name = NULL;
12737 GstPad* sinkpad = NULL;
12738 MMPlayerGstElement* mainbin = NULL;
12739 enum MainElementID elemId = MMPLAYER_M_NUM;
12740 GstCaps* caps = NULL;
12741 gint total_track_num = 0;
12745 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12746 MM_ERROR_PLAYER_NOT_INITIALIZED);
12748 LOGD("Change Track(%d) to %d\n", type, index);
12750 mainbin = player->pipeline->mainbin;
12752 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12753 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12754 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12755 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12757 /* Changing Video Track is not supported. */
12758 LOGE("Track Type Error\n");
12762 if (mainbin[elemId].gst == NULL) {
12763 result = MM_ERROR_PLAYER_NO_OP;
12764 LOGD("Req track doesn't exist\n");
12768 total_track_num = player->selector[type].total_track_num;
12769 if (total_track_num <= 0) {
12770 result = MM_ERROR_PLAYER_NO_OP;
12771 LOGD("Language list is not available \n");
12775 if ((index < 0) || (index >= total_track_num)) {
12776 result = MM_ERROR_INVALID_ARGUMENT;
12777 LOGD("Not a proper index : %d \n", index);
12781 /*To get the new pad from the selector*/
12782 change_pad_name = g_strdup_printf("sink_%u", index);
12783 if (change_pad_name == NULL) {
12784 result = MM_ERROR_PLAYER_INTERNAL;
12785 LOGD("Pad does not exists\n");
12789 LOGD("new active pad name: %s\n", change_pad_name);
12791 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12792 if (sinkpad == NULL) {
12793 LOGD("sinkpad is NULL");
12794 result = MM_ERROR_PLAYER_INTERNAL;
12798 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12799 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12801 caps = gst_pad_get_current_caps(sinkpad);
12802 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12805 gst_object_unref(sinkpad);
12807 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12808 __mmplayer_set_audio_attrs(player, caps);
12812 MMPLAYER_FREEIF(change_pad_name);
12816 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12818 int result = MM_ERROR_NONE;
12819 mm_player_t* player = NULL;
12820 MMPlayerGstElement* mainbin = NULL;
12822 gint current_active_index = 0;
12824 GstState current_state = GST_STATE_VOID_PENDING;
12825 GstEvent* event = NULL;
12830 player = (mm_player_t*)hplayer;
12831 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12833 if (!player->pipeline) {
12834 LOGE("Track %d pre setting -> %d\n", type, index);
12836 player->selector[type].active_pad_index = index;
12840 mainbin = player->pipeline->mainbin;
12842 current_active_index = player->selector[type].active_pad_index;
12844 /*If index is same as running index no need to change the pad*/
12845 if (current_active_index == index)
12848 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12849 result = MM_ERROR_PLAYER_INVALID_STATE;
12853 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12854 if (current_state < GST_STATE_PAUSED) {
12855 result = MM_ERROR_PLAYER_INVALID_STATE;
12856 LOGW("Pipeline not in porper state\n");
12860 result = __mmplayer_change_selector_pad(player, type, index);
12861 if (result != MM_ERROR_NONE) {
12862 LOGE("change selector pad error\n");
12866 player->selector[type].active_pad_index = index;
12868 if (current_state == GST_STATE_PLAYING) {
12869 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);
12871 __gst_send_event_to_sink(player, event);
12873 result = MM_ERROR_PLAYER_INTERNAL;
12882 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12884 mm_player_t* player = (mm_player_t*) hplayer;
12888 /* check player handle */
12889 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12891 *silent = player->set_mode.subtitle_off;
12893 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12897 return MM_ERROR_NONE;
12901 __is_ms_buff_src(mm_player_t* player)
12903 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12905 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12909 __has_suffix(mm_player_t* player, const gchar* suffix)
12911 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12912 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12914 gboolean ret = FALSE;
12915 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12916 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12918 if (g_str_has_suffix(player->profile.uri, suffix))
12921 MMPLAYER_FREEIF(t_url);
12922 MMPLAYER_FREEIF(t_suffix);
12928 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12930 mm_player_t* player = (mm_player_t*) hplayer;
12932 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12934 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12935 MMPLAYER_PRINT_STATE(player);
12936 LOGE("wrong-state : can't set the download mode to parse");
12937 return MM_ERROR_PLAYER_INVALID_STATE;
12940 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12941 player->video_hub_download_mode = mode;
12943 return MM_ERROR_NONE;
12947 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12949 mm_player_t* player = (mm_player_t*) hplayer;
12951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12953 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12954 player->sync_handler = enable;
12956 return MM_ERROR_NONE;
12960 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12961 gint64 video_time, gint64 media_clock, gint64 audio_time)
12963 mm_player_t* player = (mm_player_t*) hplayer;
12964 MMPlayerGstElement* mainbin = NULL;
12965 GstClockTime start_time_audio = 0, start_time_video = 0;
12966 GstClockTimeDiff base_time = 0, new_base_time = 0;
12967 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12968 gint64 api_delta = 0;
12969 gint64 position = 0, position_delta = 0;
12970 gint64 adj_base_time = 0;
12971 GstClock *curr_clock = NULL;
12972 GstClockTime curr_time = 0;
12973 gboolean query_ret = TRUE;
12974 int result = MM_ERROR_NONE;
12978 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12979 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12980 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12982 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12983 clock, clock_delta, video_time, media_clock, audio_time); */
12985 if ((video_time < 0) || (player->doing_seek)) {
12986 LOGD("skip setting master clock. %lld", video_time);
12990 mainbin = player->pipeline->mainbin;
12992 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12993 curr_time = gst_clock_get_time(curr_clock);
12995 current_state = MMPLAYER_CURRENT_STATE(player);
12997 if (current_state == MM_PLAYER_STATE_PLAYING)
12998 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13000 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13002 position = player->last_position;
13003 LOGD("query fail. %"G_GINT64_FORMAT, position);
13006 clock *= GST_USECOND;
13007 clock_delta *= GST_USECOND;
13009 api_delta = clock - curr_time;
13010 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13011 player->video_share_api_delta = api_delta;
13013 clock_delta += (api_delta - player->video_share_api_delta);
13015 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13016 player->video_share_clock_delta = (gint64)clock_delta;
13018 position_delta = (position/GST_USECOND) - video_time;
13019 position_delta *= GST_USECOND;
13021 adj_base_time = position_delta;
13022 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13025 gint64 new_play_time = 0;
13026 gint64 network_delay = 0;
13028 video_time *= GST_USECOND;
13030 network_delay = clock_delta - player->video_share_clock_delta;
13031 new_play_time = video_time + network_delay;
13033 adj_base_time = position - new_play_time;
13035 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13036 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13037 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13040 /* Adjust Current Stream Time with base_time of sink
13041 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13042 * 2. Set new base time
13043 * if adj_base_time is positive value, the stream time will be decreased.
13044 * 3. If seek event is occurred, the start time will be reset. */
13045 if ((player->pipeline->audiobin) &&
13046 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13047 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13049 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13050 LOGD("audio sink : gst_element_set_start_time -> NONE");
13051 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13054 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13057 if ((player->pipeline->videobin) &&
13058 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13059 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13061 if (start_time_video != GST_CLOCK_TIME_NONE) {
13062 LOGD("video sink : gst_element_set_start_time -> NONE");
13063 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13066 // if videobin exist, get base_time from videobin.
13067 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13070 new_base_time = base_time + adj_base_time;
13072 if ((player->pipeline->audiobin) &&
13073 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13074 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13076 if ((player->pipeline->videobin) &&
13077 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13078 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13087 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13089 mm_player_t* player = (mm_player_t*) hplayer;
13090 MMPlayerGstElement* mainbin = NULL;
13091 GstClock *curr_clock = NULL;
13092 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13093 gint64 position = 0;
13094 gboolean query_ret = TRUE;
13098 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13099 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13100 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13102 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13103 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13104 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13106 mainbin = player->pipeline->mainbin;
13108 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13110 current_state = MMPLAYER_CURRENT_STATE(player);
13112 if (current_state != MM_PLAYER_STATE_PAUSED)
13113 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13115 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13117 position = player->last_position;
13119 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13121 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13124 gst_object_unref(curr_clock);
13128 return MM_ERROR_NONE;
13132 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13134 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13135 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13137 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13138 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13142 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13143 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13144 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13145 mm_player_dump_t *dump_s;
13146 dump_s = g_malloc(sizeof(mm_player_dump_t));
13148 if (dump_s == NULL) {
13149 LOGE("malloc fail");
13153 dump_s->dump_element_file = NULL;
13154 dump_s->dump_pad = NULL;
13155 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13157 if (dump_s->dump_pad) {
13158 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13159 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]);
13160 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13161 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);
13162 /* add list for removed buffer probe and close FILE */
13163 player->dump_list = g_list_append(player->dump_list, dump_s);
13164 LOGD("%s sink pad added buffer probe for dump", factory_name);
13169 LOGE("failed to get %s sink pad added", factory_name);
13178 static GstPadProbeReturn
13179 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13181 FILE *dump_data = (FILE *) u_data;
13182 // int written = 0;
13183 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13184 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13186 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13188 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13190 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13192 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13194 return GST_PAD_PROBE_OK;
13198 __mmplayer_release_dump_list(GList *dump_list)
13201 GList *d_list = dump_list;
13202 for (; d_list; d_list = g_list_next(d_list)) {
13203 mm_player_dump_t *dump_s = d_list->data;
13204 if (dump_s->dump_pad) {
13205 if (dump_s->probe_handle_id)
13206 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13208 if (dump_s->dump_element_file) {
13209 fclose(dump_s->dump_element_file);
13210 dump_s->dump_element_file = NULL;
13212 MMPLAYER_FREEIF(dump_s);
13214 g_list_free(dump_list);
13220 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13222 mm_player_t* player = (mm_player_t*) hplayer;
13226 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13227 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13229 *exist = player->has_closed_caption;
13233 return MM_ERROR_NONE;
13236 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13240 // LOGD("unref internal gst buffer %p", buffer);
13241 gst_buffer_unref((GstBuffer *)buffer);
13248 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13250 mm_player_t *player = (mm_player_t*)user_data;
13251 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13252 guint64 current_level_bytes = 0;
13254 MMPLAYER_RETURN_IF_FAIL(player);
13256 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13258 LOGI("app-src: feed audio(%llu)", current_level_bytes);
13259 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13261 if (player->media_stream_buffer_status_cb[type])
13262 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13263 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13268 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13270 mm_player_t *player = (mm_player_t*)user_data;
13271 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13272 guint64 current_level_bytes = 0;
13274 MMPLAYER_RETURN_IF_FAIL(player);
13276 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13278 LOGI("app-src: feed video(%llu)", current_level_bytes);
13280 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13281 if (player->media_stream_buffer_status_cb[type])
13282 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13283 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13287 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13289 mm_player_t *player = (mm_player_t*)user_data;
13290 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13291 guint64 current_level_bytes = 0;
13293 MMPLAYER_RETURN_IF_FAIL(player);
13295 LOGI("app-src: feed subtitle");
13297 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13299 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13300 if (player->media_stream_buffer_status_cb[type])
13301 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13303 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13307 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13309 mm_player_t *player = (mm_player_t*)user_data;
13310 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13311 guint64 current_level_bytes = 0;
13313 MMPLAYER_RETURN_IF_FAIL(player);
13315 LOGI("app-src: audio buffer is full");
13317 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13319 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13321 if (player->media_stream_buffer_status_cb[type])
13322 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13324 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13328 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13330 mm_player_t *player = (mm_player_t*)user_data;
13331 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13332 guint64 current_level_bytes = 0;
13334 MMPLAYER_RETURN_IF_FAIL(player);
13336 LOGI("app-src: video buffer is full");
13338 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13340 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13341 if (player->media_stream_buffer_status_cb[type])
13342 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13344 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13348 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13350 mm_player_t *player = (mm_player_t*)user_data;
13351 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13353 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13355 LOGD("app-src: seek audio data %llu", position);
13356 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13358 if (player->media_stream_seek_data_cb[type])
13359 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13360 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13366 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13368 mm_player_t *player = (mm_player_t*)user_data;
13369 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13371 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13373 LOGD("app-src: seek video data %llu", position);
13374 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13375 if (player->media_stream_seek_data_cb[type])
13376 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13377 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13383 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13385 mm_player_t *player = (mm_player_t*)user_data;
13386 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13388 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13390 LOGD("app-src: seek subtitle data");
13391 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13393 if (player->media_stream_seek_data_cb[type])
13394 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13395 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13401 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13403 mm_player_t* player = (mm_player_t*) hplayer;
13407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13409 player->pcm_samplerate = samplerate;
13410 player->pcm_channel = channel;
13413 return MM_ERROR_NONE;
13416 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13418 mm_player_t* player = (mm_player_t*) hplayer;
13422 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13423 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13425 if (MMPLAYER_IS_STREAMING(player))
13426 *timeout = player->ini.live_state_change_timeout;
13428 *timeout = player->ini.localplayback_state_change_timeout;
13430 LOGD("timeout = %d\n", *timeout);
13433 return MM_ERROR_NONE;
13436 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13438 mm_player_t* player = (mm_player_t*) hplayer;
13442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13443 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13445 *num = player->video_num_buffers;
13446 *extra_num = player->video_extra_num_buffers;
13448 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13451 return MM_ERROR_NONE;
13455 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13459 MMPLAYER_RETURN_IF_FAIL(player);
13461 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13463 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13464 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13465 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13466 player->storage_info[i].id = -1;
13467 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13469 if (path_type != MMPLAYER_PATH_MAX)
13477 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13479 int ret = MM_ERROR_NONE;
13480 mm_player_t* player = (mm_player_t*)hplayer;
13481 MMMessageParamType msg_param = {0, };
13484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13486 LOGW("state changed storage %d:%d", id, state);
13488 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13489 return MM_ERROR_NONE;
13491 /* FIXME: text path should be handled seperately. */
13492 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13493 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13494 LOGW("external storage is removed");
13496 if (player->msg_posted == FALSE) {
13497 memset(&msg_param, 0, sizeof(MMMessageParamType));
13498 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13499 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13500 player->msg_posted = TRUE;
13503 /* unrealize the player */
13504 ret = _mmplayer_unrealize(hplayer);
13505 if (ret != MM_ERROR_NONE)
13506 LOGE("failed to unrealize");
13513 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13515 int ret = MM_ERROR_NONE;
13516 mm_player_t* player = (mm_player_t*) hplayer;
13517 int idx = 0, total = 0;
13518 gchar *result = NULL, *tmp = NULL;
13521 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13522 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13524 total = *num = g_list_length(player->adaptive_info.var_list);
13526 LOGW("There is no stream variant info.");
13530 result = g_strdup("");
13531 for (idx = 0 ; idx < total ; idx++) {
13532 VariantData *v_data = NULL;
13533 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13536 gchar data[64] = {0};
13537 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13539 tmp = g_strconcat(result, data, NULL);
13543 LOGW("There is no variant data in %d", idx);
13548 *var_info = (char *)result;
13550 LOGD("variant info %d:%s", *num, *var_info);
13555 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13557 int ret = MM_ERROR_NONE;
13558 mm_player_t* player = (mm_player_t*) hplayer;
13561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13563 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13565 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13566 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13567 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13569 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13570 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13571 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13572 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13574 /* FIXME: seek to current position for applying new variant limitation */
13582 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13584 int ret = MM_ERROR_NONE;
13585 mm_player_t* player = (mm_player_t*) hplayer;
13588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13589 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13591 *bandwidth = player->adaptive_info.limit.bandwidth;
13592 *width = player->adaptive_info.limit.width;
13593 *height = player->adaptive_info.limit.height;
13595 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13601 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13603 int ret = MM_ERROR_NONE;
13604 mm_player_t* player = (mm_player_t*) hplayer;
13607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13609 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13610 LOGW("buffer_ms will not be applied.");
13613 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13615 if (player->streamer == NULL) {
13616 player->streamer = __mm_player_streaming_create();
13617 __mm_player_streaming_initialize(player->streamer);
13620 if (buffer_ms >= 0)
13621 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13623 if (rebuffer_ms >= 0)
13624 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13631 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13633 int ret = MM_ERROR_NONE;
13634 mm_player_t* player = (mm_player_t*) hplayer;
13637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13638 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13640 if (player->streamer == NULL) {
13641 player->streamer = __mm_player_streaming_create();
13642 __mm_player_streaming_initialize(player->streamer);
13645 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13646 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13648 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13654 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13656 #define IDX_FIRST_SW_CODEC 0
13657 mm_player_t* player = (mm_player_t*) hplayer;
13658 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13659 MMHandleType attrs = 0;
13662 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13664 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13665 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13666 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13668 switch (stream_type) {
13669 case MM_PLAYER_STREAM_TYPE_AUDIO:
13670 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13671 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13672 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13673 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13674 LOGE("There is no a codec for codec_type %d", codec_type);
13675 return MM_ERROR_PLAYER_NO_OP;
13678 case MM_PLAYER_STREAM_TYPE_VIDEO:
13679 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13680 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13681 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13682 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13683 LOGE("There is no v codec for codec_type %d", codec_type);
13684 return MM_ERROR_PLAYER_NO_OP;
13689 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
13690 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13694 LOGD("update %s codec_type to %d", attr_name, codec_type);
13696 attrs = MMPLAYER_GET_ATTRS(player);
13697 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13699 if (mmf_attrs_commit(player->attrs)) {
13700 LOGE("failed to commit codec_type attributes");
13701 return MM_ERROR_PLAYER_INTERNAL;
13705 return MM_ERROR_NONE;
13709 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13711 mm_player_t* player = (mm_player_t*) hplayer;
13712 GstElement* rg_vol_element = NULL;
13716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13718 player->sound.rg_enable = enabled;
13720 /* just hold rgvolume enable value if pipeline is not ready */
13721 if (!player->pipeline || !player->pipeline->audiobin) {
13722 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13723 return MM_ERROR_NONE;
13726 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13728 if (!rg_vol_element) {
13729 LOGD("rgvolume element is not created");
13730 return MM_ERROR_PLAYER_INTERNAL;
13734 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13736 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13740 return MM_ERROR_NONE;
13744 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13746 mm_player_t* player = (mm_player_t*) hplayer;
13747 GstElement* rg_vol_element = NULL;
13748 gboolean enable = FALSE;
13752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13753 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13755 /* just hold enable_rg value if pipeline is not ready */
13756 if (!player->pipeline || !player->pipeline->audiobin) {
13757 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13758 *enabled = player->sound.rg_enable;
13759 return MM_ERROR_NONE;
13762 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13764 if (!rg_vol_element) {
13765 LOGD("rgvolume element is not created");
13766 return MM_ERROR_PLAYER_INTERNAL;
13769 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13774 return MM_ERROR_NONE;