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_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
105 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
107 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
108 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
109 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
110 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
112 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
113 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
115 /*---------------------------------------------------------------------------
116 | LOCAL CONSTANT DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
119 /*---------------------------------------------------------------------------
120 | LOCAL DATA TYPE DEFINITIONS: |
121 ---------------------------------------------------------------------------*/
123 /*---------------------------------------------------------------------------
124 | GLOBAL VARIABLE DEFINITIONS: |
125 ---------------------------------------------------------------------------*/
127 /*---------------------------------------------------------------------------
128 | LOCAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
130 static sound_stream_info_h stream_info;
132 /*---------------------------------------------------------------------------
133 | LOCAL FUNCTION PROTOTYPES: |
134 ---------------------------------------------------------------------------*/
135 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
138 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
140 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
141 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
143 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
144 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
146 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
149 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
150 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
151 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
152 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
153 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
154 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
155 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
156 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
157 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
158 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
159 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
161 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
162 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
163 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
164 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
165 static void __mmplayer_release_misc(mm_player_t* player);
166 static void __mmplayer_release_misc_post(mm_player_t* player);
167 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
168 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
169 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
170 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
171 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
172 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
173 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
175 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
176 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
177 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
179 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
180 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
181 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
182 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
183 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
184 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
185 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
186 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
187 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
188 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
189 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
190 static gpointer __mmplayer_next_play_thread(gpointer data);
191 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
193 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
194 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
195 static void __mmplayer_release_dump_list(GList *dump_list);
197 static int __gst_realize(mm_player_t* player);
198 static int __gst_unrealize(mm_player_t* player);
199 static int __gst_start(mm_player_t* player);
200 static int __gst_stop(mm_player_t* player);
201 static int __gst_pause(mm_player_t* player, gboolean async);
202 static int __gst_resume(mm_player_t* player, gboolean async);
203 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
204 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
205 gint64 cur, GstSeekType stop_type, gint64 stop);
206 static int __gst_pending_seek(mm_player_t* player);
208 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
209 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
210 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
211 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
212 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
214 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
216 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
217 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
220 static gboolean __is_ms_buff_src(mm_player_t* player);
221 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
223 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
224 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
225 static int __mmplayer_start_streaming_ext(mm_player_t *player);
226 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
227 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
229 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
230 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
231 static void __mmplayer_check_pipeline(mm_player_t* player);
232 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
233 static void __mmplayer_deactivate_old_path(mm_player_t *player);
235 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
236 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
238 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
239 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
240 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
241 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
242 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
243 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
244 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
245 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
246 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
247 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
248 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
249 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
250 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
251 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
252 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
253 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
255 /*===========================================================================================
257 | FUNCTION DEFINITIONS |
259 ========================================================================================== */
263 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
267 count = gst_tag_list_get_tag_size(list, tag);
269 LOGD("count = %d", count);
271 for (i = 0; i < count; i++) {
274 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
275 if (!gst_tag_list_get_string_index(list, tag, i, &str))
276 g_assert_not_reached();
278 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
281 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
283 g_print(" : %s\n", str);
290 /* This function should be called after the pipeline goes PAUSED or higher
293 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
295 static gboolean has_duration = FALSE;
296 static gboolean has_video_attrs = FALSE;
297 static gboolean has_audio_attrs = FALSE;
298 static gboolean has_bitrate = FALSE;
299 gboolean missing_only = FALSE;
300 gboolean all = FALSE;
302 GstStructure* p = NULL;
303 MMHandleType attrs = 0;
309 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
311 /* check player state here */
312 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
313 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
314 /* give warning now only */
315 LOGW("be careful. content attributes may not available in this state ");
318 /* get content attribute first */
319 attrs = MMPLAYER_GET_ATTRS(player);
321 LOGE("cannot get content attribute");
325 /* get update flag */
327 if (flag & ATTR_MISSING_ONLY) {
329 LOGD("updating missed attr only");
332 if (flag & ATTR_ALL) {
334 has_duration = FALSE;
335 has_video_attrs = FALSE;
336 has_audio_attrs = FALSE;
339 LOGD("updating all attrs");
342 if (missing_only && all) {
343 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
344 missing_only = FALSE;
347 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
348 LOGD("try to update duration");
349 has_duration = FALSE;
351 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
352 player->duration = dur_nsec;
353 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
356 if (player->duration < 0) {
357 LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
358 player->duration = 0;
361 /* update streaming service type */
362 player->streaming_type = __mmplayer_get_stream_service_type(player);
364 /* check duration is OK */
365 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
366 /* FIXIT : find another way to get duration here. */
367 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
370 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
375 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
376 /* update audio params
377 NOTE : We need original audio params and it can be only obtained from src pad of audio
378 decoder. Below code only valid when we are not using 'resampler' just before
381 LOGD("try to update audio attrs");
382 has_audio_attrs = FALSE;
384 if (player->pipeline->audiobin &&
385 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
386 GstCaps *caps_a = NULL;
388 gint samplerate = 0, channels = 0;
390 pad = gst_element_get_static_pad(
391 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
394 caps_a = gst_pad_get_current_caps(pad);
397 p = gst_caps_get_structure(caps_a, 0);
399 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
401 gst_structure_get_int(p, "rate", &samplerate);
402 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
404 gst_structure_get_int(p, "channels", &channels);
405 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
407 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
409 gst_caps_unref(caps_a);
412 has_audio_attrs = TRUE;
414 LOGW("not ready to get audio caps");
416 gst_object_unref(pad);
418 LOGW("failed to get pad from audiosink");
422 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
423 LOGD("try to update video attrs");
424 has_video_attrs = FALSE;
426 if (player->pipeline->videobin &&
427 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
428 GstCaps *caps_v = NULL;
433 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
435 caps_v = gst_pad_get_current_caps(pad);
437 /* Use v_stream_caps, if fail to get video_sink sink pad*/
438 if (!caps_v && player->v_stream_caps) {
439 caps_v = player->v_stream_caps;
440 gst_caps_ref(caps_v);
444 p = gst_caps_get_structure(caps_v, 0);
445 gst_structure_get_int(p, "width", &width);
446 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
448 gst_structure_get_int(p, "height", &height);
449 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
451 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
453 SECURE_LOGD("width : %d height : %d", width, height);
455 gst_caps_unref(caps_v);
459 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
460 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
463 has_video_attrs = TRUE;
465 LOGD("no negitiated caps from videosink");
466 gst_object_unref(pad);
469 LOGD("no videosink sink pad");
474 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
477 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
478 if (player->duration) {
479 guint64 data_size = 0;
481 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
482 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
484 if (stat(path, &sb) == 0)
485 data_size = (guint64)sb.st_size;
486 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
487 data_size = player->http_content_size;
489 LOGD("try to update bitrate : data_size = %lld", data_size);
493 guint64 msec_dur = 0;
495 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
497 bitrate = data_size * 8 * 1000 / msec_dur;
498 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
499 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
503 LOGD("player duration is less than 0");
507 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
508 if (player->total_bitrate) {
509 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
517 if (mmf_attrs_commit(attrs)) {
518 LOGE("failed to update attributes\n");
527 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
529 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
533 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
535 player->pipeline->mainbin &&
536 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
537 STREAMING_SERVICE_NONE);
539 /* streaming service type if streaming */
540 if (!MMPLAYER_IS_STREAMING(player))
541 return STREAMING_SERVICE_NONE;
543 if (MMPLAYER_IS_HTTP_STREAMING(player))
544 streaming_type = (player->duration == 0) ?
545 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
547 switch (streaming_type) {
548 case STREAMING_SERVICE_LIVE:
549 LOGD("it's live streaming");
551 case STREAMING_SERVICE_VOD:
552 LOGD("it's vod streaming");
555 LOGE("should not get here");
561 return streaming_type;
565 /* this function sets the player state and also report
566 * it to applicaton by calling callback function
569 __mmplayer_set_state(mm_player_t* player, int state)
571 MMMessageParamType msg = {0, };
572 gboolean post_bos = FALSE;
574 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
576 if (MMPLAYER_CURRENT_STATE(player) == state) {
577 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
578 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
579 return MM_ERROR_NONE;
582 /* update player states */
583 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
584 MMPLAYER_CURRENT_STATE(player) = state;
586 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
587 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
590 MMPLAYER_PRINT_STATE(player);
592 switch (MMPLAYER_CURRENT_STATE(player)) {
593 case MM_PLAYER_STATE_NULL:
594 case MM_PLAYER_STATE_READY:
597 case MM_PLAYER_STATE_PAUSED:
599 if (!player->sent_bos) {
600 /* rtsp case, get content attrs by GstMessage */
601 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
602 /* it's first time to update all content attrs. */
603 _mmplayer_update_content_attrs(player, ATTR_ALL);
607 /* add audio callback probe if condition is satisfied */
608 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
609 __mmplayer_configure_audio_callback(player);
611 /* FIXIT : handle return value */
615 case MM_PLAYER_STATE_PLAYING:
617 /* try to get content metadata */
618 if (!player->sent_bos) {
619 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
620 * c-api since c-api doesn't use _start() anymore. It may not work propery with
621 * legacy mmfw-player api */
622 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
625 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
626 if (!player->sent_bos)
627 __mmplayer_handle_missed_plugin(player);
630 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
631 /* initialize because auto resume is done well. */
632 player->resumed_by_rewind = FALSE;
633 player->playback_rate = 1.0;
636 if (!player->sent_bos) {
637 /* check audio codec field is set or not
638 * we can get it from typefinder or codec's caps.
640 gchar *audio_codec = NULL;
641 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
643 /* The codec format can't be sent for audio only case like amr, mid etc.
644 * Because, parser don't make related TAG.
645 * So, if it's not set yet, fill it with found data.
648 if (g_strrstr(player->type, "audio/midi"))
649 audio_codec = g_strdup("MIDI");
650 else if (g_strrstr(player->type, "audio/x-amr"))
651 audio_codec = g_strdup("AMR");
652 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
653 audio_codec = g_strdup("AAC");
655 audio_codec = g_strdup("unknown");
656 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
658 MMPLAYER_FREEIF(audio_codec);
659 if (mmf_attrs_commit(player->attrs))
660 LOGE("failed to update attributes\n");
662 LOGD("set audio codec type with caps\n");
670 case MM_PLAYER_STATE_NONE:
672 LOGW("invalid target state, there is nothing to do.\n");
677 /* post message to application */
678 if (MMPLAYER_TARGET_STATE(player) == state) {
679 /* fill the message with state of player */
680 msg.union_type = MM_MSG_UNION_STATE;
681 msg.state.previous = MMPLAYER_PREV_STATE(player);
682 msg.state.current = MMPLAYER_CURRENT_STATE(player);
684 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
686 /* state changed by resource callback */
687 if (player->interrupted_by_resource) {
688 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
689 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
690 } else { /* state changed by usecase */
691 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
694 LOGD("intermediate state, do nothing.\n");
695 MMPLAYER_PRINT_STATE(player);
696 return MM_ERROR_NONE;
700 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
701 player->sent_bos = TRUE;
704 return MM_ERROR_NONE;
707 static gpointer __mmplayer_next_play_thread(gpointer data)
709 mm_player_t* player = (mm_player_t*) data;
710 MMPlayerGstElement *mainbin = NULL;
712 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
714 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
715 while (!player->next_play_thread_exit) {
716 LOGD("next play thread started. waiting for signal.\n");
717 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
719 LOGD("reconfigure pipeline for gapless play.\n");
721 if (player->next_play_thread_exit) {
722 if (player->gapless.reconfigure) {
723 player->gapless.reconfigure = false;
724 MMPLAYER_PLAYBACK_UNLOCK(player);
726 LOGD("exiting gapless play thread\n");
730 mainbin = player->pipeline->mainbin;
732 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
733 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
734 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
735 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
736 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
738 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
740 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
746 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
748 MMHandleType attrs = 0;
749 guint64 data_size = 0;
751 unsigned long pos_msec = 0;
754 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
756 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
758 attrs = MMPLAYER_GET_ATTRS(player);
760 LOGE("fail to get attributes.\n");
764 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
765 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
767 if (stat(path, &sb) == 0)
768 data_size = (guint64)sb.st_size;
769 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
770 data_size = player->http_content_size;
772 __mm_player_streaming_buffering(player->streamer,
775 player->last_position,
778 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
784 __mmplayer_handle_buffering_message(mm_player_t* player)
786 int ret = MM_ERROR_NONE;
787 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
788 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
789 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
790 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
792 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
793 LOGW("do nothing for buffering msg\n");
794 ret = MM_ERROR_PLAYER_INVALID_STATE;
798 prev_state = MMPLAYER_PREV_STATE(player);
799 current_state = MMPLAYER_CURRENT_STATE(player);
800 target_state = MMPLAYER_TARGET_STATE(player);
801 pending_state = MMPLAYER_PENDING_STATE(player);
803 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
804 MMPLAYER_STATE_GET_NAME(prev_state),
805 MMPLAYER_STATE_GET_NAME(current_state),
806 MMPLAYER_STATE_GET_NAME(pending_state),
807 MMPLAYER_STATE_GET_NAME(target_state),
808 player->streamer->is_buffering);
810 if (!player->streamer->is_buffering) {
811 /* NOTE : if buffering has done, player has to go to target state. */
812 switch (target_state) {
813 case MM_PLAYER_STATE_PAUSED:
815 switch (pending_state) {
816 case MM_PLAYER_STATE_PLAYING:
817 __gst_pause(player, TRUE);
820 case MM_PLAYER_STATE_PAUSED:
821 LOGD("player is already going to paused state, there is nothing to do.\n");
824 case MM_PLAYER_STATE_NONE:
825 case MM_PLAYER_STATE_NULL:
826 case MM_PLAYER_STATE_READY:
828 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
834 case MM_PLAYER_STATE_PLAYING:
836 switch (pending_state) {
837 case MM_PLAYER_STATE_NONE:
839 if (current_state != MM_PLAYER_STATE_PLAYING)
840 __gst_resume(player, TRUE);
844 case MM_PLAYER_STATE_PAUSED:
845 /* NOTE: It should be worked as asynchronously.
846 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
848 if (current_state == MM_PLAYER_STATE_PLAYING) {
849 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
850 * The current state should be changed to paused purposely to prevent state conflict.
852 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
854 __gst_resume(player, TRUE);
857 case MM_PLAYER_STATE_PLAYING:
858 LOGD("player is already going to playing state, there is nothing to do.\n");
861 case MM_PLAYER_STATE_NULL:
862 case MM_PLAYER_STATE_READY:
864 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
870 case MM_PLAYER_STATE_NULL:
871 case MM_PLAYER_STATE_READY:
872 case MM_PLAYER_STATE_NONE:
874 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
878 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
879 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
881 switch (pending_state) {
882 case MM_PLAYER_STATE_NONE:
884 if (current_state != MM_PLAYER_STATE_PAUSED) {
885 /* rtsp streaming pause makes rtsp server stop sending data. */
886 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
887 LOGD("set pause state during buffering\n");
888 __gst_pause(player, TRUE);
894 case MM_PLAYER_STATE_PLAYING:
895 /* rtsp streaming pause makes rtsp server stop sending data. */
896 if (!MMPLAYER_IS_RTSP_STREAMING(player))
897 __gst_pause(player, TRUE);
900 case MM_PLAYER_STATE_PAUSED:
903 case MM_PLAYER_STATE_NULL:
904 case MM_PLAYER_STATE_READY:
906 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
916 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
918 MMPlayerGstElement *textbin;
921 MMPLAYER_RETURN_IF_FAIL(player &&
923 player->pipeline->textbin);
925 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
927 textbin = player->pipeline->textbin;
930 LOGD("Drop subtitle text after getting EOS\n");
932 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
933 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
935 player->is_subtitle_force_drop = TRUE;
937 if (player->is_subtitle_force_drop == TRUE) {
938 LOGD("Enable subtitle data path without drop\n");
940 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
941 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
943 LOGD("non-connected with external display");
945 player->is_subtitle_force_drop = FALSE;
951 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
953 VariantData *var_info = NULL;
954 g_return_val_if_fail(self != NULL, NULL);
956 var_info = g_new0(VariantData, 1);
957 if (!var_info) return NULL;
958 var_info->bandwidth = self->bandwidth;
959 var_info->width = self->width;
960 var_info->height = self->height;
964 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
966 mm_player_t* player = (mm_player_t*)hplayer;
967 GstMessage *msg = NULL;
968 GQueue *queue = NULL;
971 MMPLAYER_RETURN_IF_FAIL(player);
973 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
975 /* destroy the gst bus msg thread */
976 if (player->bus_msg_thread) {
977 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
978 player->bus_msg_thread_exit = TRUE;
979 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
980 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
982 LOGD("gst bus msg thread exit.");
983 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
984 player->bus_msg_thread = NULL;
986 g_mutex_clear(&player->bus_msg_thread_mutex);
987 g_cond_clear(&player->bus_msg_thread_cond);
990 g_mutex_lock(&player->bus_msg_q_lock);
991 queue = player->bus_msg_q;
992 while (!g_queue_is_empty(queue)) {
993 msg = (GstMessage *)g_queue_pop_head(queue);
994 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
995 gst_message_unref(msg);
997 g_mutex_unlock(&player->bus_msg_q_lock);
1002 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1004 mm_player_t *player = (mm_player_t *) data;
1006 g_return_val_if_fail(player, FALSE);
1007 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1009 gst_message_ref(msg);
1011 g_mutex_lock(&player->bus_msg_q_lock);
1012 g_queue_push_tail(player->bus_msg_q, msg);
1013 g_mutex_unlock(&player->bus_msg_q_lock);
1015 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1016 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1017 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1021 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1023 mm_player_t *player = (mm_player_t*)(data);
1024 GstMessage *msg = NULL;
1028 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1030 player->pipeline->mainbin &&
1031 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1034 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1036 LOGE("cannot get BUS from the pipeline");
1040 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1042 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1043 while (!player->bus_msg_thread_exit) {
1044 g_mutex_lock(&player->bus_msg_q_lock);
1045 msg = g_queue_pop_head(player->bus_msg_q);
1046 g_mutex_unlock(&player->bus_msg_q_lock);
1048 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1051 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1052 /* handle the gst msg */
1053 __mmplayer_gst_callback(msg, player);
1054 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1055 gst_message_unref(msg);
1058 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1059 gst_object_unref(GST_OBJECT(bus));
1066 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1068 mm_player_t* player = (mm_player_t*)(data);
1069 static gboolean async_done = FALSE;
1071 MMPLAYER_RETURN_IF_FAIL(player);
1072 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1074 switch (GST_MESSAGE_TYPE(msg)) {
1075 case GST_MESSAGE_UNKNOWN:
1076 LOGD("unknown message received\n");
1079 case GST_MESSAGE_EOS:
1081 MMHandleType attrs = 0;
1084 LOGD("GST_MESSAGE_EOS received\n");
1086 /* NOTE : EOS event is comming multiple time. watch out it */
1087 /* check state. we only process EOS when pipeline state goes to PLAYING */
1088 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1089 LOGD("EOS received on non-playing state. ignoring it\n");
1093 if (player->pipeline) {
1094 if (player->pipeline->textbin)
1095 __mmplayer_drop_subtitle(player, TRUE);
1097 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1100 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1102 LOGD("release audio callback\n");
1104 /* release audio callback */
1105 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1106 player->audio_cb_probe_id = 0;
1107 /* audio callback should be free because it can be called even though probe remove.*/
1108 player->audio_stream_cb = NULL;
1109 player->audio_stream_cb_user_param = NULL;
1113 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1114 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1116 /* rewind if repeat count is greater then zero */
1117 /* get play count */
1118 attrs = MMPLAYER_GET_ATTRS(player);
1121 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1123 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1125 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1126 if (player->playback_rate < 0.0) {
1127 player->resumed_by_rewind = TRUE;
1128 _mmplayer_set_mute((MMHandleType)player, 0);
1129 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1132 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1135 player->sent_bos = FALSE;
1137 /* not posting eos when repeating */
1142 if (player->pipeline)
1143 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1145 /* post eos message to application */
1146 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1148 /* reset last position */
1149 player->last_position = 0;
1153 case GST_MESSAGE_ERROR:
1155 GError *error = NULL;
1156 gchar* debug = NULL;
1158 /* generating debug info before returning error */
1159 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1161 /* get error code */
1162 gst_message_parse_error(msg, &error, &debug);
1164 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1165 /* Note : the streaming error from the streaming source is handled
1166 * using __mmplayer_handle_streaming_error.
1168 __mmplayer_handle_streaming_error(player, msg);
1170 /* dump state of all element */
1171 __mmplayer_dump_pipeline_state(player);
1173 /* traslate gst error code to msl error code. then post it
1174 * to application if needed
1176 __mmplayer_handle_gst_error(player, msg, error);
1179 LOGE("error debug : %s", debug);
1182 if (MMPLAYER_IS_HTTP_PD(player))
1183 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1185 MMPLAYER_FREEIF(debug);
1186 g_error_free(error);
1190 case GST_MESSAGE_WARNING:
1193 GError* error = NULL;
1195 gst_message_parse_warning(msg, &error, &debug);
1197 LOGD("warning : %s\n", error->message);
1198 LOGD("debug : %s\n", debug);
1200 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1202 MMPLAYER_FREEIF(debug);
1203 g_error_free(error);
1207 case GST_MESSAGE_TAG:
1209 LOGD("GST_MESSAGE_TAG\n");
1210 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1211 LOGW("failed to extract tags from gstmessage\n");
1215 case GST_MESSAGE_BUFFERING:
1217 MMMessageParamType msg_param = {0, };
1218 int bRet = MM_ERROR_NONE;
1220 if (!(player->pipeline && player->pipeline->mainbin)) {
1221 LOGE("player pipeline handle is null");
1225 if (!MMPLAYER_IS_STREAMING(player))
1228 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1229 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1230 /* skip the playback control by buffering msg while user request is handled. */
1233 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1235 gst_message_parse_buffering(msg, &per);
1236 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1238 msg_param.connection.buffering = per;
1239 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1243 MMPLAYER_CMD_LOCK(player);
1246 /* ignore the prev buffering message */
1247 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1248 && (player->streamer->is_buffering_done == TRUE)) {
1249 gint buffer_percent = 0;
1251 gst_message_parse_buffering(msg, &buffer_percent);
1253 if (buffer_percent == MAX_BUFFER_PERCENT) {
1254 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1255 player->streamer->is_buffering_done = FALSE;
1257 MMPLAYER_CMD_UNLOCK(player);
1261 __mmplayer_update_buffer_setting(player, msg);
1263 bRet = __mmplayer_handle_buffering_message(player);
1265 if (bRet == MM_ERROR_NONE) {
1266 msg_param.connection.buffering = player->streamer->buffering_percent;
1267 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1269 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1270 player->pending_resume &&
1271 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1273 player->is_external_subtitle_added_now = FALSE;
1274 player->pending_resume = FALSE;
1275 _mmplayer_resume((MMHandleType)player);
1278 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1279 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1281 if (player->doing_seek) {
1282 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1283 player->doing_seek = FALSE;
1284 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1285 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1290 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1291 if (!player->streamer) {
1292 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1293 MMPLAYER_CMD_UNLOCK(player);
1297 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1299 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1300 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1302 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1303 msg_param.connection.buffering = player->streamer->buffering_percent;
1304 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1306 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1309 msg_param.connection.buffering = player->streamer->buffering_percent;
1310 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1313 MMPLAYER_CMD_UNLOCK(player);
1317 case GST_MESSAGE_STATE_CHANGED:
1319 MMPlayerGstElement *mainbin;
1320 const GValue *voldstate, *vnewstate, *vpending;
1321 GstState oldstate = GST_STATE_NULL;
1322 GstState newstate = GST_STATE_NULL;
1323 GstState pending = GST_STATE_NULL;
1325 if (!(player->pipeline && player->pipeline->mainbin)) {
1326 LOGE("player pipeline handle is null");
1330 mainbin = player->pipeline->mainbin;
1332 /* we only handle messages from pipeline */
1333 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1336 /* get state info from msg */
1337 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1338 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1339 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1341 if (!voldstate || !vnewstate) {
1342 LOGE("received msg has wrong format.");
1346 oldstate = (GstState)voldstate->data[0].v_int;
1347 newstate = (GstState)vnewstate->data[0].v_int;
1349 pending = (GstState)vpending->data[0].v_int;
1351 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1352 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1353 gst_element_state_get_name((GstState)oldstate),
1354 gst_element_state_get_name((GstState)newstate),
1355 gst_element_state_get_name((GstState)pending));
1357 if (newstate == GST_STATE_PLAYING) {
1358 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1360 int retVal = MM_ERROR_NONE;
1361 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1363 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1365 if (MM_ERROR_NONE != retVal)
1366 LOGE("failed to seek pending postion. just keep staying current position.\n");
1368 player->pending_seek.is_pending = FALSE;
1372 if (oldstate == newstate) {
1373 LOGD("pipeline reports state transition to old state");
1378 case GST_STATE_VOID_PENDING:
1381 case GST_STATE_NULL:
1384 case GST_STATE_READY:
1387 case GST_STATE_PAUSED:
1389 gboolean prepare_async = FALSE;
1390 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1392 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1393 __mmplayer_configure_audio_callback(player);
1395 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1396 // managed prepare async case
1397 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1398 LOGD("checking prepare mode for async transition - %d", prepare_async);
1401 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1402 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1404 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1405 __mm_player_streaming_set_content_bitrate(player->streamer,
1406 player->total_maximum_bitrate, player->total_bitrate);
1408 if (player->pending_seek.is_pending) {
1409 LOGW("trying to do pending seek");
1410 MMPLAYER_CMD_LOCK(player);
1411 __gst_pending_seek(player);
1412 MMPLAYER_CMD_UNLOCK(player);
1418 case GST_STATE_PLAYING:
1420 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1422 if (MMPLAYER_IS_STREAMING(player)) {
1423 // managed prepare async case when buffering is completed
1424 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1425 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1426 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1427 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1429 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1431 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1432 if (player->streamer->buffering_percent < 100) {
1434 MMMessageParamType msg_param = {0, };
1435 LOGW("Posting Buffering Completed Message to Application !!!");
1437 msg_param.connection.buffering = 100;
1438 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1443 if (player->gapless.stream_changed) {
1444 _mmplayer_update_content_attrs(player, ATTR_ALL);
1445 player->gapless.stream_changed = FALSE;
1448 if (player->doing_seek && async_done) {
1449 player->doing_seek = FALSE;
1451 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1462 case GST_MESSAGE_CLOCK_LOST:
1464 GstClock *clock = NULL;
1465 gboolean need_new_clock = FALSE;
1467 gst_message_parse_clock_lost(msg, &clock);
1468 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1470 if (!player->videodec_linked)
1471 need_new_clock = TRUE;
1472 else if (!player->ini.use_system_clock)
1473 need_new_clock = TRUE;
1475 if (need_new_clock) {
1476 LOGD("Provide clock is TRUE, do pause->resume\n");
1477 __gst_pause(player, FALSE);
1478 __gst_resume(player, FALSE);
1483 case GST_MESSAGE_NEW_CLOCK:
1485 GstClock *clock = NULL;
1486 gst_message_parse_new_clock(msg, &clock);
1487 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1491 case GST_MESSAGE_ELEMENT:
1493 const gchar *structure_name;
1494 gint count = 0, idx = 0;
1495 MMHandleType attrs = 0;
1497 attrs = MMPLAYER_GET_ATTRS(player);
1499 LOGE("cannot get content attribute");
1503 if (gst_message_get_structure(msg) == NULL)
1506 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1507 if (!structure_name)
1510 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1512 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1513 const GValue *var_info = NULL;
1515 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1516 if (var_info != NULL) {
1517 if (player->adaptive_info.var_list)
1518 g_list_free_full(player->adaptive_info.var_list, g_free);
1520 /* share addr or copy the list */
1521 player->adaptive_info.var_list =
1522 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1524 count = g_list_length(player->adaptive_info.var_list);
1526 VariantData *temp = NULL;
1528 /* print out for debug */
1529 LOGD("num of variant_info %d", count);
1530 for (idx = 0; idx < count; idx++) {
1531 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1533 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1539 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1540 gint num_buffers = 0;
1541 gint extra_num_buffers = 0;
1543 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1544 player->video_num_buffers = num_buffers;
1545 LOGD("video_num_buffers : %d", player->video_num_buffers);
1548 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1549 player->video_extra_num_buffers = extra_num_buffers;
1550 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1555 if (!strcmp(structure_name, "Language_list")) {
1556 const GValue *lang_list = NULL;
1557 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1558 if (lang_list != NULL) {
1559 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1561 LOGD("Total audio tracks(from parser) = %d \n", count);
1565 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1566 const GValue *lang_list = NULL;
1567 MMPlayerLangStruct *temp = NULL;
1569 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1570 if (lang_list != NULL) {
1571 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1573 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1574 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1575 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1576 if (mmf_attrs_commit(attrs))
1577 LOGE("failed to commit.\n");
1578 LOGD("Total subtitle tracks = %d \n", count);
1581 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1583 LOGD("value of lang_key is %s and lang_code is %s",
1584 temp->language_key, temp->language_code);
1587 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1588 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1593 /* custom message */
1594 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1595 MMMessageParamType msg_param = {0,};
1596 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1597 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1600 /* custom message for RTSP attribute :
1601 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1602 sdp which has contents info is received when rtsp connection is opened.
1603 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1604 if (!strcmp(structure_name, "rtspsrc_properties")) {
1606 gchar *audio_codec = NULL;
1607 gchar *video_codec = NULL;
1608 gchar *video_frame_size = NULL;
1610 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1611 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1612 player->streaming_type = __mmplayer_get_stream_service_type(player);
1613 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1615 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1616 LOGD("rtsp_audio_codec : %s", audio_codec);
1618 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1620 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1621 LOGD("rtsp_video_codec : %s", video_codec);
1623 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1625 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1626 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1627 if (video_frame_size) {
1629 char *seperator = strchr(video_frame_size, '-');
1632 char video_width[10] = {0,};
1633 int frame_size_len = strlen(video_frame_size);
1634 int separtor_len = strlen(seperator);
1636 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1637 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1640 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1644 if (mmf_attrs_commit(attrs))
1645 LOGE("failed to commit.\n");
1650 case GST_MESSAGE_DURATION_CHANGED:
1652 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1653 if (!__mmplayer_gst_handle_duration(player, msg))
1654 LOGW("failed to update duration");
1659 case GST_MESSAGE_ASYNC_START:
1660 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1663 case GST_MESSAGE_ASYNC_DONE:
1665 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1667 /* we only handle messages from pipeline */
1668 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1671 if (player->doing_seek) {
1672 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1673 player->doing_seek = FALSE;
1674 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1675 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1676 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1677 (player->streamer) &&
1678 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1679 (player->streamer->is_buffering == FALSE)) {
1680 GstQuery *query = NULL;
1681 gboolean busy = FALSE;
1684 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1685 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1686 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1687 gst_query_parse_buffering_percent(query, &busy, &percent);
1688 gst_query_unref(query);
1690 LOGD("buffered percent(%s): %d\n",
1691 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1694 if (percent >= 100) {
1695 player->streamer->is_buffering = FALSE;
1696 __mmplayer_handle_buffering_message(player);
1706 #if 0 /* delete unnecessary logs */
1707 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1708 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1709 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1710 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1711 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1712 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1713 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1714 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1715 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1716 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1717 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1718 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1719 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1720 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1721 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1728 /* should not call 'gst_message_unref(msg)' */
1733 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1739 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1740 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1742 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1743 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1744 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1746 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1747 LOGD("data total size of http content: %lld", bytes);
1748 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1751 /* handling audio clip which has vbr. means duration is keep changing */
1752 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1759 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1760 mm_player_spherical_metadata_t *metadata) {
1761 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1762 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1763 gst_tag_list_get_string(tags, "stitching_software",
1764 &metadata->stitching_software);
1765 gst_tag_list_get_string(tags, "projection_type",
1766 &metadata->projection_type_string);
1767 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1768 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1769 gst_tag_list_get_int(tags, "init_view_heading",
1770 &metadata->init_view_heading);
1771 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1772 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1773 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1774 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1775 &metadata->full_pano_width_pixels);
1776 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1777 &metadata->full_pano_height_pixels);
1778 gst_tag_list_get_int(tags, "cropped_area_image_width",
1779 &metadata->cropped_area_image_width);
1780 gst_tag_list_get_int(tags, "cropped_area_image_height",
1781 &metadata->cropped_area_image_height);
1782 gst_tag_list_get_int(tags, "cropped_area_left",
1783 &metadata->cropped_area_left);
1784 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1785 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1786 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1787 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1791 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1794 /* macro for better code readability */
1795 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1796 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1797 if (string != NULL) { \
1798 SECURE_LOGD("update tag string : %s\n", string); \
1799 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1800 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1801 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1802 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1803 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1804 g_free(new_string); \
1805 new_string = NULL; \
1807 mm_attrs_set_string_by_name(attribute, playertag, string); \
1814 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1816 GstSample *sample = NULL;\
1817 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1818 GstMapInfo info = GST_MAP_INFO_INIT;\
1819 buffer = gst_sample_get_buffer(sample);\
1820 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1821 LOGD("failed to get image data from tag");\
1822 gst_sample_unref(sample);\
1825 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1826 MMPLAYER_FREEIF(player->album_art);\
1827 player->album_art = (gchar *)g_malloc(info.size);\
1828 if (player->album_art) {\
1829 memcpy(player->album_art, info.data, info.size);\
1830 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1831 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1832 msg_param.data = (void *)player->album_art;\
1833 msg_param.size = info.size;\
1834 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1835 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1838 gst_buffer_unmap(buffer, &info);\
1839 gst_sample_unref(sample);\
1843 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1845 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1848 gchar *tag_list_str = NULL; \
1849 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1850 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1851 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1852 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1853 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1855 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1856 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1857 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1858 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1859 player->bitrate[track_type] = v_uint; \
1860 player->total_bitrate = 0; \
1861 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1862 player->total_bitrate += player->bitrate[i]; \
1863 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1864 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1865 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1866 player->maximum_bitrate[track_type] = v_uint; \
1867 player->total_maximum_bitrate = 0; \
1868 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1869 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1870 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1871 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1873 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1876 g_free(tag_list_str); \
1881 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1882 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1883 if (date != NULL) {\
1884 string = g_strdup_printf("%d", g_date_get_year(date));\
1885 mm_attrs_set_string_by_name(attribute, playertag, string);\
1886 SECURE_LOGD("metainfo year : %s\n", string);\
1887 MMPLAYER_FREEIF(string);\
1892 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1893 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1894 if (datetime != NULL) {\
1895 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1896 mm_attrs_set_string_by_name(attribute, playertag, string);\
1897 SECURE_LOGD("metainfo year : %s\n", string);\
1898 MMPLAYER_FREEIF(string);\
1899 gst_date_time_unref(datetime);\
1903 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1904 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1906 /* FIXIT : don't know how to store date */\
1912 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1913 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1915 /* FIXIT : don't know how to store date */\
1921 /* function start */
1922 GstTagList* tag_list = NULL;
1924 MMHandleType attrs = 0;
1926 char *string = NULL;
1929 GstDateTime *datetime = NULL;
1931 GstBuffer *buffer = NULL;
1933 MMMessageParamType msg_param = {0, };
1935 /* currently not used. but those are needed for above macro */
1936 //guint64 v_uint64 = 0;
1937 //gdouble v_double = 0;
1939 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1941 attrs = MMPLAYER_GET_ATTRS(player);
1943 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1945 /* get tag list from gst message */
1946 gst_message_parse_tag(msg, &tag_list);
1948 /* store tags to player attributes */
1949 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1950 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1951 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1952 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1953 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1954 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1955 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1956 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1957 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1958 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1959 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1960 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1961 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1962 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1963 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1964 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1965 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1966 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1967 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1969 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1970 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1971 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1972 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1973 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1974 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1975 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1976 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1977 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1978 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1979 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1980 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1981 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1982 MMPLAYER_UPDATE_TAG_LOCK(player);
1983 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1984 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1985 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1991 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1992 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1993 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1994 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1995 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1996 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1997 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1999 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
2000 if (player->video360_metadata.is_spherical == -1) {
2001 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
2002 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2003 player->video360_metadata.is_spherical);
2004 if (player->video360_metadata.is_spherical == 1) {
2005 LOGD("This is spherical content for 360 playback.");
2006 player->is_content_spherical = TRUE;
2008 LOGD("This is not spherical content");
2009 player->is_content_spherical = FALSE;
2012 if (player->video360_metadata.projection_type_string) {
2013 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2014 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2016 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2017 player->is_content_spherical = player->is_video360_enabled = FALSE;
2021 if (player->video360_metadata.stereo_mode_string) {
2022 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2023 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2024 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2025 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2026 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2027 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2029 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2030 player->is_content_spherical = player->is_video360_enabled = FALSE;
2036 if (mmf_attrs_commit(attrs))
2037 LOGE("failed to commit.\n");
2039 gst_tag_list_free(tag_list);
2045 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2047 mm_player_t* player = (mm_player_t*) data;
2051 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2052 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2053 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2054 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2056 * [1] audio and video will be dumped with filesink.
2057 * [2] autoplugging is done by just using pad caps.
2058 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2059 * and the video will be dumped via filesink.
2061 if (player->num_dynamic_pad == 0) {
2062 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2064 if (!__mmplayer_gst_remove_fakesink(player,
2065 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2066 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2067 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2068 * source element are not same. To overcome this situation, this function will called
2069 * several places and several times. Therefore, this is not an error case.
2074 /* create dot before error-return. for debugging */
2075 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2077 player->no_more_pad = TRUE;
2083 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2085 GstElement* parent = NULL;
2087 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2089 /* if we have no fakesink. this meas we are using decodebin which doesn'
2090 t need to add extra fakesink */
2091 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2094 MMPLAYER_FSINK_LOCK(player);
2099 /* get parent of fakesink */
2100 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2102 LOGD("fakesink already removed\n");
2106 gst_element_set_locked_state(fakesink->gst, TRUE);
2108 /* setting the state to NULL never returns async
2109 * so no need to wait for completion of state transiton
2111 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2112 LOGE("fakesink state change failure!\n");
2113 /* FIXIT : should I return here? or try to proceed to next? */
2116 /* remove fakesink from it's parent */
2117 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2118 LOGE("failed to remove fakesink\n");
2120 gst_object_unref(parent);
2125 gst_object_unref(parent);
2127 LOGD("state-holder removed\n");
2129 gst_element_set_locked_state(fakesink->gst, FALSE);
2131 MMPLAYER_FSINK_UNLOCK(player);
2136 gst_element_set_locked_state(fakesink->gst, FALSE);
2138 MMPLAYER_FSINK_UNLOCK(player);
2144 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2146 GstPad *sinkpad = NULL;
2147 GstCaps* caps = NULL;
2148 GstElement* new_element = NULL;
2149 GstStructure* str = NULL;
2150 const gchar* name = NULL;
2152 mm_player_t* player = (mm_player_t*) data;
2156 MMPLAYER_RETURN_IF_FAIL(element && pad);
2157 MMPLAYER_RETURN_IF_FAIL(player &&
2159 player->pipeline->mainbin);
2162 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2163 * num_dynamic_pad will decreased after creating a sinkbin.
2165 player->num_dynamic_pad++;
2166 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2168 caps = gst_pad_query_caps(pad, NULL);
2170 MMPLAYER_CHECK_NULL(caps);
2172 /* clear previous result*/
2173 player->have_dynamic_pad = FALSE;
2175 str = gst_caps_get_structure(caps, 0);
2178 LOGE("cannot get structure from caps.\n");
2182 name = gst_structure_get_name(str);
2184 LOGE("cannot get mimetype from structure.\n");
2188 if (strstr(name, "video")) {
2190 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2192 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2193 if (player->v_stream_caps) {
2194 gst_caps_unref(player->v_stream_caps);
2195 player->v_stream_caps = NULL;
2198 new_element = gst_element_factory_make("fakesink", NULL);
2199 player->num_dynamic_pad--;
2204 /* clear previous result*/
2205 player->have_dynamic_pad = FALSE;
2207 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2208 LOGE("failed to autoplug for caps");
2212 /* check if there's dynamic pad*/
2213 if (player->have_dynamic_pad) {
2214 LOGE("using pad caps assums there's no dynamic pad !\n");
2218 gst_caps_unref(caps);
2223 /* excute new_element if created*/
2225 LOGD("adding new element to pipeline\n");
2227 /* set state to READY before add to bin */
2228 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2230 /* add new element to the pipeline */
2231 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2232 LOGE("failed to add autoplug element to bin\n");
2236 /* get pad from element */
2237 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2239 LOGE("failed to get sinkpad from autoplug element\n");
2244 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2245 LOGE("failed to link autoplug element\n");
2249 gst_object_unref(sinkpad);
2252 /* run. setting PLAYING here since streamming source is live source */
2253 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2257 gst_caps_unref(caps);
2263 STATE_CHANGE_FAILED:
2265 /* FIXIT : take care if new_element has already added to pipeline */
2267 gst_object_unref(GST_OBJECT(new_element));
2270 gst_object_unref(GST_OBJECT(sinkpad));
2273 gst_caps_unref(caps);
2275 /* FIXIT : how to inform this error to MSL ????? */
2276 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2277 * then post an error to application
2281 static GstPadProbeReturn
2282 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2284 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2285 return GST_PAD_PROBE_OK;
2288 static GstPadProbeReturn
2289 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2291 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2292 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2293 mm_player_t* player = (mm_player_t*)data;
2294 GstCaps* caps = NULL;
2295 GstStructure* str = NULL;
2296 const gchar* name = NULL;
2297 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2300 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2301 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2302 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2303 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2304 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2306 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2307 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2311 caps = gst_pad_query_caps(pad, NULL);
2313 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2317 str = gst_caps_get_structure(caps, 0);
2319 LOGE("failed to get structure from caps");
2323 name = gst_structure_get_name(str);
2325 LOGE("failed to get name from str");
2329 if (strstr(name, "audio")) {
2330 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2331 } else if (strstr(name, "video")) {
2332 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2334 /* text track is not supportable */
2335 LOGE("invalid name %s", name);
2339 switch (GST_EVENT_TYPE(event)) {
2342 /* in case of gapless, drop eos event not to send it to sink */
2343 if (player->gapless.reconfigure && !player->msg_posted) {
2344 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2345 ret = GST_PAD_PROBE_DROP;
2349 case GST_EVENT_STREAM_START:
2351 gint64 stop_running_time = 0;
2352 gint64 position_running_time = 0;
2353 gint64 position = 0;
2356 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2357 if ((player->gapless.update_segment[idx] == TRUE) ||
2358 !(player->selector[idx].event_probe_id)) {
2359 /* LOGW("[%d] skip", idx); */
2363 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2365 gst_segment_to_running_time(&player->gapless.segment[idx],
2366 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2367 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2369 gst_segment_to_running_time(&player->gapless.segment[idx],
2370 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2372 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2374 gst_segment_to_running_time(&player->gapless.segment[idx],
2375 GST_FORMAT_TIME, player->duration);
2378 position_running_time =
2379 gst_segment_to_running_time(&player->gapless.segment[idx],
2380 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2382 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2383 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2385 GST_TIME_ARGS(stop_running_time),
2386 GST_TIME_ARGS(position_running_time),
2387 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2388 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2390 position_running_time = MAX(position_running_time, stop_running_time);
2391 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2392 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2393 position_running_time = MAX(0, position_running_time);
2394 position = MAX(position, position_running_time);
2397 if (position != 0) {
2398 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2399 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2400 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2402 player->gapless.start_time[stream_type] += position;
2406 case GST_EVENT_FLUSH_STOP:
2408 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2409 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2410 player->gapless.start_time[stream_type] = 0;
2413 case GST_EVENT_SEGMENT:
2418 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2419 gst_event_copy_segment(event, &segment);
2421 if (segment.format == GST_FORMAT_TIME) {
2422 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2423 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2424 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2425 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2426 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2427 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2429 /* keep the all the segment ev to cover the seeking */
2430 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2431 player->gapless.update_segment[stream_type] = TRUE;
2433 if (!player->gapless.running)
2436 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2438 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2440 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2441 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2442 gst_event_unref(event);
2443 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2449 gdouble proportion = 0.0;
2450 GstClockTimeDiff diff = 0;
2451 GstClockTime timestamp = 0;
2452 gint64 running_time_diff = -1;
2453 GstQOSType type = 0;
2454 GstEvent *tmpev = NULL;
2456 running_time_diff = player->gapless.segment[stream_type].base;
2458 if (running_time_diff <= 0) /* don't need to adjust */
2461 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2462 gst_event_unref(event);
2464 if (timestamp < running_time_diff) {
2465 LOGW("QOS event from previous group");
2466 ret = GST_PAD_PROBE_DROP;
2470 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2471 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2472 stream_type, GST_TIME_ARGS(timestamp),
2473 GST_TIME_ARGS(running_time_diff),
2474 GST_TIME_ARGS(timestamp - running_time_diff));
2476 timestamp -= running_time_diff;
2478 /* That case is invalid for QoS events */
2479 if (diff < 0 && -diff > timestamp) {
2480 LOGW("QOS event from previous group");
2481 ret = GST_PAD_PROBE_DROP;
2485 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2486 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2496 gst_caps_unref(caps);
2501 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2503 mm_player_t* player = NULL;
2504 GstElement* pipeline = NULL;
2505 GstElement* selector = NULL;
2506 GstElement* fakesink = NULL;
2507 GstCaps* caps = NULL;
2508 GstStructure* str = NULL;
2509 const gchar* name = NULL;
2510 GstPad* sinkpad = NULL;
2511 GstPad* srcpad = NULL;
2512 gboolean first_track = FALSE;
2514 enum MainElementID elemId = MMPLAYER_M_NUM;
2515 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2518 player = (mm_player_t*)data;
2520 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2521 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2523 //LOGD("pad-added signal handling\n");
2525 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2527 /* get mimetype from caps */
2528 caps = gst_pad_query_caps(pad, NULL);
2530 LOGE("cannot get caps from pad.\n");
2534 str = gst_caps_get_structure(caps, 0);
2536 LOGE("cannot get structure from caps.\n");
2540 name = gst_structure_get_name(str);
2542 LOGE("cannot get mimetype from structure.\n");
2546 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2547 //LOGD("detected mimetype : %s\n", name);
2549 if (strstr(name, "video")) {
2552 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2553 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2555 /* don't make video because of not required, and not support multiple track */
2556 if (stype == MM_DISPLAY_SURFACE_NULL) {
2557 LOGD("no video sink by null surface");
2559 gchar *caps_str = gst_caps_to_string(caps);
2560 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2561 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2562 player->set_mode.video_zc = TRUE;
2564 MMPLAYER_FREEIF(caps_str);
2566 if (player->v_stream_caps) {
2567 gst_caps_unref(player->v_stream_caps);
2568 player->v_stream_caps = NULL;
2571 LOGD("create fakesink instead of videobin");
2574 fakesink = gst_element_factory_make("fakesink", NULL);
2575 if (fakesink == NULL) {
2576 LOGE("ERROR : fakesink create error\n");
2580 if (player->ini.set_dump_element_flag)
2581 __mmplayer_add_dump_buffer_probe(player, fakesink);
2583 player->video_fakesink = fakesink;
2585 /* store it as it's sink element */
2586 __mmplayer_add_sink(player, player->video_fakesink);
2588 gst_bin_add(GST_BIN(pipeline), fakesink);
2591 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2593 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2594 LOGW("failed to link fakesink\n");
2595 gst_object_unref(GST_OBJECT(fakesink));
2599 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2600 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2601 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2604 if (player->set_mode.media_packet_video_stream) {
2605 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2607 MMPLAYER_SIGNAL_CONNECT(player,
2609 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2611 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2614 MMPLAYER_SIGNAL_CONNECT(player,
2616 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2618 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2622 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2623 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2627 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2628 __mmplayer_gst_decode_callback(elem, pad, player);
2632 LOGD("video selector \n");
2633 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2634 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2636 if (strstr(name, "audio")) {
2637 gint samplerate = 0;
2640 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2641 __mmplayer_gst_decode_callback(elem, pad, player);
2645 LOGD("audio selector \n");
2646 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2647 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2649 gst_structure_get_int(str, "rate", &samplerate);
2650 gst_structure_get_int(str, "channels", &channels);
2652 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2654 fakesink = gst_element_factory_make("fakesink", NULL);
2655 if (fakesink == NULL) {
2656 LOGE("ERROR : fakesink create error\n");
2660 gst_bin_add(GST_BIN(pipeline), fakesink);
2663 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2665 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2666 LOGW("failed to link fakesink\n");
2667 gst_object_unref(GST_OBJECT(fakesink));
2671 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2672 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2673 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2677 } else if (strstr(name, "text")) {
2678 LOGD("text selector \n");
2679 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2680 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2682 LOGE("wrong elem id \n");
2687 selector = player->pipeline->mainbin[elemId].gst;
2688 if (selector == NULL) {
2689 selector = gst_element_factory_make("input-selector", NULL);
2690 LOGD("Creating input-selector\n");
2691 if (selector == NULL) {
2692 LOGE("ERROR : input-selector create error\n");
2695 g_object_set(selector, "sync-streams", TRUE, NULL);
2697 player->pipeline->mainbin[elemId].id = elemId;
2698 player->pipeline->mainbin[elemId].gst = selector;
2701 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2703 srcpad = gst_element_get_static_pad(selector, "src");
2705 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2706 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2707 __mmplayer_gst_selector_blocked, NULL, NULL);
2708 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2709 __mmplayer_gst_selector_event_probe, player, NULL);
2711 gst_element_set_state(selector, GST_STATE_PAUSED);
2712 gst_bin_add(GST_BIN(pipeline), selector);
2714 LOGD("input-selector is already created.\n");
2717 LOGD("Calling request pad with selector %p \n", selector);
2718 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2720 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2722 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2723 LOGW("failed to link selector\n");
2724 gst_object_unref(GST_OBJECT(selector));
2729 LOGD("this is first track --> active track \n");
2730 g_object_set(selector, "active-pad", sinkpad, NULL);
2733 _mmplayer_track_update_info(player, stream_type, sinkpad);
2740 gst_caps_unref(caps);
2743 gst_object_unref(GST_OBJECT(sinkpad));
2748 gst_object_unref(GST_OBJECT(srcpad));
2755 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2757 GstPad* srcpad = NULL;
2758 MMHandleType attrs = 0;
2759 gint active_index = 0;
2761 // [link] input-selector :: textbin
2762 srcpad = gst_element_get_static_pad(text_selector, "src");
2764 LOGE("failed to get srcpad from selector\n");
2768 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2770 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2771 if ((active_index != DEFAULT_TRACK) &&
2772 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2773 LOGW("failed to change text track\n");
2774 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2777 player->no_more_pad = TRUE;
2778 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2780 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2781 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2782 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2783 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2786 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2788 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2789 player->has_closed_caption = TRUE;
2791 attrs = MMPLAYER_GET_ATTRS(player);
2793 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2794 if (mmf_attrs_commit(attrs))
2795 LOGE("failed to commit.\n");
2797 LOGE("cannot get content attribute");
2800 gst_object_unref(GST_OBJECT(srcpad));
2806 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2808 mm_player_t* player = (mm_player_t*)data;
2809 GstElement* selector = NULL;
2810 GstElement* queue = NULL;
2812 GstPad* srcpad = NULL;
2813 GstPad* sinkpad = NULL;
2814 GstCaps* caps = NULL;
2815 gchar* caps_str = NULL;
2818 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2820 caps = gst_pad_get_current_caps(pad);
2821 caps_str = gst_caps_to_string(caps);
2822 LOGD("deinterleave new caps : %s\n", caps_str);
2823 MMPLAYER_FREEIF(caps_str);
2824 gst_caps_unref(caps);
2826 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2827 LOGE("ERROR : queue create error\n");
2831 g_object_set(G_OBJECT(queue),
2832 "max-size-buffers", 10,
2833 "max-size-bytes", 0,
2834 "max-size-time", (guint64)0,
2837 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2840 LOGE("there is no audio channel selector.\n");
2844 srcpad = gst_element_get_static_pad(queue, "src");
2845 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2847 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2849 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2850 LOGW("failed to link deinterleave - selector\n");
2854 gst_element_set_state(queue, GST_STATE_PAUSED);
2855 player->audio_mode.total_track_num++;
2860 gst_object_unref(GST_OBJECT(srcpad));
2865 gst_object_unref(GST_OBJECT(sinkpad));
2874 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2876 mm_player_t* player = NULL;
2877 GstElement* selector = NULL;
2878 GstPad* sinkpad = NULL;
2879 gint active_index = 0;
2880 gchar* change_pad_name = NULL;
2881 GstCaps* caps = NULL; // no need to unref
2882 gint default_audio_ch = 0;
2885 player = (mm_player_t*) data;
2887 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2890 LOGE("there is no audio channel selector.\n");
2894 active_index = player->audio_mode.active_pad_index;
2896 if (active_index != default_audio_ch) {
2897 gint audio_ch = default_audio_ch;
2899 /*To get the new pad from the selector*/
2900 change_pad_name = g_strdup_printf("sink%d", active_index);
2901 if (change_pad_name != NULL) {
2902 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2903 if (sinkpad != NULL) {
2904 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2905 g_object_set(selector, "active-pad", sinkpad, NULL);
2907 audio_ch = active_index;
2909 caps = gst_pad_get_current_caps(sinkpad);
2910 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2912 __mmplayer_set_audio_attrs(player, caps);
2913 gst_caps_unref(caps);
2915 MMPLAYER_FREEIF(change_pad_name);
2918 player->audio_mode.active_pad_index = audio_ch;
2919 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2925 gst_object_unref(sinkpad);
2932 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2934 mm_player_t* player = NULL;
2935 MMPlayerGstElement *mainbin = NULL;
2937 GstElement* tee = NULL;
2938 GstElement* stereo_queue = NULL;
2939 GstElement* mono_queue = NULL;
2940 GstElement* conv = NULL;
2941 GstElement* filter = NULL;
2942 GstElement* deinterleave = NULL;
2943 GstElement* selector = NULL;
2945 GstPad* srcpad = NULL;
2946 GstPad* selector_srcpad = NULL;
2947 GstPad* sinkpad = NULL;
2948 GstCaps* caps = NULL;
2949 gulong block_id = 0;
2954 player = (mm_player_t*) data;
2956 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2957 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2959 mainbin = player->pipeline->mainbin;
2962 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2963 LOGE("ERROR : tee create error\n");
2967 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2968 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2970 gst_element_set_state(tee, GST_STATE_PAUSED);
2973 srcpad = gst_element_get_request_pad(tee, "src_%u");
2974 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2975 LOGE("ERROR : stereo queue create error\n");
2979 g_object_set(G_OBJECT(stereo_queue),
2980 "max-size-buffers", 10,
2981 "max-size-bytes", 0,
2982 "max-size-time", (guint64)0,
2985 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2986 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2989 gst_object_unref(GST_OBJECT(srcpad));
2993 srcpad = gst_element_get_request_pad(tee, "src_%u");
2995 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2996 LOGE("ERROR : mono queue create error\n");
3000 g_object_set(G_OBJECT(mono_queue),
3001 "max-size-buffers", 10,
3002 "max-size-bytes", 0,
3003 "max-size-time", (guint64)0,
3006 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3007 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3009 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3010 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3013 srcpad = gst_element_get_static_pad(mono_queue, "src");
3014 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3015 LOGE("ERROR : audioconvert create error\n");
3019 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3020 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3024 gst_object_unref(GST_OBJECT(srcpad));
3027 srcpad = gst_element_get_static_pad(conv, "src");
3029 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3030 LOGE("ERROR : capsfilter create error\n");
3034 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3035 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3037 caps = gst_caps_from_string("audio/x-raw-int, "
3038 "width = (int) 16, "
3039 "depth = (int) 16, "
3040 "channels = (int) 2");
3042 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3043 gst_caps_unref(caps);
3045 gst_element_set_state(conv, GST_STATE_PAUSED);
3046 gst_element_set_state(filter, GST_STATE_PAUSED);
3050 gst_object_unref(GST_OBJECT(srcpad));
3053 srcpad = gst_element_get_static_pad(filter, "src");
3055 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3056 LOGE("ERROR : deinterleave create error\n");
3060 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3062 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3063 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3065 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3066 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3068 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3069 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3072 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3073 if (selector == NULL) {
3074 LOGE("ERROR : audio-selector create error\n");
3078 g_object_set(selector, "sync-streams", TRUE, NULL);
3079 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3081 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3082 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3084 selector_srcpad = gst_element_get_static_pad(selector, "src");
3086 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3088 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3089 __mmplayer_gst_selector_blocked, NULL, NULL);
3092 gst_object_unref(GST_OBJECT(srcpad));
3096 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3097 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3099 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3100 LOGW("failed to link queue_stereo - selector\n");
3104 player->audio_mode.total_track_num++;
3106 g_object_set(selector, "active-pad", sinkpad, NULL);
3107 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3108 gst_element_set_state(selector, GST_STATE_PAUSED);
3110 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3114 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3115 if (block_id != 0) {
3116 gst_pad_remove_probe(selector_srcpad, block_id);
3121 gst_object_unref(GST_OBJECT(sinkpad));
3126 gst_object_unref(GST_OBJECT(srcpad));
3130 if (selector_srcpad) {
3131 gst_object_unref(GST_OBJECT(selector_srcpad));
3132 selector_srcpad = NULL;
3140 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3142 mm_player_t* player = NULL;
3143 GstPad* srcpad = NULL;
3144 GstElement* video_selector = NULL;
3145 GstElement* audio_selector = NULL;
3146 GstElement* text_selector = NULL;
3147 MMHandleType attrs = 0;
3148 gint active_index = 0;
3149 gint64 dur_bytes = 0L;
3151 player = (mm_player_t*) data;
3153 LOGD("no-more-pad signal handling\n");
3155 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3156 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3157 LOGW("no need to go more");
3159 if (player->gapless.reconfigure) {
3160 player->gapless.reconfigure = FALSE;
3161 MMPLAYER_PLAYBACK_UNLOCK(player);
3167 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3168 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3169 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3170 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3171 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3173 if (NULL == player->streamer) {
3174 LOGW("invalid state for buffering");
3178 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3179 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3181 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3182 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3184 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3186 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3187 LOGE("fail to get duration.\n");
3189 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3190 // use file information was already set on Q2 when it was created.
3191 __mm_player_streaming_set_queue2(player->streamer,
3192 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3193 TRUE, // use_buffering
3195 init_buffering_time,
3197 player->ini.http_buffering_limit, // high percent
3198 MUXED_BUFFER_TYPE_MEM_QUEUE,
3200 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3203 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3204 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3205 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3206 if (video_selector) {
3207 // [link] input-selector :: videobin
3208 srcpad = gst_element_get_static_pad(video_selector, "src");
3210 LOGE("failed to get srcpad from video selector\n");
3214 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3215 if (!text_selector && !audio_selector)
3216 player->no_more_pad = TRUE;
3218 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3220 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3221 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3222 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3223 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3227 if (audio_selector) {
3228 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3229 if ((active_index != DEFAULT_TRACK) &&
3230 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3231 LOGW("failed to change audio track\n");
3232 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3235 // [link] input-selector :: audiobin
3236 srcpad = gst_element_get_static_pad(audio_selector, "src");
3238 LOGE("failed to get srcpad from selector\n");
3242 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3244 player->no_more_pad = TRUE;
3246 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3247 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3248 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3249 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3250 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3253 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3255 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3257 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3258 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3259 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3260 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3264 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3266 attrs = MMPLAYER_GET_ATTRS(player);
3268 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3269 if (mmf_attrs_commit(attrs))
3270 LOGE("failed to commit.\n");
3272 LOGE("cannot get content attribute");
3274 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3275 LOGD("There is no audio track : remove audiobin");
3277 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3278 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3280 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3281 MMPLAYER_FREEIF(player->pipeline->audiobin);
3284 if (player->num_dynamic_pad == 0)
3285 __mmplayer_pipeline_complete(NULL, player);
3288 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3290 __mmplayer_handle_text_decode_path(player, text_selector);
3297 gst_object_unref(GST_OBJECT(srcpad));
3301 if (player->gapless.reconfigure) {
3302 player->gapless.reconfigure = FALSE;
3303 MMPLAYER_PLAYBACK_UNLOCK(player);
3308 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3310 mm_player_t* player = NULL;
3311 MMHandleType attrs = 0;
3312 GstElement* pipeline = NULL;
3313 GstCaps* caps = NULL;
3314 gchar* caps_str = NULL;
3315 GstStructure* str = NULL;
3316 const gchar* name = NULL;
3317 GstPad* sinkpad = NULL;
3318 GstElement* sinkbin = NULL;
3319 gboolean reusing = FALSE;
3320 GstElement *text_selector = NULL;
3323 player = (mm_player_t*) data;
3325 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3326 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3328 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3330 attrs = MMPLAYER_GET_ATTRS(player);
3332 LOGE("cannot get content attribute\n");
3336 /* get mimetype from caps */
3337 caps = gst_pad_query_caps(pad, NULL);
3339 LOGE("cannot get caps from pad.\n");
3342 caps_str = gst_caps_to_string(caps);
3344 str = gst_caps_get_structure(caps, 0);
3346 LOGE("cannot get structure from caps.\n");
3350 name = gst_structure_get_name(str);
3352 LOGE("cannot get mimetype from structure.\n");
3356 //LOGD("detected mimetype : %s\n", name);
3358 if (strstr(name, "audio")) {
3359 if (player->pipeline->audiobin == NULL) {
3360 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3361 LOGE("failed to create audiobin. continuing without audio\n");
3365 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3366 LOGD("creating audiosink bin success\n");
3369 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3370 LOGD("reusing audiobin\n");
3371 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3374 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3375 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3377 player->audiosink_linked = 1;
3379 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3381 LOGE("failed to get pad from sinkbin\n");
3384 } else if (strstr(name, "video")) {
3385 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3386 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3387 player->set_mode.video_zc = TRUE;
3389 if (player->pipeline->videobin == NULL) {
3390 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3391 /* get video surface type */
3392 int surface_type = 0;
3393 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3394 LOGD("display_surface_type(%d)\n", surface_type);
3396 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3397 LOGD("not make videobin because it dose not want\n");
3401 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3402 /* mark video overlay for acquire */
3403 if (player->video_overlay_resource == NULL) {
3404 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3405 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3406 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3407 &player->video_overlay_resource)
3408 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3409 LOGE("could not mark video_overlay resource for acquire\n");
3415 player->interrupted_by_resource = FALSE;
3416 /* acquire resources for video overlay */
3417 if (mm_resource_manager_commit(player->resource_manager) !=
3418 MM_RESOURCE_MANAGER_ERROR_NONE) {
3419 LOGE("could not acquire resources for video playing\n");
3423 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3424 LOGE("failed to create videobin. continuing without video\n");
3428 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3429 LOGD("creating videosink bin success\n");
3432 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3433 LOGD("re-using videobin\n");
3434 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3437 player->videosink_linked = 1;
3439 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3441 LOGE("failed to get pad from sinkbin\n");
3444 } else if (strstr(name, "text")) {
3445 if (player->pipeline->textbin == NULL) {
3446 MMPlayerGstElement* mainbin = NULL;
3448 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3449 LOGE("failed to create text sink bin. continuing without text\n");
3453 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3454 LOGD("creating textsink bin success\n");
3456 /* FIXIT : track number shouldn't be hardcoded */
3457 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3459 player->textsink_linked = 1;
3460 LOGI("player->textsink_linked set to 1\n");
3462 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3464 LOGE("failed to get pad from sinkbin\n");
3468 mainbin = player->pipeline->mainbin;
3470 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3471 /* input selector */
3472 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3473 if (!text_selector) {
3474 LOGE("failed to create subtitle input selector element\n");
3477 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3479 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3480 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3483 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3484 LOGE("failed to set state(READY) to sinkbin\n");
3488 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3489 LOGW("failed to add subtitle input selector\n");
3493 LOGD("created element input-selector");
3496 LOGD("already having subtitle input selector");
3497 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3500 if (!player->textsink_linked) {
3501 LOGD("re-using textbin\n");
3504 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3506 player->textsink_linked = 1;
3507 LOGI("player->textsink_linked set to 1\n");
3509 LOGD("ignoring internal subtutle since external subtitle is available");
3512 LOGW("unknown type of elementary stream!ignoring it...\n");
3519 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3520 LOGE("failed to set state(READY) to sinkbin\n");
3524 /* Added for multi audio support to avoid adding audio bin again*/
3526 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3527 LOGE("failed to add sinkbin to pipeline\n");
3533 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3534 LOGE("failed to get pad from sinkbin\n");
3540 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3541 LOGE("failed to set state(PAUSED) to sinkbin\n");
3545 if (text_selector) {
3546 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3547 LOGE("failed to set state(PAUSED) to sinkbin\n");
3553 gst_object_unref(sinkpad);
3557 LOGD("[handle: %p] linking sink bin success", player);
3559 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3560 * streaming task. if the task blocked, then buffer will not flow to the next element
3561 *(autoplugging element). so this is special hack for streaming. please try to remove it
3563 /* dec stream count. we can remove fakesink if it's zero */
3564 if (player->num_dynamic_pad)
3565 player->num_dynamic_pad--;
3567 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3569 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3570 __mmplayer_pipeline_complete(NULL, player);
3574 MMPLAYER_FREEIF(caps_str);
3577 gst_caps_unref(caps);
3580 gst_object_unref(GST_OBJECT(sinkpad));
3582 /* flusing out new attributes */
3583 if (mmf_attrs_commit(attrs))
3584 LOGE("failed to comit attributes\n");
3590 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3592 int pro_value = 0; // in the case of expection, default will be returned.
3593 int dest_angle = rotation_angle;
3594 int rotation_type = -1;
3596 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3597 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3598 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3600 if (rotation_angle >= 360)
3601 dest_angle = rotation_angle - 360;
3603 /* chech if supported or not */
3604 if (dest_angle % 90) {
3605 LOGD("not supported rotation angle = %d", rotation_angle);
3611 * custom_convert - none (B)
3612 * videoflip - none (C)
3614 if (player->set_mode.video_zc) {
3615 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3616 rotation_type = ROTATION_USING_CUSTOM;
3618 rotation_type = ROTATION_USING_SINK;
3620 int surface_type = 0;
3621 rotation_type = ROTATION_USING_FLIP;
3623 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3624 LOGD("check display surface type attribute: %d", surface_type);
3626 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3627 rotation_type = ROTATION_USING_SINK;
3629 rotation_type = ROTATION_USING_FLIP; //C
3631 LOGD("using %d type for rotation", rotation_type);
3634 /* get property value for setting */
3635 switch (rotation_type) {
3636 case ROTATION_USING_SINK: // tizenwlsink
3638 switch (dest_angle) {
3642 pro_value = 3; // clockwise 90
3648 pro_value = 1; // counter-clockwise 90
3653 case ROTATION_USING_CUSTOM:
3655 gchar *ename = NULL;
3656 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3658 if (g_strrstr(ename, "fimcconvert")) {
3659 switch (dest_angle) {
3663 pro_value = 90; // clockwise 90
3669 pro_value = 270; // counter-clockwise 90
3675 case ROTATION_USING_FLIP: // videoflip
3677 switch (dest_angle) {
3681 pro_value = 1; // clockwise 90
3687 pro_value = 3; // counter-clockwise 90
3694 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3702 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3704 /* check video sinkbin is created */
3705 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3707 player->pipeline->videobin &&
3708 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3709 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3710 MM_ERROR_PLAYER_NOT_INITIALIZED);
3712 return MM_ERROR_NONE;
3716 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3718 int rotation_value = 0;
3719 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3723 /* check video sinkbin is created */
3724 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3727 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3729 /* get rotation value to set */
3730 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3731 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3732 LOGD("set video param : rotate %d", rotation_value);
3736 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3738 MMHandleType attrs = 0;
3742 /* check video sinkbin is created */
3743 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3746 attrs = MMPLAYER_GET_ATTRS(player);
3747 MMPLAYER_RETURN_IF_FAIL(attrs);
3749 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3750 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3751 LOGD("set video param : visible %d", visible);
3755 __mmplayer_video_param_set_display_method(mm_player_t* player)
3757 MMHandleType attrs = 0;
3758 int display_method = 0;
3761 /* check video sinkbin is created */
3762 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3765 attrs = MMPLAYER_GET_ATTRS(player);
3766 MMPLAYER_RETURN_IF_FAIL(attrs);
3768 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3769 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3770 LOGD("set video param : method %d", display_method);
3774 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3776 MMHandleType attrs = 0;
3777 void *handle = NULL;
3779 int wl_window_x = 0;
3780 int wl_window_y = 0;
3781 int wl_window_width = 0;
3782 int wl_window_height = 0;
3785 /* check video sinkbin is created */
3786 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3789 attrs = MMPLAYER_GET_ATTRS(player);
3790 MMPLAYER_RETURN_IF_FAIL(attrs);
3792 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3795 /*It should be set after setting window*/
3796 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3797 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3798 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3799 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3801 /* After setting window handle, set render rectangle */
3802 gst_video_overlay_set_render_rectangle(
3803 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3804 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3805 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3806 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3811 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3813 MMHandleType attrs = 0;
3814 void *handle = NULL;
3816 /* check video sinkbin is created */
3817 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3820 attrs = MMPLAYER_GET_ATTRS(player);
3821 MMPLAYER_RETURN_IF_FAIL(attrs);
3823 /* common case if using overlay surface */
3824 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3827 /* default is using wl_surface_id */
3828 unsigned int wl_surface_id = 0;
3829 wl_surface_id = *(int*)handle;
3830 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3831 gst_video_overlay_set_wl_window_wl_surface_id(
3832 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3835 /* FIXIT : is it error case? */
3836 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3841 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3843 bool update_all_param = FALSE;
3846 /* check video sinkbin is created */
3847 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3848 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3850 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3851 LOGE("can not find tizenwlsink");
3852 return MM_ERROR_PLAYER_INTERNAL;
3855 LOGD("param_name : %s", param_name);
3856 if (!g_strcmp0(param_name, "update_all_param"))
3857 update_all_param = TRUE;
3859 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3860 __mmplayer_video_param_set_display_overlay(player);
3861 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3862 __mmplayer_video_param_set_display_method(player);
3863 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3864 __mmplayer_video_param_set_render_rectangle(player);
3865 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3866 __mmplayer_video_param_set_display_visible(player);
3867 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3868 __mmplayer_video_param_set_display_rotation(player);
3870 return MM_ERROR_NONE;
3874 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3876 MMHandleType attrs = 0;
3877 int surface_type = 0;
3878 int ret = MM_ERROR_NONE;
3882 /* check video sinkbin is created */
3883 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3884 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3886 attrs = MMPLAYER_GET_ATTRS(player);
3888 LOGE("cannot get content attribute");
3889 return MM_ERROR_PLAYER_INTERNAL;
3891 LOGD("param_name : %s", param_name);
3893 /* update display surface */
3894 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3895 LOGD("check display surface type attribute: %d", surface_type);
3897 /* configuring display */
3898 switch (surface_type) {
3899 case MM_DISPLAY_SURFACE_OVERLAY:
3901 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3902 if (ret != MM_ERROR_NONE)
3910 return MM_ERROR_NONE;
3914 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3916 gboolean disable_overlay = FALSE;
3917 mm_player_t* player = (mm_player_t*) hplayer;
3918 int ret = MM_ERROR_NONE;
3921 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3922 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3923 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3924 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3926 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3927 LOGW("Display control is not supported");
3928 return MM_ERROR_PLAYER_INTERNAL;
3931 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3933 if (audio_only == (bool)disable_overlay) {
3934 LOGE("It's the same with current setting: (%d)", audio_only);
3935 return MM_ERROR_NONE;
3939 LOGE("disable overlay");
3940 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3942 /* release overlay resource */
3943 if (player->video_overlay_resource != NULL) {
3944 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3945 player->video_overlay_resource);
3946 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3947 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3950 player->video_overlay_resource = NULL;
3953 ret = mm_resource_manager_commit(player->resource_manager);
3954 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3955 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3959 /* mark video overlay for acquire */
3960 if (player->video_overlay_resource == NULL) {
3961 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3962 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3963 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3964 &player->video_overlay_resource);
3965 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3966 LOGE("could not prepare for video_overlay resource\n");
3971 player->interrupted_by_resource = FALSE;
3972 /* acquire resources for video overlay */
3973 ret = mm_resource_manager_commit(player->resource_manager);
3974 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3975 LOGE("could not acquire resources for video playing\n");
3979 LOGD("enable overlay");
3980 __mmplayer_video_param_set_display_overlay(player);
3981 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3986 return MM_ERROR_NONE;
3990 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3992 mm_player_t* player = (mm_player_t*) hplayer;
3993 gboolean disable_overlay = FALSE;
3997 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3998 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3999 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
4000 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4001 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4003 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4004 LOGW("Display control is not supported");
4005 return MM_ERROR_PLAYER_INTERNAL;
4008 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4010 *paudio_only = (bool)(disable_overlay);
4012 LOGD("audio_only : %d", *paudio_only);
4016 return MM_ERROR_NONE;
4020 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4022 GList* bucket = element_bucket;
4023 MMPlayerGstElement* element = NULL;
4024 MMPlayerGstElement* prv_element = NULL;
4025 gint successful_link_count = 0;
4029 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4031 prv_element = (MMPlayerGstElement*)bucket->data;
4032 bucket = bucket->next;
4034 for (; bucket; bucket = bucket->next) {
4035 element = (MMPlayerGstElement*)bucket->data;
4037 if (element && element->gst) {
4038 /* If next element is audio appsrc then make a separate audio pipeline */
4039 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4040 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4041 prv_element = element;
4045 if (prv_element && prv_element->gst) {
4046 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4047 LOGD("linking [%s] to [%s] success\n",
4048 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4049 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4050 successful_link_count++;
4052 LOGD("linking [%s] to [%s] failed\n",
4053 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4054 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4060 prv_element = element;
4065 return successful_link_count;
4069 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4071 GList* bucket = element_bucket;
4072 MMPlayerGstElement* element = NULL;
4073 int successful_add_count = 0;
4077 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4078 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4080 for (; bucket; bucket = bucket->next) {
4081 element = (MMPlayerGstElement*)bucket->data;
4083 if (element && element->gst) {
4084 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4085 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4086 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4087 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4090 successful_add_count++;
4096 return successful_add_count;
4099 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4101 mm_player_t* player = (mm_player_t*) data;
4102 GstCaps *caps = NULL;
4103 GstStructure *str = NULL;
4108 MMPLAYER_RETURN_IF_FAIL(pad)
4109 MMPLAYER_RETURN_IF_FAIL(unused)
4110 MMPLAYER_RETURN_IF_FAIL(data)
4112 caps = gst_pad_get_current_caps(pad);
4116 str = gst_caps_get_structure(caps, 0);
4120 name = gst_structure_get_name(str);
4124 LOGD("name = %s\n", name);
4126 if (strstr(name, "audio")) {
4127 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4129 if (player->audio_stream_changed_cb) {
4130 LOGE("call the audio stream changed cb\n");
4131 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4133 } else if (strstr(name, "video")) {
4134 if ((name = gst_structure_get_string(str, "format")))
4135 player->set_mode.video_zc = name[0] == 'S';
4137 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4139 if (player->video_stream_changed_cb) {
4140 LOGE("call the video stream changed cb\n");
4141 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4148 gst_caps_unref(caps);
4158 * This function is to create audio pipeline for playing.
4160 * @param player [in] handle of player
4162 * @return This function returns zero on success.
4164 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4166 /* macro for code readability. just for sinkbin-creation functions */
4167 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4169 x_bin[x_id].id = x_id;\
4170 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4171 if (!x_bin[x_id].gst) {\
4172 LOGE("failed to create %s \n", x_factory);\
4175 if (x_player->ini.set_dump_element_flag)\
4176 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4179 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4183 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4188 MMPLAYER_RETURN_IF_FAIL(player);
4190 if (player->audio_stream_buff_list) {
4191 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4192 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4195 LOGD("[%lld] send remained data.", tmp->channel_mask);
4196 __mmplayer_audio_stream_send_data(player, tmp);
4199 g_free(tmp->pcm_data);
4203 g_list_free(player->audio_stream_buff_list);
4204 player->audio_stream_buff_list = NULL;
4211 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4213 MMPlayerAudioStreamDataType audio_stream = { 0, };
4216 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4218 audio_stream.bitrate = a_buffer->bitrate;
4219 audio_stream.channel = a_buffer->channel;
4220 audio_stream.depth = a_buffer->depth;
4221 audio_stream.is_little_endian = a_buffer->is_little_endian;
4222 audio_stream.channel_mask = a_buffer->channel_mask;
4223 audio_stream.data_size = a_buffer->data_size;
4224 audio_stream.data = a_buffer->pcm_data;
4226 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4227 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4233 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4235 mm_player_t* player = (mm_player_t*) data;
4240 gint endianness = 0;
4241 guint64 channel_mask = 0;
4242 void *a_data = NULL;
4244 mm_player_audio_stream_buff_t *a_buffer = NULL;
4245 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4249 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4251 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4252 a_data = mapinfo.data;
4253 a_size = mapinfo.size;
4255 GstCaps *caps = gst_pad_get_current_caps(pad);
4256 GstStructure *structure = gst_caps_get_structure(caps, 0);
4258 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4259 gst_structure_get_int(structure, "rate", &rate);
4260 gst_structure_get_int(structure, "channels", &channel);
4261 gst_structure_get_int(structure, "depth", &depth);
4262 gst_structure_get_int(structure, "endianness", &endianness);
4263 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4264 gst_caps_unref(GST_CAPS(caps));
4266 /* In case of the sync is false, use buffer list. *
4267 * The num of buffer list depends on the num of audio channels */
4268 if (player->audio_stream_buff_list) {
4269 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4270 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4272 if (channel_mask == tmp->channel_mask) {
4273 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4274 if (tmp->data_size + a_size < tmp->buff_size) {
4275 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4276 tmp->data_size += a_size;
4278 /* send data to client */
4279 __mmplayer_audio_stream_send_data(player, tmp);
4281 if (a_size > tmp->buff_size) {
4282 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4283 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4284 if (tmp->pcm_data == NULL) {
4285 LOGE("failed to realloc data.");
4288 tmp->buff_size = a_size;
4290 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4291 memcpy(tmp->pcm_data, a_data, a_size);
4292 tmp->data_size = a_size;
4297 LOGE("data is empty in list.");
4303 /* create new audio stream data */
4304 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4305 if (a_buffer == NULL) {
4306 LOGE("failed to alloc data.");
4309 a_buffer->bitrate = rate;
4310 a_buffer->channel = channel;
4311 a_buffer->depth = depth;
4312 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4313 a_buffer->channel_mask = channel_mask;
4314 a_buffer->data_size = a_size;
4316 if (!player->audio_stream_sink_sync) {
4317 /* If sync is FALSE, use buffer list to reduce the IPC. */
4318 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4319 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4320 if (a_buffer->pcm_data == NULL) {
4321 LOGE("failed to alloc data.");
4325 memcpy(a_buffer->pcm_data, a_data, a_size);
4326 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4327 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4329 /* If sync is TRUE, send data directly. */
4330 a_buffer->pcm_data = a_data;
4331 __mmplayer_audio_stream_send_data(player, a_buffer);
4336 gst_buffer_unmap(buffer, &mapinfo);
4341 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4343 mm_player_t* player = (mm_player_t*)data;
4344 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4345 GstPad* sinkpad = NULL;
4346 GstElement *queue = NULL, *sink = NULL;
4349 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4351 queue = gst_element_factory_make("queue", NULL);
4352 if (queue == NULL) {
4353 LOGD("fail make queue\n");
4357 sink = gst_element_factory_make("fakesink", NULL);
4359 LOGD("fail make fakesink\n");
4363 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4365 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4366 LOGW("failed to link queue & sink\n");
4370 sinkpad = gst_element_get_static_pad(queue, "sink");
4372 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4373 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4377 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4379 gst_object_unref(sinkpad);
4380 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4381 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4383 gst_element_set_state(sink, GST_STATE_PAUSED);
4384 gst_element_set_state(queue, GST_STATE_PAUSED);
4386 MMPLAYER_SIGNAL_CONNECT(player,
4388 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4390 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4397 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4399 gst_object_unref(GST_OBJECT(queue));
4403 gst_object_unref(GST_OBJECT(sink));
4407 gst_object_unref(GST_OBJECT(sinkpad));
4414 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4416 #define MAX_PROPS_LEN 128
4417 gint latency_mode = 0;
4418 gchar *stream_type = NULL;
4419 gchar *latency = NULL;
4421 gchar stream_props[MAX_PROPS_LEN] = {0,};
4422 GstStructure *props = NULL;
4425 * It should be set after player creation through attribute.
4426 * But, it can not be changed during playing.
4429 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4430 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4433 LOGE("stream_type is null.\n");
4435 if (player->sound.focus_id)
4436 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4437 stream_type, stream_id, player->sound.focus_id);
4439 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4440 stream_type, stream_id);
4441 props = gst_structure_from_string(stream_props, NULL);
4442 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4443 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4444 stream_type, stream_id, player->sound.focus_id, stream_props);
4445 gst_structure_free(props);
4448 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4450 switch (latency_mode) {
4451 case AUDIO_LATENCY_MODE_LOW:
4452 latency = g_strndup("low", 3);
4454 case AUDIO_LATENCY_MODE_MID:
4455 latency = g_strndup("mid", 3);
4457 case AUDIO_LATENCY_MODE_HIGH:
4458 latency = g_strndup("high", 4);
4462 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4466 LOGD("audiosink property - latency=%s \n", latency);
4474 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4476 MMPlayerGstElement* first_element = NULL;
4477 MMPlayerGstElement* audiobin = NULL;
4478 MMHandleType attrs = 0;
4480 GstPad *ghostpad = NULL;
4481 GList* element_bucket = NULL;
4482 gboolean link_audio_sink_now = TRUE;
4488 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4491 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4493 LOGE("failed to allocate memory for audiobin\n");
4494 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4497 attrs = MMPLAYER_GET_ATTRS(player);
4500 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4501 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4502 if (!audiobin[MMPLAYER_A_BIN].gst) {
4503 LOGE("failed to create audiobin\n");
4508 player->pipeline->audiobin = audiobin;
4510 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4512 /* Adding audiotp plugin for reverse trickplay feature */
4513 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4516 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4518 /* replaygain volume */
4519 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4520 if (player->sound.rg_enable)
4521 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4523 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4526 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4528 if (player->set_mode.pcm_extraction) {
4529 // pcm extraction only and no sound output
4530 if (player->audio_stream_render_cb_ex) {
4531 char *caps_str = NULL;
4532 GstCaps* caps = NULL;
4533 gchar *format = NULL;
4536 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4538 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4540 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4542 caps = gst_caps_new_simple("audio/x-raw",
4543 "format", G_TYPE_STRING, format,
4544 "rate", G_TYPE_INT, player->pcm_samplerate,
4545 "channels", G_TYPE_INT, player->pcm_channel,
4547 caps_str = gst_caps_to_string(caps);
4548 LOGD("new caps : %s\n", caps_str);
4550 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4553 gst_caps_unref(caps);
4554 MMPLAYER_FREEIF(caps_str);
4556 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4558 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4559 /* raw pad handling signal */
4560 MMPLAYER_SIGNAL_CONNECT(player,
4561 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4562 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4563 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4565 int dst_samplerate = 0;
4566 int dst_channels = 0;
4568 char *caps_str = NULL;
4569 GstCaps* caps = NULL;
4571 /* get conf. values */
4572 mm_attrs_multiple_get(player->attrs,
4574 "pcm_extraction_samplerate", &dst_samplerate,
4575 "pcm_extraction_channels", &dst_channels,
4576 "pcm_extraction_depth", &dst_depth,
4580 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4581 caps = gst_caps_new_simple("audio/x-raw",
4582 "rate", G_TYPE_INT, dst_samplerate,
4583 "channels", G_TYPE_INT, dst_channels,
4584 "depth", G_TYPE_INT, dst_depth,
4586 caps_str = gst_caps_to_string(caps);
4587 LOGD("new caps : %s\n", caps_str);
4589 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4592 gst_caps_unref(caps);
4593 MMPLAYER_FREEIF(caps_str);
4596 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4599 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4603 //GstCaps* caps = NULL;
4606 /* for logical volume control */
4607 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4608 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4610 if (player->sound.mute) {
4611 LOGD("mute enabled\n");
4612 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4617 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4618 caps = gst_caps_from_string("audio/x-raw-int, "
4619 "endianness = (int) LITTLE_ENDIAN, "
4620 "signed = (boolean) true, "
4621 "width = (int) 16, "
4622 "depth = (int) 16");
4623 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4624 gst_caps_unref(caps);
4627 /* check if multi-channels */
4628 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4629 GstPad *srcpad = NULL;
4630 GstCaps *caps = NULL;
4632 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4633 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4634 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4635 GstStructure *str = gst_caps_get_structure(caps, 0);
4637 gst_structure_get_int(str, "channels", &channels);
4638 gst_caps_unref(caps);
4640 gst_object_unref(srcpad);
4644 /* audio effect element. if audio effect is enabled */
4645 if ((strcmp(player->ini.audioeffect_element, ""))
4647 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4648 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4650 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4652 if ((!player->bypass_audio_effect)
4653 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4654 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4655 if (!_mmplayer_audio_effect_custom_apply(player))
4656 LOGI("apply audio effect(custom) setting success\n");
4660 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4661 && (player->set_mode.rich_audio))
4662 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4665 /* create audio sink */
4666 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4667 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4668 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4670 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4671 if (player->is_360_feature_enabled &&
4672 player->is_content_spherical &&
4674 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4675 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4676 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4678 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4683 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4685 gst_caps_unref(acaps);
4687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4689 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4690 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4692 player->is_openal_plugin_used = TRUE;
4694 if (player->video360_yaw_radians <= M_PI &&
4695 player->video360_yaw_radians >= -M_PI &&
4696 player->video360_pitch_radians <= M_PI_2 &&
4697 player->video360_pitch_radians >= -M_PI_2) {
4698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4699 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4700 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4701 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4703 "source-orientation-y", player->video360_metadata.init_view_heading,
4704 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4707 if (player->is_360_feature_enabled && player->is_content_spherical)
4708 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4713 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4717 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4718 (player->videodec_linked && player->ini.use_system_clock)) {
4719 LOGD("system clock will be used.\n");
4720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4723 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4724 __mmplayer_gst_set_audiosink_property(player, attrs);
4727 if (audiobin[MMPLAYER_A_SINK].gst) {
4728 GstPad *sink_pad = NULL;
4729 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4730 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4731 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4732 gst_object_unref(GST_OBJECT(sink_pad));
4735 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4737 /* adding created elements to bin */
4738 LOGD("adding created elements to bin\n");
4739 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4740 LOGE("failed to add elements\n");
4744 /* linking elements in the bucket by added order. */
4745 LOGD("Linking elements in the bucket by added order.\n");
4746 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4747 LOGE("failed to link elements\n");
4751 /* get first element's sinkpad for creating ghostpad */
4752 first_element = (MMPlayerGstElement *)element_bucket->data;
4753 if (!first_element) {
4754 LOGE("failed to get first elem\n");
4758 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4760 LOGE("failed to get pad from first element of audiobin\n");
4764 ghostpad = gst_ghost_pad_new("sink", pad);
4766 LOGE("failed to create ghostpad\n");
4770 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4771 LOGE("failed to add ghostpad to audiobin\n");
4775 gst_object_unref(pad);
4777 g_list_free(element_bucket);
4780 return MM_ERROR_NONE;
4784 LOGD("ERROR : releasing audiobin\n");
4787 gst_object_unref(GST_OBJECT(pad));
4790 gst_object_unref(GST_OBJECT(ghostpad));
4793 g_list_free(element_bucket);
4795 /* release element which are not added to bin */
4796 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4797 /* NOTE : skip bin */
4798 if (audiobin[i].gst) {
4799 GstObject* parent = NULL;
4800 parent = gst_element_get_parent(audiobin[i].gst);
4803 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4804 audiobin[i].gst = NULL;
4806 gst_object_unref(GST_OBJECT(parent));
4810 /* release audiobin with it's childs */
4811 if (audiobin[MMPLAYER_A_BIN].gst)
4812 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4814 MMPLAYER_FREEIF(audiobin);
4816 player->pipeline->audiobin = NULL;
4818 return MM_ERROR_PLAYER_INTERNAL;
4821 static GstPadProbeReturn
4822 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4824 mm_player_t* player = (mm_player_t*) u_data;
4825 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4826 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4828 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4830 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4831 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4833 return GST_PAD_PROBE_OK;
4836 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4838 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4841 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4843 int ret = MM_ERROR_NONE;
4845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4846 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4848 MMPLAYER_VIDEO_BO_LOCK(player);
4850 if (player->video_bo_list) {
4851 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4852 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4853 if (tmp && tmp->bo == bo) {
4855 LOGD("release bo %p", bo);
4856 tbm_bo_unref(tmp->bo);
4857 MMPLAYER_VIDEO_BO_UNLOCK(player);
4858 MMPLAYER_VIDEO_BO_SIGNAL(player);
4863 /* hw codec is running or the list was reset for DRC. */
4864 LOGW("there is no bo list.");
4866 MMPLAYER_VIDEO_BO_UNLOCK(player);
4868 LOGW("failed to find bo %p", bo);
4873 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4878 MMPLAYER_RETURN_IF_FAIL(player);
4880 MMPLAYER_VIDEO_BO_LOCK(player);
4881 if (player->video_bo_list) {
4882 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4883 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4884 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4887 tbm_bo_unref(tmp->bo);
4891 g_list_free(player->video_bo_list);
4892 player->video_bo_list = NULL;
4894 player->video_bo_size = 0;
4895 MMPLAYER_VIDEO_BO_UNLOCK(player);
4902 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4905 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4906 gboolean ret = TRUE;
4908 /* check DRC, if it is, destroy the prev bo list to create again */
4909 if (player->video_bo_size != size) {
4910 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4911 __mmplayer_video_stream_destroy_bo_list(player);
4912 player->video_bo_size = size;
4915 MMPLAYER_VIDEO_BO_LOCK(player);
4917 if ((!player->video_bo_list) ||
4918 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4920 /* create bo list */
4922 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4924 if (player->video_bo_list) {
4925 /* if bo list did not created all, try it again. */
4926 idx = g_list_length(player->video_bo_list);
4927 LOGD("bo list exist(len: %d)", idx);
4930 for (; idx < player->ini.num_of_video_bo; idx++) {
4931 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4933 LOGE("Fail to alloc bo_info.");
4936 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4938 LOGE("Fail to tbm_bo_alloc.");
4942 bo_info->using = FALSE;
4943 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4946 /* update video num buffers */
4947 player->video_num_buffers = idx;
4948 if (idx == player->ini.num_of_video_bo)
4949 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4952 MMPLAYER_VIDEO_BO_UNLOCK(player);
4956 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4960 /* get bo from list*/
4961 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4962 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4963 if (tmp && (tmp->using == FALSE)) {
4964 LOGD("found bo %p to use", tmp->bo);
4966 MMPLAYER_VIDEO_BO_UNLOCK(player);
4967 return tbm_bo_ref(tmp->bo);
4971 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4972 MMPLAYER_VIDEO_BO_UNLOCK(player);
4976 if (player->ini.video_bo_timeout <= 0) {
4977 MMPLAYER_VIDEO_BO_WAIT(player);
4979 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4980 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4987 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4989 mm_player_t* player = (mm_player_t*)data;
4991 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4993 /* send prerolled pkt */
4994 player->video_stream_prerolled = FALSE;
4996 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4998 /* not to send prerolled pkt again */
4999 player->video_stream_prerolled = TRUE;
5003 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5005 mm_player_t* player = (mm_player_t*)data;
5006 GstCaps *caps = NULL;
5007 MMPlayerVideoStreamDataType *stream = NULL;
5008 MMVideoBuffer *video_buffer = NULL;
5009 GstMemory *dataBlock = NULL;
5010 GstMemory *metaBlock = NULL;
5011 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5012 GstStructure *structure = NULL;
5013 const gchar *string_format = NULL;
5014 unsigned int fourcc = 0;
5017 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5019 if (player->video_stream_prerolled) {
5020 player->video_stream_prerolled = FALSE;
5021 LOGD("skip the prerolled pkt not to send it again");
5025 caps = gst_pad_get_current_caps(pad);
5027 LOGE("Caps is NULL.");
5031 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5033 /* clear stream data structure */
5034 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5036 LOGE("failed to alloc mem for video data");
5040 structure = gst_caps_get_structure(caps, 0);
5041 gst_structure_get_int(structure, "width", &(stream->width));
5042 gst_structure_get_int(structure, "height", &(stream->height));
5043 string_format = gst_structure_get_string(structure, "format");
5045 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5046 stream->format = util_get_pixtype(fourcc);
5047 gst_caps_unref(caps);
5051 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5052 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5055 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5056 LOGE("Wrong condition!!");
5060 /* set size and timestamp */
5061 dataBlock = gst_buffer_peek_memory(buffer, 0);
5062 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5063 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5065 /* check zero-copy */
5066 if (player->set_mode.video_zc &&
5067 player->set_mode.media_packet_video_stream &&
5068 gst_buffer_n_memory(buffer) > 1) {
5069 metaBlock = gst_buffer_peek_memory(buffer, 1);
5070 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5071 video_buffer = (MMVideoBuffer *)mapinfo.data;
5074 if (video_buffer) { /* hw codec */
5076 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5079 /* copy pointer of tbm bo, stride, elevation */
5080 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5081 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5085 LOGE("Not support video buffer format");
5088 memcpy(stream->stride, video_buffer->stride_width,
5089 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5090 memcpy(stream->elevation, video_buffer->stride_height,
5091 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5093 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5094 stream->internal_buffer = gst_buffer_ref(buffer);
5095 } else { /* sw codec */
5099 int ret = TBM_SURFACE_ERROR_NONE;
5100 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5101 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5103 unsigned char *src = NULL;
5104 unsigned char *dest = NULL;
5105 tbm_bo_handle thandle;
5106 tbm_surface_h surface;
5107 tbm_surface_info_s info;
5110 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5112 LOGE("fail to gst_memory_map");
5117 if (stream->format == MM_PIXEL_FORMAT_I420) {
5118 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5120 ret = tbm_surface_get_info(surface, &info);
5122 if (ret != TBM_SURFACE_ERROR_NONE) {
5123 tbm_surface_destroy(surface);
5126 tbm_surface_destroy(surface);
5128 src_stride[0] = GST_ROUND_UP_4(stream->width);
5129 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5130 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5131 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5132 stream->stride[0] = info.planes[0].stride;
5133 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5134 stream->stride[1] = info.planes[1].stride;
5135 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5136 stream->stride[2] = info.planes[2].stride;
5137 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5138 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5139 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5140 stream->stride[0] = stream->width * 4;
5141 stream->elevation[0] = stream->height;
5142 size = stream->stride[0] * stream->height;
5144 LOGE("Not support format %d", stream->format);
5148 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5149 if (!stream->bo[0]) {
5150 LOGE("Fail to tbm_bo_alloc!!");
5154 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5155 if (thandle.ptr && mapinfo.data) {
5156 if (stream->format == MM_PIXEL_FORMAT_I420) {
5157 for (i = 0; i < 3; i++) {
5158 src = mapinfo.data + src_offset[i];
5159 dest = thandle.ptr + info.planes[i].offset;
5162 for (j = 0; j < stream->height>>k; j++) {
5163 memcpy(dest, src, stream->width>>k);
5164 src += src_stride[i];
5165 dest += stream->stride[i];
5168 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5169 memcpy(thandle.ptr, mapinfo.data, size);
5171 LOGE("Not support format %d", stream->format);
5175 LOGE("data pointer is wrong. dest : %p, src : %p",
5176 thandle.ptr, mapinfo.data);
5179 tbm_bo_unmap(stream->bo[0]);
5182 if (player->video_stream_cb) { /* This has been already checked at the entry */
5183 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5184 LOGE("failed to send video stream data.");
5190 gst_memory_unmap(metaBlock, &mapinfo);
5192 gst_memory_unmap(dataBlock, &mapinfo);
5197 LOGE("release video stream resource.");
5200 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5202 tbm_bo_unref(stream->bo[i]);
5204 gst_memory_unmap(metaBlock, &mapinfo);
5206 /* unref gst buffer */
5207 if (stream->internal_buffer)
5208 gst_buffer_unref(stream->internal_buffer);
5209 } else if (dataBlock) {
5211 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5212 gst_memory_unmap(dataBlock, &mapinfo);
5220 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5222 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5223 GList* element_bucket = NULL;
5225 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5229 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5230 LOGD("do not need to add video filters.");
5231 return MM_ERROR_NONE;
5234 /* in case of sw codec except 360 playback,
5235 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5236 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5237 LOGD("using video converter: %s", video_csc);
5239 /* set video rotator */
5240 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5242 *bucket = element_bucket;
5244 return MM_ERROR_NONE;
5246 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5247 g_list_free(element_bucket);
5251 return MM_ERROR_PLAYER_INTERNAL;
5255 * This function is to create video pipeline.
5257 * @param player [in] handle of player
5258 * caps [in] src caps of decoder
5259 * surface_type [in] surface type for video rendering
5261 * @return This function returns zero on success.
5263 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5267 * - video overlay surface(arm/x86) : tizenwlsink
5270 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5274 GList*element_bucket = NULL;
5275 MMPlayerGstElement* first_element = NULL;
5276 MMPlayerGstElement* videobin = NULL;
5277 gchar *videosink_element = NULL;
5281 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5284 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5286 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5288 player->pipeline->videobin = videobin;
5290 attrs = MMPLAYER_GET_ATTRS(player);
5292 LOGE("cannot get content attribute");
5293 return MM_ERROR_PLAYER_INTERNAL;
5297 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5298 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5299 if (!videobin[MMPLAYER_V_BIN].gst) {
5300 LOGE("failed to create videobin");
5304 int enable_video_decoded_cb = 0;
5305 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5307 if (player->is_360_feature_enabled && player->is_content_spherical) {
5308 LOGD("video360 elem will be added.");
5310 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5311 "video-360", TRUE, player);
5313 /* Set spatial media metadata and/or user settings to the element.
5315 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5316 "projection-type", player->video360_metadata.projection_type, NULL);
5318 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5319 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5321 if (player->video360_metadata.full_pano_width_pixels &&
5322 player->video360_metadata.full_pano_height_pixels &&
5323 player->video360_metadata.cropped_area_image_width &&
5324 player->video360_metadata.cropped_area_image_height) {
5325 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5326 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5327 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5328 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5329 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5330 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5331 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5335 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5336 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5337 "horizontal-fov", player->video360_horizontal_fov,
5338 "vertical-fov", player->video360_vertical_fov, NULL);
5341 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5343 "zoom", 1.0f / player->video360_zoom, NULL);
5346 if (player->video360_yaw_radians <= M_PI &&
5347 player->video360_yaw_radians >= -M_PI &&
5348 player->video360_pitch_radians <= M_PI_2 &&
5349 player->video360_pitch_radians >= -M_PI_2) {
5350 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5351 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5352 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5353 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5354 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5355 "pose-yaw", player->video360_metadata.init_view_heading,
5356 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5359 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5360 "passthrough", !player->is_video360_enabled, NULL);
5363 /* set video sink */
5364 switch (surface_type) {
5365 case MM_DISPLAY_SURFACE_OVERLAY:
5366 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5368 if (strlen(player->ini.videosink_element_overlay) > 0)
5369 videosink_element = player->ini.videosink_element_overlay;
5373 case MM_DISPLAY_SURFACE_NULL:
5374 if (strlen(player->ini.videosink_element_fake) > 0)
5375 videosink_element = player->ini.videosink_element_fake;
5379 case MM_DISPLAY_SURFACE_REMOTE:
5380 if (strlen(player->ini.videosink_element_fake) > 0)
5381 videosink_element = player->ini.videosink_element_fake;
5386 LOGE("unidentified surface type");
5389 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5391 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5393 /* additional setting for sink plug-in */
5394 switch (surface_type) {
5395 case MM_DISPLAY_SURFACE_OVERLAY:
5397 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5399 LOGD("selected videosink name: %s", videosink_element);
5401 /* support shard memory with S/W codec on HawkP */
5402 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5403 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5404 "use-tbm", use_tbm, NULL);
5410 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5413 LOGD("disable last-sample");
5414 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5418 if (player->set_mode.media_packet_video_stream) {
5420 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5422 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5424 MMPLAYER_SIGNAL_CONNECT(player,
5425 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5426 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5428 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5431 MMPLAYER_SIGNAL_CONNECT(player,
5432 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5433 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5435 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5440 case MM_DISPLAY_SURFACE_REMOTE:
5442 if (player->set_mode.media_packet_video_stream) {
5443 LOGE("add data probe at videosink");
5444 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5445 "sync", TRUE, "signal-handoffs", TRUE, NULL);
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_render_cb),
5454 MMPLAYER_SIGNAL_CONNECT(player,
5455 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5456 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5458 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5463 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5466 LOGD("disable last-sample");
5467 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5477 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5480 if (videobin[MMPLAYER_V_SINK].gst) {
5481 GstPad *sink_pad = NULL;
5482 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5484 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5485 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5486 gst_object_unref(GST_OBJECT(sink_pad));
5488 LOGW("failed to get sink pad from videosink\n");
5491 /* store it as it's sink element */
5492 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5494 /* adding created elements to bin */
5495 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5496 LOGE("failed to add elements\n");
5500 /* Linking elements in the bucket by added order */
5501 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5502 LOGE("failed to link elements\n");
5506 /* get first element's sinkpad for creating ghostpad */
5508 first_element = (MMPlayerGstElement *)element_bucket->data;
5509 if (!first_element) {
5510 LOGE("failed to get first element from bucket\n");
5514 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5516 LOGE("failed to get pad from first element\n");
5520 /* create ghostpad */
5521 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5522 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5523 LOGE("failed to add ghostpad to videobin\n");
5526 gst_object_unref(pad);
5528 /* done. free allocated variables */
5530 g_list_free(element_bucket);
5534 return MM_ERROR_NONE;
5537 LOGE("ERROR : releasing videobin\n");
5539 g_list_free(element_bucket);
5542 gst_object_unref(GST_OBJECT(pad));
5544 /* release videobin with it's childs */
5545 if (videobin[MMPLAYER_V_BIN].gst)
5546 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5549 MMPLAYER_FREEIF(videobin);
5551 player->pipeline->videobin = NULL;
5553 return MM_ERROR_PLAYER_INTERNAL;
5556 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5558 GList *element_bucket = NULL;
5559 MMPlayerGstElement *textbin = player->pipeline->textbin;
5561 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5562 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5563 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5564 "signal-handoffs", FALSE,
5567 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5568 MMPLAYER_SIGNAL_CONNECT(player,
5569 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5570 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5572 G_CALLBACK(__mmplayer_update_subtitle),
5575 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5576 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5577 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5579 if (!player->play_subtitle) {
5580 LOGD("add textbin sink as sink element of whole pipeline.\n");
5581 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5584 /* adding created elements to bin */
5585 LOGD("adding created elements to bin\n");
5586 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5587 LOGE("failed to add elements\n");
5591 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5592 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5593 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5595 /* linking elements in the bucket by added order. */
5596 LOGD("Linking elements in the bucket by added order.\n");
5597 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5598 LOGE("failed to link elements\n");
5602 /* done. free allocated variables */
5603 g_list_free(element_bucket);
5605 if (textbin[MMPLAYER_T_QUEUE].gst) {
5607 GstPad *ghostpad = NULL;
5609 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5611 LOGE("failed to get sink pad of text queue");
5615 ghostpad = gst_ghost_pad_new("text_sink", pad);
5616 gst_object_unref(pad);
5619 LOGE("failed to create ghostpad of textbin\n");
5623 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5624 LOGE("failed to add ghostpad to textbin\n");
5625 gst_object_unref(ghostpad);
5630 return MM_ERROR_NONE;
5633 g_list_free(element_bucket);
5635 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5636 LOGE("remove textbin sink from sink list");
5637 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5640 /* release element at __mmplayer_gst_create_text_sink_bin */
5641 return MM_ERROR_PLAYER_INTERNAL;
5644 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5646 MMPlayerGstElement *textbin = NULL;
5647 GList *element_bucket = NULL;
5648 int surface_type = 0;
5653 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5656 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5658 LOGE("failed to allocate memory for textbin\n");
5659 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5663 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5664 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5665 if (!textbin[MMPLAYER_T_BIN].gst) {
5666 LOGE("failed to create textbin\n");
5671 player->pipeline->textbin = textbin;
5674 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5675 LOGD("surface type for subtitle : %d", surface_type);
5676 switch (surface_type) {
5677 case MM_DISPLAY_SURFACE_OVERLAY:
5678 case MM_DISPLAY_SURFACE_NULL:
5679 case MM_DISPLAY_SURFACE_REMOTE:
5680 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5681 LOGE("failed to make plain text elements\n");
5692 return MM_ERROR_NONE;
5696 LOGD("ERROR : releasing textbin\n");
5698 g_list_free(element_bucket);
5700 /* release signal */
5701 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5703 /* release element which are not added to bin */
5704 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5705 /* NOTE : skip bin */
5706 if (textbin[i].gst) {
5707 GstObject* parent = NULL;
5708 parent = gst_element_get_parent(textbin[i].gst);
5711 gst_object_unref(GST_OBJECT(textbin[i].gst));
5712 textbin[i].gst = NULL;
5714 gst_object_unref(GST_OBJECT(parent));
5719 /* release textbin with it's childs */
5720 if (textbin[MMPLAYER_T_BIN].gst)
5721 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5723 MMPLAYER_FREEIF(player->pipeline->textbin);
5724 player->pipeline->textbin = NULL;
5727 return MM_ERROR_PLAYER_INTERNAL;
5732 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5734 MMPlayerGstElement* mainbin = NULL;
5735 MMPlayerGstElement* textbin = NULL;
5736 MMHandleType attrs = 0;
5737 GstElement *subsrc = NULL;
5738 GstElement *subparse = NULL;
5739 gchar *subtitle_uri = NULL;
5740 const gchar *charset = NULL;
5746 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5748 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5750 mainbin = player->pipeline->mainbin;
5752 attrs = MMPLAYER_GET_ATTRS(player);
5754 LOGE("cannot get content attribute\n");
5755 return MM_ERROR_PLAYER_INTERNAL;
5758 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5759 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5760 LOGE("subtitle uri is not proper filepath.\n");
5761 return MM_ERROR_PLAYER_INVALID_URI;
5764 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5765 LOGE("failed to get storage info of subtitle path");
5766 return MM_ERROR_PLAYER_INVALID_URI;
5769 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5771 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5772 player->subtitle_language_list = NULL;
5773 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5775 /* create the subtitle source */
5776 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5778 LOGE("failed to create filesrc element\n");
5781 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5783 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5784 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5786 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5787 LOGW("failed to add queue\n");
5788 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5789 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5790 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5795 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5797 LOGE("failed to create subparse element\n");
5801 charset = util_get_charset(subtitle_uri);
5803 LOGD("detected charset is %s\n", charset);
5804 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5807 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5808 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5810 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5811 LOGW("failed to add subparse\n");
5812 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5813 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5814 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5818 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5819 LOGW("failed to link subsrc and subparse\n");
5823 player->play_subtitle = TRUE;
5824 player->adjust_subtitle_pos = 0;
5826 LOGD("play subtitle using subtitle file\n");
5828 if (player->pipeline->textbin == NULL) {
5829 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5830 LOGE("failed to create text sink bin. continuing without text\n");
5834 textbin = player->pipeline->textbin;
5836 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5837 LOGW("failed to add textbin\n");
5839 /* release signal */
5840 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5842 /* release textbin with it's childs */
5843 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5844 MMPLAYER_FREEIF(player->pipeline->textbin);
5845 player->pipeline->textbin = textbin = NULL;
5849 LOGD("link text input selector and textbin ghost pad");
5851 player->textsink_linked = 1;
5852 player->external_text_idx = 0;
5853 LOGI("player->textsink_linked set to 1\n");
5855 textbin = player->pipeline->textbin;
5856 LOGD("text bin has been created. reuse it.");
5857 player->external_text_idx = 1;
5860 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5861 LOGW("failed to link subparse and textbin\n");
5865 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5867 LOGE("failed to get sink pad from textsink to probe data");
5871 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5872 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5874 gst_object_unref(pad);
5877 /* create dot. for debugging */
5878 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5881 return MM_ERROR_NONE;
5884 /* release text pipeline resource */
5885 player->textsink_linked = 0;
5887 /* release signal */
5888 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5890 if (player->pipeline->textbin) {
5891 LOGE("remove textbin");
5893 /* release textbin with it's childs */
5894 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5895 MMPLAYER_FREEIF(player->pipeline->textbin);
5896 player->pipeline->textbin = NULL;
5900 /* release subtitle elem */
5901 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5902 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5904 return MM_ERROR_PLAYER_INTERNAL;
5908 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5910 mm_player_t* player = (mm_player_t*) data;
5911 MMMessageParamType msg = {0, };
5912 GstClockTime duration = 0;
5913 gpointer text = NULL;
5914 guint text_size = 0;
5915 gboolean ret = TRUE;
5916 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5920 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5921 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5923 if (player->is_subtitle_force_drop) {
5924 LOGW("subtitle is dropped forcedly.");
5928 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5929 text = mapinfo.data;
5930 text_size = mapinfo.size;
5931 duration = GST_BUFFER_DURATION(buffer);
5933 if (player->set_mode.subtitle_off) {
5934 LOGD("subtitle is OFF.\n");
5938 if (!text || (text_size == 0)) {
5939 LOGD("There is no subtitle to be displayed.\n");
5943 msg.data = (void *) text;
5944 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5946 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5948 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5949 gst_buffer_unmap(buffer, &mapinfo);
5956 static GstPadProbeReturn
5957 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5959 mm_player_t *player = (mm_player_t *) u_data;
5960 GstClockTime cur_timestamp = 0;
5961 gint64 adjusted_timestamp = 0;
5962 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5964 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5966 if (player->set_mode.subtitle_off) {
5967 LOGD("subtitle is OFF.\n");
5971 if (player->adjust_subtitle_pos == 0) {
5972 LOGD("nothing to do");
5976 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5977 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5979 if (adjusted_timestamp < 0) {
5980 LOGD("adjusted_timestamp under zero");
5985 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5986 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5987 GST_TIME_ARGS(cur_timestamp),
5988 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5990 return GST_PAD_PROBE_OK;
5992 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5996 /* check player and subtitlebin are created */
5997 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5998 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
6000 if (position == 0) {
6001 LOGD("nothing to do\n");
6003 return MM_ERROR_NONE;
6007 case MM_PLAYER_POS_FORMAT_TIME:
6009 /* check current postion */
6010 player->adjust_subtitle_pos = position;
6012 LOGD("save adjust_subtitle_pos in player") ;
6018 LOGW("invalid format.\n");
6020 return MM_ERROR_INVALID_ARGUMENT;
6026 return MM_ERROR_NONE;
6028 static int __gst_adjust_video_position(mm_player_t* player, int offset)
6031 LOGD("adjusting video_pos in player") ;
6032 int current_pos = 0;
6033 /* check player and videobin are created */
6034 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6035 if (!player->pipeline->videobin ||
6036 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
6037 LOGD("no video pipeline or sink is there");
6038 return MM_ERROR_PLAYER_INVALID_STATE ;
6041 LOGD("nothing to do\n");
6043 return MM_ERROR_NONE;
6045 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6046 LOGD("failed to get current position");
6047 return MM_ERROR_PLAYER_INTERNAL;
6049 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6050 LOGD("enter video delay is valid");
6052 LOGD("enter video delay is crossing content boundary");
6053 return MM_ERROR_INVALID_ARGUMENT ;
6055 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6056 LOGD("video delay has been done");
6059 return MM_ERROR_NONE;
6063 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6065 GstElement *appsrc = element;
6066 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6067 GstBuffer *buffer = NULL;
6068 GstFlowReturn ret = GST_FLOW_OK;
6071 MMPLAYER_RETURN_IF_FAIL(element);
6072 MMPLAYER_RETURN_IF_FAIL(buf);
6074 buffer = gst_buffer_new();
6076 if (buf->offset >= buf->len) {
6077 LOGD("call eos appsrc\n");
6078 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6082 if (buf->len - buf->offset < size)
6083 len = buf->len - buf->offset;
6085 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6086 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6087 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6089 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6090 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6096 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6098 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6100 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6102 buf->offset = (int)size;
6107 static GstBusSyncReply
6108 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6110 mm_player_t *player = (mm_player_t *)data;
6111 GstBusSyncReply reply = GST_BUS_DROP;
6113 if (!(player->pipeline && player->pipeline->mainbin)) {
6114 LOGE("player pipeline handle is null");
6115 return GST_BUS_PASS;
6118 if (!__mmplayer_check_useful_message(player, message)) {
6119 gst_message_unref(message);
6120 return GST_BUS_DROP;
6123 switch (GST_MESSAGE_TYPE(message)) {
6124 case GST_MESSAGE_STATE_CHANGED:
6125 /* post directly for fast launch */
6126 if (player->sync_handler) {
6127 __mmplayer_gst_callback(message, player);
6128 reply = GST_BUS_DROP;
6130 reply = GST_BUS_PASS;
6132 case GST_MESSAGE_TAG:
6133 __mmplayer_gst_extract_tag_from_msg(player, message);
6137 GstTagList *tags = NULL;
6139 gst_message_parse_tag(message, &tags);
6141 LOGE("TAGS received from element \"%s\".\n",
6142 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6144 gst_tag_list_foreach(tags, print_tag, NULL);
6145 gst_tag_list_free(tags);
6153 case GST_MESSAGE_DURATION_CHANGED:
6154 __mmplayer_gst_handle_duration(player, message);
6156 case GST_MESSAGE_ASYNC_DONE:
6157 /* NOTE:Don't call gst_callback directly
6158 * because previous frame can be showed even though this message is received for seek.
6161 reply = GST_BUS_PASS;
6165 if (reply == GST_BUS_DROP)
6166 gst_message_unref(message);
6172 __mmplayer_gst_create_decoder(mm_player_t *player,
6173 MMPlayerTrackType track,
6175 enum MainElementID elemId,
6178 gboolean ret = TRUE;
6179 GstPad *sinkpad = NULL;
6183 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6185 player->pipeline->mainbin, FALSE);
6186 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6187 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6188 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6190 GstElement *decodebin = NULL;
6191 GstCaps *dec_caps = NULL;
6193 /* create decodebin */
6194 decodebin = gst_element_factory_make("decodebin", name);
6197 LOGE("error : fail to create decodebin for %d decoder\n", track);
6202 /* raw pad handling signal */
6203 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6204 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6206 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6207 before looking for any elements that can handle that stream.*/
6208 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6209 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6211 /* This signal is emitted when a element is added to the bin.*/
6212 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6213 G_CALLBACK(__mmplayer_gst_element_added), player);
6215 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6216 LOGE("failed to add new decodebin\n");
6221 dec_caps = gst_pad_query_caps(srcpad, NULL);
6223 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6224 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6225 gst_caps_unref(dec_caps);
6228 player->pipeline->mainbin[elemId].id = elemId;
6229 player->pipeline->mainbin[elemId].gst = decodebin;
6231 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6233 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6234 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6235 gst_object_unref(GST_OBJECT(decodebin));
6238 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6239 LOGE("failed to sync second level decodebin state with parent\n");
6241 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6245 gst_object_unref(GST_OBJECT(sinkpad));
6254 * This function is to create audio or video pipeline for playing.
6256 * @param player [in] handle of player
6258 * @return This function returns zero on success.
6263 __mmplayer_gst_create_pipeline(mm_player_t* player)
6266 MMPlayerGstElement *mainbin = NULL;
6267 MMHandleType attrs = 0;
6268 GstElement* element = NULL;
6269 GstElement* elem_src_audio = NULL;
6270 GstElement* elem_src_subtitle = NULL;
6271 GstElement* es_video_queue = NULL;
6272 GstElement* es_audio_queue = NULL;
6273 GstElement* es_subtitle_queue = NULL;
6274 GList* element_bucket = NULL;
6275 gboolean need_state_holder = TRUE;
6277 #ifdef SW_CODEC_ONLY
6278 int surface_type = 0;
6282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6284 /* get profile attribute */
6285 attrs = MMPLAYER_GET_ATTRS(player);
6287 LOGE("cannot get content attribute\n");
6291 /* create pipeline handles */
6292 if (player->pipeline) {
6293 LOGW("pipeline should be released before create new one\n");
6297 player->video360_metadata.is_spherical = -1;
6298 player->is_openal_plugin_used = FALSE;
6300 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6301 if (player->pipeline == NULL)
6304 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6306 /* create mainbin */
6307 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6308 if (mainbin == NULL)
6311 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6313 /* create pipeline */
6314 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6315 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6316 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6317 LOGE("failed to create pipeline\n");
6320 player->demux_pad_index = 0;
6321 player->subtitle_language_list = NULL;
6323 player->is_subtitle_force_drop = FALSE;
6324 player->last_multiwin_status = FALSE;
6326 _mmplayer_track_initialize(player);
6327 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6329 /* create source element */
6330 switch (player->profile.uri_type) {
6331 /* rtsp streamming */
6332 case MM_PLAYER_URI_TYPE_URL_RTSP:
6336 element = gst_element_factory_make("rtspsrc", "rtsp source");
6339 LOGE("failed to create streaming source element\n");
6347 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6349 SECURE_LOGD("user_agent : %s\n", user_agent);
6351 /* setting property to streaming source */
6352 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6354 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6356 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6357 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6358 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6359 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6364 case MM_PLAYER_URI_TYPE_URL_HTTP:
6366 gchar *user_agent, *cookies, **cookie_list;
6367 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6368 user_agent = cookies = NULL;
6370 gint mode = MM_PLAYER_PD_MODE_NONE;
6372 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6374 player->pd_mode = mode;
6376 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6378 if (!MMPLAYER_IS_HTTP_PD(player)) {
6379 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6381 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6384 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6387 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6388 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6390 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6391 LOGD("get timeout from ini\n");
6392 http_timeout = player->ini.http_timeout;
6396 SECURE_LOGD("location : %s\n", player->profile.uri);
6397 SECURE_LOGD("cookies : %s\n", cookies);
6398 SECURE_LOGD("user_agent : %s\n", user_agent);
6399 LOGD("timeout : %d\n", http_timeout);
6401 /* setting property to streaming source */
6402 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6403 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6404 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6406 /* parsing cookies */
6407 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6408 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6409 g_strfreev(cookie_list);
6412 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6414 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6415 LOGW("it's dash. and it's still experimental feature.");
6417 // progressive download
6418 gchar* location = NULL;
6420 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6423 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6425 MMPLAYER_FREEIF(player->pd_file_save_path);
6427 LOGD("PD Location : %s\n", path);
6430 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6431 LOGE("failed to get storage info");
6434 player->pd_file_save_path = g_strdup(path);
6436 LOGE("can't find pd location so, it should be set \n");
6441 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6443 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6447 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6448 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6450 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6451 g_object_get(element, "location", &location, NULL);
6452 LOGD("PD_LOCATION [%s].\n", location);
6460 case MM_PLAYER_URI_TYPE_FILE:
6462 LOGD("using filesrc for 'file://' handler.\n");
6463 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6464 LOGE("failed to get storage info");
6468 element = gst_element_factory_make("filesrc", "source");
6470 LOGE("failed to create filesrc\n");
6474 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6478 case MM_PLAYER_URI_TYPE_SS:
6480 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6481 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6483 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6487 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6488 LOGD("get timeout from ini\n");
6489 http_timeout = player->ini.http_timeout;
6492 /* setting property to streaming source */
6493 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6494 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6497 case MM_PLAYER_URI_TYPE_MS_BUFF:
6499 LOGD("MS buff src is selected\n");
6501 if (player->v_stream_caps) {
6502 element = gst_element_factory_make("appsrc", "video_appsrc");
6504 LOGF("failed to create video app source element[appsrc].\n");
6508 if (player->a_stream_caps) {
6509 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6510 if (!elem_src_audio) {
6511 LOGF("failed to create audio app source element[appsrc].\n");
6515 } else if (player->a_stream_caps) {
6516 /* no video, only audio pipeline*/
6517 element = gst_element_factory_make("appsrc", "audio_appsrc");
6519 LOGF("failed to create audio app source element[appsrc].\n");
6524 if (player->s_stream_caps) {
6525 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6526 if (!elem_src_subtitle) {
6527 LOGF("failed to create subtitle app source element[appsrc].\n");
6532 LOGD("setting app sources properties.\n");
6533 LOGD("location : %s\n", player->profile.uri);
6535 if (player->v_stream_caps && element) {
6536 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6537 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6538 "caps", player->v_stream_caps, NULL);
6540 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6541 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6542 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6543 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6545 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6546 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6547 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6548 G_CALLBACK(__gst_seek_video_data), player);
6550 if (player->a_stream_caps && elem_src_audio) {
6551 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6552 "caps", player->a_stream_caps, NULL);
6554 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6555 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6556 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6557 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6559 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6560 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6561 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6562 G_CALLBACK(__gst_seek_audio_data), player);
6564 } else if (player->a_stream_caps && element) {
6565 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6566 "caps", player->a_stream_caps, NULL);
6568 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6569 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6570 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6571 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6573 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6574 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6575 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6576 G_CALLBACK(__gst_seek_audio_data), player);
6579 if (player->s_stream_caps && elem_src_subtitle) {
6580 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6581 "caps", player->s_stream_caps, NULL);
6583 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6584 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6585 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6586 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6588 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6590 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6591 G_CALLBACK(__gst_seek_subtitle_data), player);
6594 if (player->v_stream_caps && element) {
6595 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6596 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6597 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6598 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6600 if (player->a_stream_caps && elem_src_audio) {
6601 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6602 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6603 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6604 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6606 } else if (player->a_stream_caps && element) {
6607 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6608 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6609 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6610 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6613 if (player->s_stream_caps && elem_src_subtitle)
6614 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6615 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6617 need_state_holder = FALSE;
6619 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6620 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6621 LOGE("failed to commit\n");
6625 case MM_PLAYER_URI_TYPE_MEM:
6627 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6629 LOGD("mem src is selected\n");
6631 element = gst_element_factory_make("appsrc", "mem-source");
6633 LOGE("failed to create appsrc element\n");
6637 g_object_set(element, "stream-type", stream_type, NULL);
6638 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6639 g_object_set(element, "blocksize", (guint64)20480, NULL);
6641 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6642 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6643 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6644 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6647 case MM_PLAYER_URI_TYPE_URL:
6650 case MM_PLAYER_URI_TYPE_TEMP:
6653 case MM_PLAYER_URI_TYPE_NONE:
6658 /* check source element is OK */
6660 LOGE("no source element was created.\n");
6664 /* take source element */
6665 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6666 mainbin[MMPLAYER_M_SRC].gst = element;
6667 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6669 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6670 player->streamer = __mm_player_streaming_create();
6671 __mm_player_streaming_initialize(player->streamer);
6674 if (MMPLAYER_IS_HTTP_PD(player)) {
6675 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6677 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6678 element = gst_element_factory_make("queue2", "queue2");
6680 LOGE("failed to create http streaming buffer element\n");
6685 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6686 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6687 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6689 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6691 player->streamer->is_pd_mode = TRUE;
6693 __mm_player_streaming_set_queue2(player->streamer,
6696 player->ini.http_max_size_bytes + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6699 player->ini.http_buffering_limit,
6700 MUXED_BUFFER_TYPE_MEM_QUEUE,
6704 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6705 if (player->v_stream_caps) {
6706 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6707 if (!es_video_queue) {
6708 LOGE("create es_video_queue for es player failed\n");
6711 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6712 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6713 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6714 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6716 /* Adding audio appsrc to bucket */
6717 if (player->a_stream_caps && elem_src_audio) {
6718 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6719 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6720 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6722 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6723 if (!es_audio_queue) {
6724 LOGE("create es_audio_queue for es player failed\n");
6727 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6729 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6730 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6731 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6733 } else if (player->a_stream_caps) {
6734 /* Only audio stream, no video */
6735 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6736 if (!es_audio_queue) {
6737 LOGE("create es_audio_queue for es player failed\n");
6740 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6741 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6742 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6745 if (player->s_stream_caps && elem_src_subtitle) {
6746 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6747 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6748 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6750 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6751 if (!es_subtitle_queue) {
6752 LOGE("create es_subtitle_queue for es player failed\n");
6755 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6756 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6757 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6761 /* create autoplugging element if src element is not a rtsp src */
6762 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6763 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6765 enum MainElementID elemId = MMPLAYER_M_NUM;
6767 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6768 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6769 elemId = MMPLAYER_M_AUTOPLUG;
6770 element = __mmplayer_create_decodebin(player);
6772 /* default size of mq in decodebin is 2M
6773 * but it can cause blocking issue during seeking depends on content. */
6774 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6776 need_state_holder = FALSE;
6778 elemId = MMPLAYER_M_TYPEFIND;
6779 element = gst_element_factory_make("typefind", "typefinder");
6780 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6781 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6785 /* check autoplug element is OK */
6787 LOGE("can not create element(%d)\n", elemId);
6791 mainbin[elemId].id = elemId;
6792 mainbin[elemId].gst = element;
6794 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6797 /* add elements to pipeline */
6798 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6799 LOGE("Failed to add elements to pipeline\n");
6804 /* linking elements in the bucket by added order. */
6805 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6806 LOGE("Failed to link some elements\n");
6811 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6812 if (need_state_holder) {
6814 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6815 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6817 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6818 LOGE("fakesink element could not be created\n");
6821 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6823 /* take ownership of fakesink. we are reusing it */
6824 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6827 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6828 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6829 LOGE("failed to add fakesink to bin\n");
6834 /* now we have completed mainbin. take it */
6835 player->pipeline->mainbin = mainbin;
6837 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6838 GstPad *srcpad = NULL;
6840 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6841 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6843 __mmplayer_gst_create_decoder(player,
6844 MM_PLAYER_TRACK_TYPE_VIDEO,
6846 MMPLAYER_M_AUTOPLUG_V_DEC,
6849 gst_object_unref(GST_OBJECT(srcpad));
6854 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6855 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6857 __mmplayer_gst_create_decoder(player,
6858 MM_PLAYER_TRACK_TYPE_AUDIO,
6860 MMPLAYER_M_AUTOPLUG_A_DEC,
6863 gst_object_unref(GST_OBJECT(srcpad));
6868 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6869 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6872 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6873 if (__mmplayer_check_subtitle(player)) {
6874 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6875 LOGE("fail to create text pipeline");
6878 /* connect bus callback */
6879 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6881 LOGE("cannot get bus from pipeline.\n");
6885 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6887 player->context.thread_default = g_main_context_get_thread_default();
6889 if (player->context.thread_default == NULL) {
6890 player->context.thread_default = g_main_context_default();
6891 LOGD("thread-default context is the global default context");
6893 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6895 /* set sync handler to get tag synchronously */
6896 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6899 gst_object_unref(GST_OBJECT(bus));
6900 g_list_free(element_bucket);
6902 /* create gst bus_msb_cb thread */
6903 g_mutex_init(&player->bus_msg_thread_mutex);
6904 g_cond_init(&player->bus_msg_thread_cond);
6905 player->bus_msg_thread_exit = FALSE;
6906 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6907 player->bus_msg_thread =
6908 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6909 if (!player->bus_msg_thread) {
6910 LOGE("failed to create gst BUS msg thread");
6911 g_mutex_clear(&player->bus_msg_thread_mutex);
6912 g_cond_clear(&player->bus_msg_thread_cond);
6918 return MM_ERROR_NONE;
6921 __mmplayer_gst_destroy_pipeline(player);
6922 g_list_free(element_bucket);
6925 /* release element which are not added to bin */
6926 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6927 /* NOTE : skip pipeline */
6928 if (mainbin[i].gst) {
6929 GstObject* parent = NULL;
6930 parent = gst_element_get_parent(mainbin[i].gst);
6933 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6934 mainbin[i].gst = NULL;
6936 gst_object_unref(GST_OBJECT(parent));
6940 /* release pipeline with it's childs */
6941 if (mainbin[MMPLAYER_M_PIPE].gst)
6942 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6944 MMPLAYER_FREEIF(mainbin);
6947 MMPLAYER_FREEIF(player->pipeline);
6948 return MM_ERROR_PLAYER_INTERNAL;
6952 __mmplayer_reset_gapless_state(mm_player_t* player)
6955 MMPLAYER_RETURN_IF_FAIL(player
6957 && player->pipeline->audiobin
6958 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6960 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6967 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6970 int ret = MM_ERROR_NONE;
6974 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6976 /* cleanup stuffs */
6977 MMPLAYER_FREEIF(player->type);
6978 player->have_dynamic_pad = FALSE;
6979 player->no_more_pad = FALSE;
6980 player->num_dynamic_pad = 0;
6981 player->demux_pad_index = 0;
6982 player->use_deinterleave = FALSE;
6983 player->max_audio_channels = 0;
6984 player->video_share_api_delta = 0;
6985 player->video_share_clock_delta = 0;
6986 player->video_hub_download_mode = 0;
6988 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6989 player->subtitle_language_list = NULL;
6990 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6992 __mmplayer_reset_gapless_state(player);
6994 if (player->streamer) {
6995 __mm_player_streaming_deinitialize(player->streamer);
6996 __mm_player_streaming_destroy(player->streamer);
6997 player->streamer = NULL;
7000 /* cleanup unlinked mime type */
7001 MMPLAYER_FREEIF(player->unlinked_audio_mime);
7002 MMPLAYER_FREEIF(player->unlinked_video_mime);
7003 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
7005 /* cleanup running stuffs */
7006 __mmplayer_cancel_eos_timer(player);
7008 /* cleanup gst stuffs */
7009 if (player->pipeline) {
7010 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
7011 GstTagList* tag_list = player->pipeline->tag_list;
7013 /* first we need to disconnect all signal hander */
7014 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
7016 if (player->bus_watcher)
7017 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
7018 player->bus_watcher = 0;
7021 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
7022 MMPlayerGstElement* videobin = player->pipeline->videobin;
7023 MMPlayerGstElement* textbin = player->pipeline->textbin;
7024 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
7025 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
7026 gst_object_unref(bus);
7028 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7029 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
7030 if (ret != MM_ERROR_NONE) {
7031 LOGE("fail to change state to NULL\n");
7032 return MM_ERROR_PLAYER_INTERNAL;
7035 LOGW("succeeded in chaning state to NULL\n");
7037 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7040 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7041 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7043 /* free avsysaudiosink
7044 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7045 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7047 MMPLAYER_FREEIF(audiobin);
7048 MMPLAYER_FREEIF(videobin);
7049 MMPLAYER_FREEIF(textbin);
7050 MMPLAYER_FREEIF(mainbin);
7054 gst_tag_list_free(tag_list);
7056 MMPLAYER_FREEIF(player->pipeline);
7058 MMPLAYER_FREEIF(player->album_art);
7060 if (player->v_stream_caps) {
7061 gst_caps_unref(player->v_stream_caps);
7062 player->v_stream_caps = NULL;
7064 if (player->a_stream_caps) {
7065 gst_caps_unref(player->a_stream_caps);
7066 player->a_stream_caps = NULL;
7069 if (player->s_stream_caps) {
7070 gst_caps_unref(player->s_stream_caps);
7071 player->s_stream_caps = NULL;
7073 _mmplayer_track_destroy(player);
7075 if (player->sink_elements)
7076 g_list_free(player->sink_elements);
7077 player->sink_elements = NULL;
7079 if (player->bufmgr) {
7080 tbm_bufmgr_deinit(player->bufmgr);
7081 player->bufmgr = NULL;
7084 LOGW("finished destroy pipeline\n");
7091 static int __gst_realize(mm_player_t* player)
7094 int ret = MM_ERROR_NONE;
7098 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7100 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7102 ret = __mmplayer_gst_create_pipeline(player);
7104 LOGE("failed to create pipeline\n");
7108 /* set pipeline state to READY */
7109 /* NOTE : state change to READY must be performed sync. */
7110 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7111 ret = __mmplayer_gst_set_state(player,
7112 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7114 if (ret != MM_ERROR_NONE) {
7115 /* return error if failed to set state */
7116 LOGE("failed to set READY state");
7120 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7122 /* create dot before error-return. for debugging */
7123 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7130 static int __gst_unrealize(mm_player_t* player)
7132 int ret = MM_ERROR_NONE;
7136 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7138 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7139 MMPLAYER_PRINT_STATE(player);
7141 /* release miscellaneous information */
7142 __mmplayer_release_misc(player);
7144 /* destroy pipeline */
7145 ret = __mmplayer_gst_destroy_pipeline(player);
7146 if (ret != MM_ERROR_NONE) {
7147 LOGE("failed to destory pipeline\n");
7151 /* release miscellaneous information.
7152 these info needs to be released after pipeline is destroyed. */
7153 __mmplayer_release_misc_post(player);
7155 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7162 static int __gst_pending_seek(mm_player_t* player)
7164 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7165 int ret = MM_ERROR_NONE;
7169 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7171 if (!player->pending_seek.is_pending) {
7172 LOGD("pending seek is not reserved. nothing to do.\n");
7176 /* check player state if player could pending seek or not. */
7177 current_state = MMPLAYER_CURRENT_STATE(player);
7179 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7180 LOGW("try to pending seek in %s state, try next time. \n",
7181 MMPLAYER_STATE_GET_NAME(current_state));
7185 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7187 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7189 if (MM_ERROR_NONE != ret)
7190 LOGE("failed to seek pending postion. just keep staying current position.\n");
7192 player->pending_seek.is_pending = FALSE;
7199 static int __gst_start(mm_player_t* player)
7201 gboolean sound_extraction = 0;
7202 int ret = MM_ERROR_NONE;
7203 gboolean async = FALSE;
7207 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7209 /* get sound_extraction property */
7210 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7212 /* NOTE : if SetPosition was called before Start. do it now */
7213 /* streaming doesn't support it. so it should be always sync */
7214 /* !!create one more api to check if there is pending seek rather than checking variables */
7215 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7216 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7217 ret = __gst_pause(player, FALSE);
7218 if (ret != MM_ERROR_NONE) {
7219 LOGE("failed to set state to PAUSED for pending seek\n");
7223 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7225 if (sound_extraction) {
7226 LOGD("setting pcm extraction\n");
7228 ret = __mmplayer_set_pcm_extraction(player);
7229 if (MM_ERROR_NONE != ret) {
7230 LOGW("failed to set pcm extraction\n");
7234 if (MM_ERROR_NONE != __gst_pending_seek(player))
7235 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7239 LOGD("current state before doing transition");
7240 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7241 MMPLAYER_PRINT_STATE(player);
7243 /* set pipeline state to PLAYING */
7244 if (player->es_player_push_mode)
7246 /* set pipeline state to PLAYING */
7247 ret = __mmplayer_gst_set_state(player,
7248 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7250 if (ret == MM_ERROR_NONE) {
7251 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7253 LOGE("failed to set state to PLAYING");
7257 /* generating debug info before returning error */
7258 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7265 static int __gst_stop(mm_player_t* player)
7267 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7268 MMHandleType attrs = 0;
7269 gboolean rewind = FALSE;
7271 int ret = MM_ERROR_NONE;
7272 gboolean async = FALSE;
7276 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7277 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7279 LOGD("current state before doing transition");
7280 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7281 MMPLAYER_PRINT_STATE(player);
7283 attrs = MMPLAYER_GET_ATTRS(player);
7285 LOGE("cannot get content attribute\n");
7286 return MM_ERROR_PLAYER_INTERNAL;
7289 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7290 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7292 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7293 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7296 if (player->es_player_push_mode)
7299 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7301 /* return if set_state has failed */
7302 if (ret != MM_ERROR_NONE) {
7303 LOGE("failed to set state.\n");
7309 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7310 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7311 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7312 LOGW("failed to rewind\n");
7313 ret = MM_ERROR_PLAYER_SEEK;
7318 player->sent_bos = FALSE;
7320 if (player->es_player_push_mode) //for cloudgame
7323 /* wait for seek to complete */
7324 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7325 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7326 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7328 LOGE("fail to stop player.\n");
7329 ret = MM_ERROR_PLAYER_INTERNAL;
7330 __mmplayer_dump_pipeline_state(player);
7333 /* generate dot file if enabled */
7334 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7341 int __gst_pause(mm_player_t* player, gboolean async)
7343 int ret = MM_ERROR_NONE;
7347 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7348 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7350 LOGD("current state before doing transition");
7351 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7352 MMPLAYER_PRINT_STATE(player);
7354 /* set pipeline status to PAUSED */
7355 ret = __mmplayer_gst_set_state(player,
7356 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7358 if (FALSE == async) {
7359 if (ret != MM_ERROR_NONE) {
7360 GstMessage *msg = NULL;
7361 GTimer *timer = NULL;
7362 gdouble MAX_TIMEOUT_SEC = 3;
7364 LOGE("failed to set state to PAUSED");
7366 if (player->msg_posted) {
7367 LOGE("error msg is already posted.");
7371 timer = g_timer_new();
7372 g_timer_start(timer);
7374 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7377 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7379 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7380 GError *error = NULL;
7382 /* parse error code */
7383 gst_message_parse_error(msg, &error, NULL);
7385 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7386 /* Note : the streaming error from the streaming source is handled
7387 * using __mmplayer_handle_streaming_error.
7389 __mmplayer_handle_streaming_error(player, msg);
7392 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7394 if (error->domain == GST_STREAM_ERROR)
7395 ret = __gst_handle_stream_error(player, error, msg);
7396 else if (error->domain == GST_RESOURCE_ERROR)
7397 ret = __gst_handle_resource_error(player, error->code, NULL);
7398 else if (error->domain == GST_LIBRARY_ERROR)
7399 ret = __gst_handle_library_error(player, error->code);
7400 else if (error->domain == GST_CORE_ERROR)
7401 ret = __gst_handle_core_error(player, error->code);
7403 g_error_free(error);
7405 player->msg_posted = TRUE;
7407 gst_message_unref(msg);
7409 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7411 gst_object_unref(bus);
7412 g_timer_stop(timer);
7413 g_timer_destroy(timer);
7417 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7418 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7420 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7422 } else if (ret == MM_ERROR_NONE) {
7424 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7428 /* generate dot file before returning error */
7429 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7436 int __gst_resume(mm_player_t* player, gboolean async)
7438 int ret = MM_ERROR_NONE;
7443 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7444 MM_ERROR_PLAYER_NOT_INITIALIZED);
7446 LOGD("current state before doing transition");
7447 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7448 MMPLAYER_PRINT_STATE(player);
7450 /* generate dot file before returning error */
7451 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7454 LOGD("do async state transition to PLAYING.\n");
7456 /* set pipeline state to PLAYING */
7457 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7459 ret = __mmplayer_gst_set_state(player,
7460 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7461 if (ret != MM_ERROR_NONE) {
7462 LOGE("failed to set state to PLAYING\n");
7465 if (async == FALSE) {
7466 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7467 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7468 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7472 /* generate dot file before returning error */
7473 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7481 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7483 unsigned long dur_msec = 0;
7484 gint64 dur_nsec = 0;
7485 gint64 pos_nsec = 0;
7486 gboolean ret = TRUE;
7487 gboolean accurated = FALSE;
7488 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7491 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7492 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7494 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7495 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7498 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7499 /* check duration */
7500 /* NOTE : duration cannot be zero except live streaming.
7501 * Since some element could have some timing problemn with quering duration, try again.
7503 if (!player->duration) {
7504 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7505 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7506 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7507 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7508 player->pending_seek.is_pending = TRUE;
7509 player->pending_seek.format = format;
7510 player->pending_seek.pos = position;
7511 player->doing_seek = FALSE;
7512 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7513 return MM_ERROR_NONE;
7518 player->duration = dur_nsec;
7521 if (player->duration) {
7522 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7524 LOGE("could not get the duration. fail to seek.\n");
7528 LOGD("playback rate: %f\n", player->playback_rate);
7530 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7532 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7534 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7538 case MM_PLAYER_POS_FORMAT_TIME:
7540 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7541 GstQuery *query = NULL;
7542 gboolean seekable = FALSE;
7544 /* check position is valid or not */
7545 if (position > dur_msec)
7548 query = gst_query_new_seeking(GST_FORMAT_TIME);
7549 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7550 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7551 gst_query_unref(query);
7554 LOGW("non-seekable content");
7555 player->doing_seek = FALSE;
7556 return MM_ERROR_PLAYER_NO_OP;
7559 LOGW("failed to get seeking query");
7560 gst_query_unref(query); /* keep seeking operation */
7563 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7565 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7566 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7567 This causes problem is position calculation during normal pause resume scenarios also.
7568 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7569 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7570 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7571 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7572 LOGW("getting current position failed in seek\n");
7574 player->last_position = pos_nsec;
7575 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7578 if (player->doing_seek) {
7579 LOGD("not completed seek");
7580 return MM_ERROR_PLAYER_DOING_SEEK;
7584 if (!internal_called)
7585 player->doing_seek = TRUE;
7587 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7589 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7590 gint64 cur_time = 0;
7592 /* get current position */
7593 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7596 GstEvent *event = gst_event_new_seek(1.0,
7598 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7599 GST_SEEK_TYPE_SET, cur_time,
7600 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7602 __gst_send_event_to_sink(player, event);
7604 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7605 __gst_pause(player, FALSE);
7608 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7609 that's why set position through property. */
7610 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7611 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7612 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7613 (!player->videodec_linked) && (!player->audiodec_linked)) {
7615 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7616 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7617 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7618 player->doing_seek = FALSE;
7619 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7621 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7622 GST_FORMAT_TIME, seek_flags,
7623 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7627 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7633 case MM_PLAYER_POS_FORMAT_PERCENT:
7635 LOGD("seeking to(%lu)%% \n", position);
7637 if (player->doing_seek) {
7638 LOGD("not completed seek");
7639 return MM_ERROR_PLAYER_DOING_SEEK;
7642 if (!internal_called)
7643 player->doing_seek = TRUE;
7645 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7646 pos_nsec = (gint64)((position * player->duration) / 100);
7647 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7648 GST_FORMAT_TIME, seek_flags,
7649 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7651 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7661 /* NOTE : store last seeking point to overcome some bad operation
7662 * (returning zero when getting current position) of some elements
7664 player->last_position = pos_nsec;
7666 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7667 if (player->playback_rate > 1.0)
7668 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7671 return MM_ERROR_NONE;
7674 player->pending_seek.is_pending = TRUE;
7675 player->pending_seek.format = format;
7676 player->pending_seek.pos = position;
7678 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7679 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7681 return MM_ERROR_NONE;
7684 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7685 return MM_ERROR_INVALID_ARGUMENT;
7688 player->doing_seek = FALSE;
7689 return MM_ERROR_PLAYER_SEEK;
7692 #define TRICKPLAY_OFFSET GST_MSECOND
7695 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7697 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7698 gint64 pos_msec = 0;
7699 gboolean ret = TRUE;
7701 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7702 MM_ERROR_PLAYER_NOT_INITIALIZED);
7704 current_state = MMPLAYER_CURRENT_STATE(player);
7706 /* NOTE : query position except paused state to overcome some bad operation
7707 * please refer to below comments in details
7709 if (current_state != MM_PLAYER_STATE_PAUSED)
7710 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7712 /* NOTE : get last point to overcome some bad operation of some elements
7713 *(returning zero when getting current position in paused state
7714 * and when failed to get postion during seeking
7716 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7717 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7719 if (player->playback_rate < 0.0)
7720 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7722 pos_msec = player->last_position;
7725 pos_msec = player->last_position;
7727 player->last_position = pos_msec;
7729 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7732 if (player->duration > 0 && pos_msec > player->duration)
7733 pos_msec = player->duration;
7735 player->last_position = pos_msec;
7739 case MM_PLAYER_POS_FORMAT_TIME:
7740 *position = GST_TIME_AS_MSECONDS(pos_msec);
7743 case MM_PLAYER_POS_FORMAT_PERCENT:
7745 if (player->duration <= 0) {
7746 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7749 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7750 *position = pos_msec * 100 / player->duration;
7755 return MM_ERROR_PLAYER_INTERNAL;
7758 return MM_ERROR_NONE;
7762 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7764 #define STREAMING_IS_FINISHED 0
7765 #define BUFFERING_MAX_PER 100
7766 #define DEFAULT_PER_VALUE -1
7767 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7769 MMPlayerGstElement *mainbin = NULL;
7770 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7771 gint64 buffered_total = 0;
7772 unsigned long position = 0;
7773 gint buffered_sec = -1;
7774 GstBufferingMode mode = GST_BUFFERING_STREAM;
7775 gint64 content_size_time = player->duration;
7776 guint64 content_size_bytes = player->http_content_size;
7778 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7780 player->pipeline->mainbin,
7781 MM_ERROR_PLAYER_NOT_INITIALIZED);
7783 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7788 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7789 /* and rtsp is not ready yet. */
7790 LOGW("it's only used for http streaming case.\n");
7791 return MM_ERROR_PLAYER_NO_OP;
7794 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7795 LOGW("Time format is not supported yet.\n");
7796 return MM_ERROR_INVALID_ARGUMENT;
7799 if (content_size_time <= 0 || content_size_bytes <= 0) {
7800 LOGW("there is no content size.");
7801 return MM_ERROR_NONE;
7804 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7805 LOGW("fail to get current position.");
7806 return MM_ERROR_NONE;
7809 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7810 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7812 mainbin = player->pipeline->mainbin;
7813 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7815 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7816 GstQuery *query = NULL;
7817 gint byte_in_rate = 0, byte_out_rate = 0;
7818 gint64 estimated_total = 0;
7820 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7821 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7822 LOGW("fail to get buffering query from queue2");
7824 gst_query_unref(query);
7825 return MM_ERROR_NONE;
7828 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7829 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7831 if (mode == GST_BUFFERING_STREAM) {
7832 /* using only queue in case of push mode(ts / mp3) */
7833 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7834 GST_FORMAT_BYTES, &buffered_total)) {
7835 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7836 stop_per = 100 * buffered_total / content_size_bytes;
7839 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7841 guint num_of_ranges = 0;
7842 gint64 start_byte = 0, stop_byte = 0;
7844 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7845 if (estimated_total != STREAMING_IS_FINISHED) {
7846 /* buffered size info from queue2 */
7847 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7848 for (idx = 0; idx < num_of_ranges; idx++) {
7849 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7850 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7852 buffered_total += (stop_byte - start_byte);
7855 stop_per = BUFFERING_MAX_PER;
7857 gst_query_unref(query);
7860 if (stop_per == DEFAULT_PER_VALUE) {
7861 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7863 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7865 /* buffered size info from multiqueue */
7866 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7867 guint curr_size_bytes = 0;
7868 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7869 "curr-size-bytes", &curr_size_bytes, NULL);
7870 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7871 buffered_total += curr_size_bytes;
7874 if (avg_byterate > 0)
7875 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7876 else if (player->total_maximum_bitrate > 0)
7877 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7878 else if (player->total_bitrate > 0)
7879 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7881 if (buffered_sec >= 0)
7882 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7886 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7887 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7889 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7890 buffered_total, buffered_sec, *start_pos, *stop_pos);
7892 return MM_ERROR_NONE;
7896 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7901 LOGW("set_message_callback is called with invalid player handle\n");
7902 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7905 player->msg_cb = callback;
7906 player->msg_cb_param = user_param;
7908 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7912 return MM_ERROR_NONE;
7915 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7917 int ret = MM_ERROR_PLAYER_INVALID_URI;
7922 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7923 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7924 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7926 memset(data, 0, sizeof(MMPlayerParseProfile));
7928 if ((path = strstr(uri, "es_buff://"))) {
7930 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7931 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7932 ret = MM_ERROR_NONE;
7934 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7936 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7937 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7938 ret = MM_ERROR_NONE;
7940 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7943 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7944 tmp = g_ascii_strdown(uri, strlen(uri));
7946 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7947 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7949 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7951 ret = MM_ERROR_NONE;
7954 } else if ((path = strstr(uri, "rtspu://"))) {
7956 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7957 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7958 ret = MM_ERROR_NONE;
7960 } else if ((path = strstr(uri, "rtspr://"))) {
7961 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7962 char *separater = strstr(path, "*");
7966 char *urgent = separater + strlen("*");
7968 if ((urgent_len = strlen(urgent))) {
7969 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7970 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7971 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7972 ret = MM_ERROR_NONE;
7975 } else if ((path = strstr(uri, "mms://"))) {
7977 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7978 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7979 ret = MM_ERROR_NONE;
7981 } else if ((path = strstr(uri, "mem://"))) {
7984 char *buffer = NULL;
7985 char *seperator = strchr(path, ',');
7986 char ext[100] = {0,}, size[100] = {0,};
7989 if ((buffer = strstr(path, "ext="))) {
7990 buffer += strlen("ext=");
7992 if (strlen(buffer)) {
7993 strncpy(ext, buffer, 99);
7995 if ((seperator = strchr(ext, ','))
7996 || (seperator = strchr(ext, ' '))
7997 || (seperator = strchr(ext, '\0'))) {
7998 seperator[0] = '\0';
8003 if ((buffer = strstr(path, "size="))) {
8004 buffer += strlen("size=");
8006 if (strlen(buffer) > 0) {
8007 strncpy(size, buffer, 99);
8009 if ((seperator = strchr(size, ','))
8010 || (seperator = strchr(size, ' '))
8011 || (seperator = strchr(size, '\0'))) {
8012 seperator[0] = '\0';
8015 mem_size = atoi(size);
8020 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8021 if (mem_size && param) {
8022 if (data->input_mem.buf)
8023 free(data->input_mem.buf);
8024 data->input_mem.buf = malloc(mem_size);
8026 if (data->input_mem.buf) {
8027 memcpy(data->input_mem.buf, param, mem_size);
8028 data->input_mem.len = mem_size;
8029 ret = MM_ERROR_NONE;
8031 LOGE("failed to alloc mem %d", mem_size);
8032 ret = MM_ERROR_PLAYER_INTERNAL;
8035 data->input_mem.offset = 0;
8036 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8040 gchar *location = NULL;
8043 if ((path = strstr(uri, "file://"))) {
8045 location = g_filename_from_uri(uri, NULL, &err);
8047 if (!location || (err != NULL)) {
8048 LOGE("Invalid URI '%s' for filesrc: %s", path,
8049 (err != NULL) ? err->message : "unknown error");
8051 if (err) g_error_free(err);
8052 if (location) g_free(location);
8054 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8058 LOGD("path from uri: %s", location);
8061 path = (location != NULL) ? (location) : ((char*)uri);
8062 int file_stat = MM_ERROR_NONE;
8064 file_stat = util_exist_file_path(path);
8066 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8067 if (file_stat == MM_ERROR_NONE) {
8068 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8070 if (util_is_sdp_file(path)) {
8071 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8072 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8074 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8076 ret = MM_ERROR_NONE;
8077 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8078 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8080 LOGE("invalid uri, could not play..\n");
8081 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8084 if (location) g_free(location);
8088 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8089 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8090 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8091 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8093 /* dump parse result */
8094 SECURE_LOGW("incomming uri : %s\n", uri);
8095 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8096 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8104 __mmplayer_can_do_interrupt(mm_player_t *player)
8106 if (!player || !player->pipeline || !player->attrs) {
8107 LOGW("not initialized");
8111 if (player->set_mode.pcm_extraction) {
8112 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8116 /* check if seeking */
8117 if (player->doing_seek) {
8118 MMMessageParamType msg_param;
8119 memset(&msg_param, 0, sizeof(MMMessageParamType));
8120 msg_param.code = MM_ERROR_PLAYER_SEEK;
8121 player->doing_seek = FALSE;
8122 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8126 /* check other thread */
8127 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8128 LOGW("locked already, cmd state : %d", player->cmd);
8130 /* check application command */
8131 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8132 LOGW("playing.. should wait cmd lock then, will be interrupted");
8134 /* lock will be released at mrp_resource_release_cb() */
8135 MMPLAYER_CMD_LOCK(player);
8138 LOGW("nothing to do");
8141 LOGW("can interrupt immediately");
8145 FAILED: /* with CMD UNLOCKED */
8148 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8153 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8156 mm_player_t *player = NULL;
8160 if (user_data == NULL) {
8161 LOGE("- user_data is null\n");
8164 player = (mm_player_t *)user_data;
8166 /* do something to release resource here.
8167 * player stop and interrupt forwarding */
8168 if (!__mmplayer_can_do_interrupt(player)) {
8169 LOGW("no need to interrupt, so leave");
8171 MMMessageParamType msg = {0, };
8172 unsigned long pos = 0;
8174 player->interrupted_by_resource = TRUE;
8176 /* get last play position */
8177 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8178 LOGW("failed to get play position.");
8180 msg.union_type = MM_MSG_UNION_TIME;
8181 msg.time.elapsed = (unsigned int)pos;
8182 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8184 LOGD("video resource conflict so, resource will be freed by unrealizing");
8185 if (_mmplayer_unrealize((MMHandleType)player))
8186 LOGW("failed to unrealize");
8188 /* lock is called in __mmplayer_can_do_interrupt() */
8189 MMPLAYER_CMD_UNLOCK(player);
8192 if (res == player->video_overlay_resource)
8193 player->video_overlay_resource = FALSE;
8195 player->video_decoder_resource = FALSE;
8203 _mmplayer_create_player(MMHandleType handle)
8205 int ret = MM_ERROR_PLAYER_INTERNAL;
8206 bool enabled = false;
8208 mm_player_t* player = MM_PLAYER_CAST(handle);
8212 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8214 /* initialize player state */
8215 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8216 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8217 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8218 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8220 /* check current state */
8221 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8223 /* construct attributes */
8224 player->attrs = _mmplayer_construct_attribute(handle);
8226 if (!player->attrs) {
8227 LOGE("Failed to construct attributes\n");
8231 /* initialize gstreamer with configured parameter */
8232 if (!__mmplayer_init_gstreamer(player)) {
8233 LOGE("Initializing gstreamer failed\n");
8234 _mmplayer_deconstruct_attribute(handle);
8238 /* create lock. note that g_tread_init() has already called in gst_init() */
8239 g_mutex_init(&player->fsink_lock);
8241 /* create update tag lock */
8242 g_mutex_init(&player->update_tag_lock);
8244 /* create next play mutex */
8245 g_mutex_init(&player->next_play_thread_mutex);
8247 /* create next play cond */
8248 g_cond_init(&player->next_play_thread_cond);
8250 /* create next play thread */
8251 player->next_play_thread =
8252 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8253 if (!player->next_play_thread) {
8254 LOGE("failed to create next play thread");
8255 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8256 g_mutex_clear(&player->next_play_thread_mutex);
8257 g_cond_clear(&player->next_play_thread_cond);
8261 player->bus_msg_q = g_queue_new();
8262 if (!player->bus_msg_q) {
8263 LOGE("failed to create queue for bus_msg");
8264 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8268 ret = _mmplayer_initialize_video_capture(player);
8269 if (ret != MM_ERROR_NONE) {
8270 LOGE("failed to initialize video capture\n");
8274 /* initialize resource manager */
8275 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8276 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8277 &player->resource_manager)) {
8278 LOGE("failed to initialize resource manager\n");
8282 if (MMPLAYER_IS_HTTP_PD(player)) {
8283 player->pd_downloader = NULL;
8284 player->pd_file_save_path = NULL;
8287 /* create video bo lock and cond */
8288 g_mutex_init(&player->video_bo_mutex);
8289 g_cond_init(&player->video_bo_cond);
8291 /* create media stream callback mutex */
8292 g_mutex_init(&player->media_stream_cb_lock);
8294 /* create subtitle info lock and cond */
8295 g_mutex_init(&player->subtitle_info_mutex);
8296 g_cond_init(&player->subtitle_info_cond);
8298 player->streaming_type = STREAMING_SERVICE_NONE;
8300 /* give default value of audio effect setting */
8301 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8302 player->sound.rg_enable = false;
8303 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8305 player->play_subtitle = FALSE;
8306 player->use_deinterleave = FALSE;
8307 player->max_audio_channels = 0;
8308 player->video_share_api_delta = 0;
8309 player->video_share_clock_delta = 0;
8310 player->has_closed_caption = FALSE;
8311 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8312 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8313 player->pending_resume = FALSE;
8314 if (player->ini.dump_element_keyword[0][0] == '\0')
8315 player->ini.set_dump_element_flag = FALSE;
8317 player->ini.set_dump_element_flag = TRUE;
8319 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8320 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8321 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8323 /* Set video360 settings to their defaults for just-created player.
8326 player->is_360_feature_enabled = FALSE;
8327 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8328 LOGI("spherical feature info: %d", enabled);
8330 player->is_360_feature_enabled = TRUE;
8332 LOGE("failed to get spherical feature info");
8335 player->is_content_spherical = FALSE;
8336 player->is_video360_enabled = TRUE;
8337 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8338 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8339 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8340 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8341 player->video360_zoom = 1.0f;
8342 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8343 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8345 /* set player state to null */
8346 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8347 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8349 return MM_ERROR_NONE;
8353 g_mutex_clear(&player->fsink_lock);
8355 /* free update tag lock */
8356 g_mutex_clear(&player->update_tag_lock);
8358 g_queue_free(player->bus_msg_q);
8360 /* free next play thread */
8361 if (player->next_play_thread) {
8362 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8363 player->next_play_thread_exit = TRUE;
8364 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8365 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8367 g_thread_join(player->next_play_thread);
8368 player->next_play_thread = NULL;
8370 g_mutex_clear(&player->next_play_thread_mutex);
8371 g_cond_clear(&player->next_play_thread_cond);
8374 /* release attributes */
8375 _mmplayer_deconstruct_attribute(handle);
8383 __mmplayer_init_gstreamer(mm_player_t* player)
8385 static gboolean initialized = FALSE;
8386 static const int max_argc = 50;
8388 gchar** argv = NULL;
8389 gchar** argv2 = NULL;
8395 LOGD("gstreamer already initialized.\n");
8400 argc = malloc(sizeof(int));
8401 argv = malloc(sizeof(gchar*) * max_argc);
8402 argv2 = malloc(sizeof(gchar*) * max_argc);
8404 if (!argc || !argv || !argv2)
8407 memset(argv, 0, sizeof(gchar*) * max_argc);
8408 memset(argv2, 0, sizeof(gchar*) * max_argc);
8412 argv[0] = g_strdup("mmplayer");
8415 for (i = 0; i < 5; i++) {
8416 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8417 if (strlen(player->ini.gst_param[i]) > 0) {
8418 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8423 /* we would not do fork for scanning plugins */
8424 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8427 /* check disable registry scan */
8428 if (player->ini.skip_rescan) {
8429 argv[*argc] = g_strdup("--gst-disable-registry-update");
8433 /* check disable segtrap */
8434 if (player->ini.disable_segtrap) {
8435 argv[*argc] = g_strdup("--gst-disable-segtrap");
8439 LOGD("initializing gstreamer with following parameter\n");
8440 LOGD("argc : %d\n", *argc);
8443 for (i = 0; i < arg_count; i++) {
8445 LOGD("argv[%d] : %s\n", i, argv2[i]);
8448 /* initializing gstreamer */
8449 if (!gst_init_check(argc, &argv, &err)) {
8450 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8457 for (i = 0; i < arg_count; i++) {
8458 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8459 MMPLAYER_FREEIF(argv2[i]);
8462 MMPLAYER_FREEIF(argv);
8463 MMPLAYER_FREEIF(argv2);
8464 MMPLAYER_FREEIF(argc);
8474 for (i = 0; i < arg_count; i++) {
8475 LOGD("free[%d] : %s\n", i, argv2[i]);
8476 MMPLAYER_FREEIF(argv2[i]);
8479 MMPLAYER_FREEIF(argv);
8480 MMPLAYER_FREEIF(argv2);
8481 MMPLAYER_FREEIF(argc);
8487 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8491 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8492 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8493 MMPLAYER_FREEIF(player->pd_file_save_path);
8496 return MM_ERROR_NONE;
8500 __mmplayer_check_async_state_transition(mm_player_t* player)
8502 GstState element_state = GST_STATE_VOID_PENDING;
8503 GstState element_pending_state = GST_STATE_VOID_PENDING;
8504 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8505 GstElement * element = NULL;
8506 gboolean async = FALSE;
8508 /* check player handle */
8509 MMPLAYER_RETURN_IF_FAIL(player &&
8511 player->pipeline->mainbin &&
8512 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8515 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8517 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8518 LOGD("don't need to check the pipeline state");
8522 MMPLAYER_PRINT_STATE(player);
8524 /* wait for state transition */
8525 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8526 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8528 if (ret == GST_STATE_CHANGE_FAILURE) {
8529 LOGE(" [%s] state : %s pending : %s \n",
8530 GST_ELEMENT_NAME(element),
8531 gst_element_state_get_name(element_state),
8532 gst_element_state_get_name(element_pending_state));
8534 /* dump state of all element */
8535 __mmplayer_dump_pipeline_state(player);
8540 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8545 _mmplayer_destroy(MMHandleType handle)
8547 mm_player_t* player = MM_PLAYER_CAST(handle);
8551 /* check player handle */
8552 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554 /* destroy can called at anytime */
8555 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8557 /* check async state transition */
8558 __mmplayer_check_async_state_transition(player);
8560 __mmplayer_destroy_streaming_ext(player);
8562 /* release next play thread */
8563 if (player->next_play_thread) {
8564 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8565 player->next_play_thread_exit = TRUE;
8566 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8567 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8569 LOGD("waitting for next play thread exit\n");
8570 g_thread_join(player->next_play_thread);
8571 g_mutex_clear(&player->next_play_thread_mutex);
8572 g_cond_clear(&player->next_play_thread_cond);
8573 LOGD("next play thread released\n");
8576 _mmplayer_release_video_capture(player);
8578 /* de-initialize resource manager */
8579 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8580 player->resource_manager))
8581 LOGE("failed to deinitialize resource manager\n");
8583 /* release pipeline */
8584 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8585 LOGE("failed to destory pipeline\n");
8586 return MM_ERROR_PLAYER_INTERNAL;
8589 g_queue_free(player->bus_msg_q);
8591 /* release subtitle info lock and cond */
8592 g_mutex_clear(&player->subtitle_info_mutex);
8593 g_cond_clear(&player->subtitle_info_cond);
8595 __mmplayer_release_dump_list(player->dump_list);
8597 /* release miscellaneous information */
8598 __mmplayer_release_misc(player);
8600 /* release miscellaneous information.
8601 these info needs to be released after pipeline is destroyed. */
8602 __mmplayer_release_misc_post(player);
8604 /* release attributes */
8605 _mmplayer_deconstruct_attribute(handle);
8608 g_mutex_clear(&player->fsink_lock);
8611 g_mutex_clear(&player->update_tag_lock);
8613 /* release video bo lock and cond */
8614 g_mutex_clear(&player->video_bo_mutex);
8615 g_cond_clear(&player->video_bo_cond);
8617 /* release media stream callback lock */
8618 g_mutex_clear(&player->media_stream_cb_lock);
8622 return MM_ERROR_NONE;
8626 __mmplayer_realize_streaming_ext(mm_player_t* player)
8628 int ret = MM_ERROR_NONE;
8631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8633 if (MMPLAYER_IS_HTTP_PD(player)) {
8634 gboolean bret = FALSE;
8636 player->pd_downloader = _mmplayer_create_pd_downloader();
8637 if (!player->pd_downloader) {
8638 LOGE("Unable to create PD Downloader...");
8639 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8642 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8644 if (FALSE == bret) {
8645 LOGE("Unable to create PD Downloader...");
8646 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8655 _mmplayer_realize(MMHandleType hplayer)
8657 mm_player_t* player = (mm_player_t*)hplayer;
8660 MMHandleType attrs = 0;
8661 int ret = MM_ERROR_NONE;
8665 /* check player handle */
8666 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8668 /* check current state */
8669 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8671 attrs = MMPLAYER_GET_ATTRS(player);
8673 LOGE("fail to get attributes.\n");
8674 return MM_ERROR_PLAYER_INTERNAL;
8676 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8677 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8679 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8680 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8682 if (ret != MM_ERROR_NONE) {
8683 LOGE("failed to parse profile\n");
8688 if (uri && (strstr(uri, "es_buff://"))) {
8689 if (strstr(uri, "es_buff://push_mode"))
8690 player->es_player_push_mode = TRUE;
8692 player->es_player_push_mode = FALSE;
8695 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8696 LOGW("mms protocol is not supported format.\n");
8697 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8700 if (MMPLAYER_IS_STREAMING(player))
8701 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8703 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8705 player->smooth_streaming = FALSE;
8706 player->videodec_linked = 0;
8707 player->videosink_linked = 0;
8708 player->audiodec_linked = 0;
8709 player->audiosink_linked = 0;
8710 player->textsink_linked = 0;
8711 player->is_external_subtitle_present = FALSE;
8712 player->is_external_subtitle_added_now = FALSE;
8713 /* set the subtitle ON default */
8714 player->is_subtitle_off = FALSE;
8716 /* realize pipeline */
8717 ret = __gst_realize(player);
8718 if (ret != MM_ERROR_NONE)
8719 LOGE("fail to realize the player.\n");
8721 ret = __mmplayer_realize_streaming_ext(player);
8723 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8724 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8732 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8737 /* destroy can called at anytime */
8738 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8739 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8742 return MM_ERROR_NONE;
8746 _mmplayer_unrealize(MMHandleType hplayer)
8748 mm_player_t* player = (mm_player_t*)hplayer;
8749 int ret = MM_ERROR_NONE;
8753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8755 MMPLAYER_CMD_UNLOCK(player);
8756 /* destroy the gst bus msg thread which is created during realize.
8757 this funct have to be called before getting cmd lock. */
8758 _mmplayer_bus_msg_thread_destroy(player);
8759 MMPLAYER_CMD_LOCK(player);
8761 /* check current state */
8762 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8764 /* check async state transition */
8765 __mmplayer_check_async_state_transition(player);
8767 __mmplayer_unrealize_streaming_ext(player);
8769 /* unrealize pipeline */
8770 ret = __gst_unrealize(player);
8772 /* set asm stop if success */
8773 if (MM_ERROR_NONE == ret) {
8774 if (!player->interrupted_by_resource) {
8775 if (player->video_decoder_resource != NULL) {
8776 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8777 player->video_decoder_resource);
8778 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8779 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8781 player->video_decoder_resource = NULL;
8784 if (player->video_overlay_resource != NULL) {
8785 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8786 player->video_overlay_resource);
8787 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8788 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8790 player->video_overlay_resource = NULL;
8793 ret = mm_resource_manager_commit(player->resource_manager);
8794 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8795 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8798 LOGE("failed and don't change asm state to stop");
8806 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8808 mm_player_t* player = (mm_player_t*)hplayer;
8810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812 return __gst_set_message_callback(player, callback, user_param);
8816 _mmplayer_get_state(MMHandleType hplayer, int* state)
8818 mm_player_t *player = (mm_player_t*)hplayer;
8820 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8822 *state = MMPLAYER_CURRENT_STATE(player);
8824 return MM_ERROR_NONE;
8829 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8831 mm_player_t* player = (mm_player_t*) hplayer;
8832 GstElement* vol_element = NULL;
8837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8839 LOGD("volume [L]=%f:[R]=%f\n",
8840 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8842 /* invalid factor range or not */
8843 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8844 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8845 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8846 return MM_ERROR_INVALID_ARGUMENT;
8850 /* not support to set other value into each channel */
8851 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8852 return MM_ERROR_INVALID_ARGUMENT;
8854 /* Save volume to handle. Currently the first array element will be saved. */
8855 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8857 /* check pipeline handle */
8858 if (!player->pipeline || !player->pipeline->audiobin) {
8859 LOGD("audiobin is not created yet\n");
8860 LOGD("but, current stored volume will be set when it's created.\n");
8862 /* NOTE : stored volume will be used in create_audiobin
8863 * returning MM_ERROR_NONE here makes application to able to
8864 * set volume at anytime.
8866 return MM_ERROR_NONE;
8869 /* setting volume to volume element */
8870 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8873 LOGD("volume is set [%f]\n", player->sound.volume);
8874 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8879 return MM_ERROR_NONE;
8884 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8886 mm_player_t* player = (mm_player_t*) hplayer;
8891 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8892 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8894 /* returning stored volume */
8895 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8896 volume->level[i] = player->sound.volume;
8900 return MM_ERROR_NONE;
8904 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8906 mm_player_t* player = (mm_player_t*) hplayer;
8907 GstElement* vol_element = NULL;
8911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8913 /* mute value shoud 0 or 1 */
8914 if (mute != 0 && mute != 1) {
8915 LOGE("bad mute value\n");
8917 /* FIXIT : definitly, we need _BAD_PARAM error code */
8918 return MM_ERROR_INVALID_ARGUMENT;
8921 player->sound.mute = mute;
8923 /* just hold mute value if pipeline is not ready */
8924 if (!player->pipeline || !player->pipeline->audiobin) {
8925 LOGD("pipeline is not ready. holding mute value\n");
8926 return MM_ERROR_NONE;
8929 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8931 /* NOTE : volume will only created when the bt is enabled */
8933 LOGD("mute : %d\n", mute);
8934 g_object_set(vol_element, "mute", mute, NULL);
8936 LOGD("volume elemnet is not created. using volume in audiosink\n");
8940 return MM_ERROR_NONE;
8944 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8946 mm_player_t* player = (mm_player_t*) hplayer;
8950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8951 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8953 /* just hold mute value if pipeline is not ready */
8954 if (!player->pipeline || !player->pipeline->audiobin) {
8955 LOGD("pipeline is not ready. returning stored value\n");
8956 *pmute = player->sound.mute;
8957 return MM_ERROR_NONE;
8960 *pmute = player->sound.mute;
8964 return MM_ERROR_NONE;
8968 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8970 mm_player_t* player = (mm_player_t*) hplayer;
8974 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8976 player->video_stream_changed_cb = callback;
8977 player->video_stream_changed_cb_user_param = user_param;
8978 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8982 return MM_ERROR_NONE;
8986 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8988 mm_player_t* player = (mm_player_t*) hplayer;
8992 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8994 player->audio_stream_changed_cb = callback;
8995 player->audio_stream_changed_cb_user_param = user_param;
8996 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
9000 return MM_ERROR_NONE;
9004 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
9006 mm_player_t* player = (mm_player_t*) hplayer;
9010 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9012 player->audio_stream_render_cb_ex = callback;
9013 player->audio_stream_cb_user_param = user_param;
9014 player->audio_stream_sink_sync = sync;
9015 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);
9019 return MM_ERROR_NONE;
9023 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
9025 mm_player_t* player = (mm_player_t*) hplayer;
9029 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9031 if (callback && !player->bufmgr)
9032 player->bufmgr = tbm_bufmgr_init(-1);
9034 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
9035 player->video_stream_cb = callback;
9036 player->video_stream_cb_user_param = user_param;
9038 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9042 return MM_ERROR_NONE;
9046 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9048 mm_player_t* player = (mm_player_t*) hplayer;
9052 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9054 player->audio_stream_cb = callback;
9055 player->audio_stream_cb_user_param = user_param;
9056 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9060 return MM_ERROR_NONE;
9064 __mmplayer_start_streaming_ext(mm_player_t *player)
9066 gint ret = MM_ERROR_NONE;
9069 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9071 if (MMPLAYER_IS_HTTP_PD(player)) {
9072 if (!player->pd_downloader) {
9073 ret = __mmplayer_realize_streaming_ext(player);
9075 if (ret != MM_ERROR_NONE) {
9076 LOGE("failed to realize streaming ext\n");
9081 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9082 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9084 LOGE("ERROR while starting PD...\n");
9085 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9087 ret = MM_ERROR_NONE;
9096 _mmplayer_start(MMHandleType hplayer)
9098 mm_player_t* player = (mm_player_t*) hplayer;
9099 gint ret = MM_ERROR_NONE;
9103 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9105 /* check current state */
9106 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9108 /* NOTE : we should check and create pipeline again if not created as we destroy
9109 * whole pipeline when stopping in streamming playback
9111 if (!player->pipeline) {
9112 ret = __gst_realize(player);
9113 if (MM_ERROR_NONE != ret) {
9114 LOGE("failed to realize before starting. only in streamming\n");
9120 ret = __mmplayer_start_streaming_ext(player);
9121 if (ret != MM_ERROR_NONE) {
9122 LOGE("failed to start streaming ext 0x%X", ret);
9126 /* start pipeline */
9127 ret = __gst_start(player);
9128 if (ret != MM_ERROR_NONE)
9129 LOGE("failed to start player.\n");
9136 /* NOTE: post "not supported codec message" to application
9137 * when one codec is not found during AUTOPLUGGING in MSL.
9138 * So, it's separated with error of __mmplayer_gst_callback().
9139 * And, if any codec is not found, don't send message here.
9140 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9143 __mmplayer_handle_missed_plugin(mm_player_t* player)
9145 MMMessageParamType msg_param;
9146 memset(&msg_param, 0, sizeof(MMMessageParamType));
9147 gboolean post_msg_direct = FALSE;
9151 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9153 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9154 player->not_supported_codec, player->can_support_codec);
9156 if (player->not_found_demuxer) {
9157 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9158 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9160 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9161 MMPLAYER_FREEIF(msg_param.data);
9163 return MM_ERROR_NONE;
9166 if (player->not_supported_codec) {
9167 if (player->can_support_codec) {
9168 // There is one codec to play
9169 post_msg_direct = TRUE;
9171 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9172 post_msg_direct = TRUE;
9175 if (post_msg_direct) {
9176 MMMessageParamType msg_param;
9177 memset(&msg_param, 0, sizeof(MMMessageParamType));
9179 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9180 LOGW("not found AUDIO codec, posting error code to application.\n");
9182 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9183 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9184 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9185 LOGW("not found VIDEO codec, posting error code to application.\n");
9187 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9188 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9191 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9193 MMPLAYER_FREEIF(msg_param.data);
9195 return MM_ERROR_NONE;
9197 // no any supported codec case
9198 LOGW("not found any codec, posting error code to application.\n");
9200 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9201 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9202 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9204 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9205 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9208 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9210 MMPLAYER_FREEIF(msg_param.data);
9216 return MM_ERROR_NONE;
9219 static void __mmplayer_check_pipeline(mm_player_t* player)
9221 GstState element_state = GST_STATE_VOID_PENDING;
9222 GstState element_pending_state = GST_STATE_VOID_PENDING;
9224 int ret = MM_ERROR_NONE;
9226 if (player->gapless.reconfigure) {
9227 LOGW("pipeline is under construction.\n");
9229 MMPLAYER_PLAYBACK_LOCK(player);
9230 MMPLAYER_PLAYBACK_UNLOCK(player);
9232 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9234 /* wait for state transition */
9235 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9237 if (ret == GST_STATE_CHANGE_FAILURE)
9238 LOGE("failed to change pipeline state within %d sec\n", timeout);
9242 /* NOTE : it should be able to call 'stop' anytime*/
9244 _mmplayer_stop(MMHandleType hplayer)
9246 mm_player_t* player = (mm_player_t*)hplayer;
9247 int ret = MM_ERROR_NONE;
9251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9253 /* check current state */
9254 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9256 /* check pipline building state */
9257 __mmplayer_check_pipeline(player);
9258 __mmplayer_reset_gapless_state(player);
9260 /* NOTE : application should not wait for EOS after calling STOP */
9261 __mmplayer_cancel_eos_timer(player);
9263 __mmplayer_unrealize_streaming_ext(player);
9266 player->doing_seek = FALSE;
9269 ret = __gst_stop(player);
9271 if (ret != MM_ERROR_NONE)
9272 LOGE("failed to stop player.\n");
9280 _mmplayer_pause(MMHandleType hplayer)
9282 mm_player_t* player = (mm_player_t*)hplayer;
9283 gint64 pos_msec = 0;
9284 gboolean async = FALSE;
9285 gint ret = MM_ERROR_NONE;
9289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9291 /* check current state */
9292 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9294 /* check pipline building state */
9295 __mmplayer_check_pipeline(player);
9297 switch (MMPLAYER_CURRENT_STATE(player)) {
9298 case MM_PLAYER_STATE_READY:
9300 /* check prepare async or not.
9301 * In the case of streaming playback, it's recommned to avoid blocking wait.
9303 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9304 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9306 /* Changing back sync of rtspsrc to async */
9307 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9308 LOGD("async prepare working mode for rtsp");
9314 case MM_PLAYER_STATE_PLAYING:
9316 /* NOTE : store current point to overcome some bad operation
9317 *(returning zero when getting current position in paused state) of some
9320 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9321 LOGW("getting current position failed in paused\n");
9323 player->last_position = pos_msec;
9325 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9326 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9327 This causes problem is position calculation during normal pause resume scenarios also.
9328 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9329 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9330 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9331 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9337 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9338 LOGD("doing async pause in case of ms buff src");
9342 /* pause pipeline */
9343 ret = __gst_pause(player, async);
9345 if (ret != MM_ERROR_NONE)
9346 LOGE("failed to pause player. ret : 0x%x\n", ret);
9348 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9349 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9350 LOGE("failed to update display_rotation");
9359 _mmplayer_resume(MMHandleType hplayer)
9361 mm_player_t* player = (mm_player_t*)hplayer;
9362 int ret = MM_ERROR_NONE;
9363 gboolean async = FALSE;
9367 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9369 /* Changing back sync mode rtspsrc to async */
9370 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9371 LOGD("async resume for rtsp case");
9375 /* check current state */
9376 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9378 ret = __gst_resume(player, async);
9380 if (ret != MM_ERROR_NONE)
9381 LOGE("failed to resume player.\n");
9389 __mmplayer_set_pcm_extraction(mm_player_t* player)
9391 gint64 start_nsec = 0;
9392 gint64 end_nsec = 0;
9393 gint64 dur_nsec = 0;
9394 gint64 dur_msec = 0;
9395 int required_start = 0;
9396 int required_end = 0;
9401 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9403 mm_attrs_multiple_get(player->attrs,
9405 "pcm_extraction_start_msec", &required_start,
9406 "pcm_extraction_end_msec", &required_end,
9409 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9411 if (required_start == 0 && required_end == 0) {
9412 LOGD("extracting entire stream");
9413 return MM_ERROR_NONE;
9414 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9415 LOGD("invalid range for pcm extraction");
9416 return MM_ERROR_INVALID_ARGUMENT;
9420 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9422 LOGE("failed to get duration");
9423 return MM_ERROR_PLAYER_INTERNAL;
9425 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9427 if (dur_msec < required_end) {
9429 LOGD("invalid end pos for pcm extraction");
9430 return MM_ERROR_INVALID_ARGUMENT;
9433 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9434 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9436 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9439 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9440 GST_SEEK_TYPE_SET, start_nsec,
9441 GST_SEEK_TYPE_SET, end_nsec))) {
9442 LOGE("failed to seek for pcm extraction\n");
9444 return MM_ERROR_PLAYER_SEEK;
9447 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9451 return MM_ERROR_NONE;
9455 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9457 mm_player_t* player = (mm_player_t*)hplayer;
9458 gint64 pos_msec = 0;
9459 int ret = MM_ERROR_NONE;
9461 signed long long start = 0, stop = 0;
9462 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9465 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9466 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9468 /* The sound of video is not supported under 0.0 and over 2.0. */
9469 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9470 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9473 _mmplayer_set_mute(hplayer, mute);
9475 if (player->playback_rate == rate)
9476 return MM_ERROR_NONE;
9478 /* If the position is reached at start potion during fast backward, EOS is posted.
9479 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9481 player->playback_rate = rate;
9483 current_state = MMPLAYER_CURRENT_STATE(player);
9485 if (current_state != MM_PLAYER_STATE_PAUSED)
9486 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9488 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9490 if ((current_state == MM_PLAYER_STATE_PAUSED)
9491 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9492 LOGW("returning last point : %lld\n", player->last_position);
9493 pos_msec = player->last_position;
9498 stop = GST_CLOCK_TIME_NONE;
9500 start = GST_CLOCK_TIME_NONE;
9504 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9505 player->playback_rate,
9507 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9508 GST_SEEK_TYPE_SET, start,
9509 GST_SEEK_TYPE_SET, stop)) {
9510 LOGE("failed to set speed playback\n");
9511 return MM_ERROR_PLAYER_SEEK;
9514 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9518 return MM_ERROR_NONE;;
9522 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9524 mm_player_t* player = (mm_player_t*)hplayer;
9525 int ret = MM_ERROR_NONE;
9529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9531 /* check pipline building state */
9532 __mmplayer_check_pipeline(player);
9534 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9542 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9544 mm_player_t* player = (mm_player_t*)hplayer;
9545 int ret = MM_ERROR_NONE;
9547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9549 ret = __gst_get_position(player, format, position);
9555 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9557 mm_player_t* player = (mm_player_t*)hplayer;
9558 int ret = MM_ERROR_NONE;
9560 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9562 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9568 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9570 mm_player_t* player = (mm_player_t*)hplayer;
9571 int ret = MM_ERROR_NONE;
9575 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9577 ret = __gst_adjust_subtitle_position(player, format, position);
9584 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9586 mm_player_t* player = (mm_player_t*)hplayer;
9587 int ret = MM_ERROR_NONE;
9591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9593 ret = __gst_adjust_video_position(player, offset);
9601 __mmplayer_is_midi_type(gchar* str_caps)
9603 if ((g_strrstr(str_caps, "audio/midi")) ||
9604 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9605 (g_strrstr(str_caps, "application/x-smaf")) ||
9606 (g_strrstr(str_caps, "audio/x-imelody")) ||
9607 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9608 (g_strrstr(str_caps, "audio/xmf")) ||
9609 (g_strrstr(str_caps, "audio/mxmf"))) {
9618 __mmplayer_is_only_mp3_type(gchar *str_caps)
9620 if (g_strrstr(str_caps, "application/x-id3") ||
9621 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9627 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9629 GstStructure* caps_structure = NULL;
9630 gint samplerate = 0;
9634 MMPLAYER_RETURN_IF_FAIL(player && caps);
9636 caps_structure = gst_caps_get_structure(caps, 0);
9638 /* set stream information */
9639 gst_structure_get_int(caps_structure, "rate", &samplerate);
9640 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9642 gst_structure_get_int(caps_structure, "channels", &channels);
9643 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9645 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9649 __mmplayer_update_content_type_info(mm_player_t* player)
9652 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9654 if (__mmplayer_is_midi_type(player->type)) {
9655 player->bypass_audio_effect = TRUE;
9656 } else if (g_strrstr(player->type, "application/x-hls")) {
9657 /* If it can't know exact type when it parses uri because of redirection case,
9658 * it will be fixed by typefinder or when doing autoplugging.
9660 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9661 if (player->streamer) {
9662 player->streamer->is_adaptive_streaming = TRUE;
9663 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9664 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9666 } else if (g_strrstr(player->type, "application/dash+xml")) {
9667 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9674 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9675 GstCaps *caps, gpointer data)
9677 mm_player_t* player = (mm_player_t*)data;
9682 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9684 /* store type string */
9685 MMPLAYER_FREEIF(player->type);
9686 player->type = gst_caps_to_string(caps);
9688 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9689 player, player->type, probability, gst_caps_get_size(caps));
9692 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9693 (g_strrstr(player->type, "audio/x-raw-int"))) {
9694 LOGE("not support media format\n");
9696 if (player->msg_posted == FALSE) {
9697 MMMessageParamType msg_param;
9698 memset(&msg_param, 0, sizeof(MMMessageParamType));
9700 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9701 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9703 /* don't post more if one was sent already */
9704 player->msg_posted = TRUE;
9709 __mmplayer_update_content_type_info(player);
9711 pad = gst_element_get_static_pad(tf, "src");
9713 LOGE("fail to get typefind src pad.\n");
9717 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9718 gboolean async = FALSE;
9719 LOGE("failed to autoplug %s\n", player->type);
9721 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9723 if (async && player->msg_posted == FALSE)
9724 __mmplayer_handle_missed_plugin(player);
9730 gst_object_unref(GST_OBJECT(pad));
9738 __mmplayer_create_decodebin(mm_player_t* player)
9740 GstElement *decodebin = NULL;
9744 /* create decodebin */
9745 decodebin = gst_element_factory_make("decodebin", NULL);
9748 LOGE("fail to create decodebin\n");
9752 /* raw pad handling signal */
9753 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9754 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9756 /* no-more-pad pad handling signal */
9757 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9758 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9760 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9761 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9763 /* This signal is emitted when a pad for which there is no further possible
9764 decoding is added to the decodebin.*/
9765 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9766 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9768 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9769 before looking for any elements that can handle that stream.*/
9770 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9771 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9773 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9774 before looking for any elements that can handle that stream.*/
9775 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9776 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9778 /* This signal is emitted once decodebin has finished decoding all the data.*/
9779 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9780 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9782 /* This signal is emitted when a element is added to the bin.*/
9783 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9784 G_CALLBACK(__mmplayer_gst_element_added), player);
9791 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9793 MMPlayerGstElement* mainbin = NULL;
9794 GstElement* decodebin = NULL;
9795 GstElement* queue2 = NULL;
9796 GstPad* sinkpad = NULL;
9797 GstPad* qsrcpad = NULL;
9798 gint64 dur_bytes = 0L;
9800 guint max_buffer_size_bytes = 0;
9801 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9804 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9806 mainbin = player->pipeline->mainbin;
9808 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9809 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9810 LOGD("creating http streaming buffering queue(queue2)\n");
9812 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9813 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9815 queue2 = gst_element_factory_make("queue2", "queue2");
9817 LOGE("failed to create buffering queue element\n");
9821 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9822 LOGE("failed to add buffering queue\n");
9826 sinkpad = gst_element_get_static_pad(queue2, "sink");
9827 qsrcpad = gst_element_get_static_pad(queue2, "src");
9829 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9830 LOGE("failed to link buffering queue\n");
9834 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9835 LOGE("fail to get duration.\n");
9837 LOGD("dur_bytes = %lld\n", dur_bytes);
9839 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9841 if (dur_bytes > 0) {
9842 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9843 type = MUXED_BUFFER_TYPE_FILE;
9845 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9846 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9852 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9853 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9854 if (!g_strrstr(player->type, "video/mpegts")) {
9855 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9856 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9858 // FIXME : pass ini setting directly. is this ok?
9859 __mm_player_streaming_set_queue2(player->streamer,
9862 max_buffer_size_bytes,
9863 player->ini.http_buffering_time,
9865 player->ini.http_buffering_limit, // no meaning
9867 player->http_file_buffering_path,
9868 (guint64)dur_bytes);
9871 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9872 LOGE("failed to sync queue2 state with parent\n");
9878 gst_object_unref(GST_OBJECT(sinkpad));
9880 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9881 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9885 /* create decodebin */
9886 decodebin = __mmplayer_create_decodebin(player);
9889 LOGE("can not create autoplug element\n");
9893 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9894 LOGE("failed to add decodebin\n");
9898 /* to force caps on the decodebin element and avoid reparsing stuff by
9899 * typefind. It also avoids a deadlock in the way typefind activates pads in
9900 * the state change */
9901 g_object_set(decodebin, "sink-caps", caps, NULL);
9903 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9905 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9906 LOGE("failed to link decodebin\n");
9910 gst_object_unref(GST_OBJECT(sinkpad));
9912 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9913 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9915 /* set decodebin property about buffer in streaming playback. *
9916 * in case of HLS/DASH, it does not need to have big buffer *
9917 * because it is kind of adaptive streaming. */
9918 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9919 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9920 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9921 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9923 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9924 || MMPLAYER_IS_DASH_STREAMING(player)) {
9925 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9926 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9929 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9930 "high-percent", (gint)player->ini.http_buffering_limit,
9931 "low-percent", 1, // 1%
9932 "max-size-bytes", max_size_bytes,
9933 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9934 "max-size-buffers", 0, NULL); // disable or automatic
9937 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9938 LOGE("failed to sync decodebin state with parent\n");
9949 gst_object_unref(GST_OBJECT(sinkpad));
9952 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9953 * You need to explicitly set elements to the NULL state before
9954 * dropping the final reference, to allow them to clean up.
9956 gst_element_set_state(queue2, GST_STATE_NULL);
9958 /* And, it still has a parent "player".
9959 * You need to let the parent manage the object instead of unreffing the object directly.
9961 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9962 gst_object_unref(queue2);
9967 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9968 * You need to explicitly set elements to the NULL state before
9969 * dropping the final reference, to allow them to clean up.
9971 gst_element_set_state(decodebin, GST_STATE_NULL);
9973 /* And, it still has a parent "player".
9974 * You need to let the parent manage the object instead of unreffing the object directly.
9977 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9978 gst_object_unref(decodebin);
9986 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9990 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9991 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9993 LOGD("class : %s, mime : %s \n", factory_class, mime);
9995 /* add missing plugin */
9996 /* NOTE : msl should check missing plugin for image mime type.
9997 * Some motion jpeg clips can have playable audio track.
9998 * So, msl have to play audio after displaying popup written video format not supported.
10000 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
10001 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
10002 LOGD("not found demuxer\n");
10003 player->not_found_demuxer = TRUE;
10004 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
10010 if (!g_strrstr(factory_class, "Demuxer")) {
10011 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
10012 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
10013 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
10015 /* check that clip have multi tracks or not */
10016 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
10017 LOGD("video plugin is already linked\n");
10019 LOGW("add VIDEO to missing plugin\n");
10020 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
10021 player->unlinked_video_mime = g_strdup_printf("%s", mime);
10023 } else if (g_str_has_prefix(mime, "audio")) {
10024 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
10025 LOGD("audio plugin is already linked\n");
10027 LOGW("add AUDIO to missing plugin\n");
10028 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
10029 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
10037 return MM_ERROR_NONE;
10042 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10044 mm_player_t* player = (mm_player_t*)data;
10048 MMPLAYER_RETURN_IF_FAIL(player);
10050 /* remove fakesink. */
10051 if (!__mmplayer_gst_remove_fakesink(player,
10052 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10053 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10054 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10055 * source element are not same. To overcome this situation, this function will called
10056 * several places and several times. Therefore, this is not an error case.
10061 LOGD("[handle: %p] pipeline has completely constructed", player);
10063 if ((player->ini.async_start) &&
10064 (player->msg_posted == FALSE) &&
10065 (player->cmd >= MMPLAYER_COMMAND_START))
10066 __mmplayer_handle_missed_plugin(player);
10068 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10072 __mmplayer_verify_next_play_path(mm_player_t *player)
10074 MMHandleType attrs = 0;
10075 MMPlayerParseProfile profile;
10076 gint uri_idx = 0, check_cnt = 0;
10078 gint mode = MM_PLAYER_PD_MODE_NONE;
10082 guint num_of_list = 0;
10083 static int profile_tv = -1;
10087 LOGD("checking for gapless play");
10089 if (player->pipeline->textbin) {
10090 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10094 attrs = MMPLAYER_GET_ATTRS(player);
10096 LOGE("fail to get attributes.\n");
10100 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10102 if (__builtin_expect(profile_tv == -1, 0)) {
10104 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10105 switch (*profileName) {
10115 /* gapless playback is not supported in case of video at TV profile. */
10116 if (profile_tv && video) {
10117 LOGW("not support video gapless playback");
10121 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10122 if (mode == TRUE) {
10128 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10129 LOGE("can not get play count\n");
10131 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10132 LOGE("can not get gapless mode\n");
10134 if (video && !gapless) {
10135 LOGW("not enabled video gapless playback");
10139 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10143 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10147 num_of_list = g_list_length(player->uri_info.uri_list);
10149 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10151 if (num_of_list == 0) {
10152 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10153 LOGE("can not get profile_uri\n");
10158 LOGE("uri list is empty.\n");
10162 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10163 LOGD("add original path : %s ", uri);
10169 uri_idx = player->uri_info.uri_idx;
10174 if (check_cnt > num_of_list) {
10175 LOGE("there is no valid uri.");
10179 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10181 if (uri_idx < num_of_list-1) {
10184 if ((count <= 1) && (count != -1)) {
10185 LOGD("no repeat.");
10187 } else if (count > 1) {
10188 /* decrease play count */
10189 /* we succeeded to rewind. update play count and then wait for next EOS */
10192 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10194 /* commit attribute */
10195 if (mmf_attrs_commit(attrs))
10196 LOGE("failed to commit attribute\n");
10199 /* count < 0 : repeat continually */
10203 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10204 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10207 LOGW("next uri does not exist\n");
10211 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10212 LOGE("failed to parse profile\n");
10216 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10217 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10218 LOGW("uri type is not supported(%d).", profile.uri_type);
10225 player->uri_info.uri_idx = uri_idx;
10226 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10228 if (mmf_attrs_commit(player->attrs)) {
10229 LOGE("failed to commit.\n");
10233 LOGD("next uri %s(%d)\n", uri, uri_idx);
10239 LOGE("unable to play next path. EOS will be posted soon.\n");
10244 __mmplayer_initialize_next_play(mm_player_t *player)
10250 player->smooth_streaming = FALSE;
10251 player->videodec_linked = 0;
10252 player->audiodec_linked = 0;
10253 player->videosink_linked = 0;
10254 player->audiosink_linked = 0;
10255 player->textsink_linked = 0;
10256 player->is_external_subtitle_present = FALSE;
10257 player->is_external_subtitle_added_now = FALSE;
10258 player->not_supported_codec = MISSING_PLUGIN_NONE;
10259 player->can_support_codec = FOUND_PLUGIN_NONE;
10260 player->pending_seek.is_pending = FALSE;
10261 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10262 player->pending_seek.pos = 0;
10263 player->msg_posted = FALSE;
10264 player->has_many_types = FALSE;
10265 player->no_more_pad = FALSE;
10266 player->not_found_demuxer = 0;
10267 player->doing_seek = FALSE;
10268 player->max_audio_channels = 0;
10269 player->is_subtitle_force_drop = FALSE;
10270 player->play_subtitle = FALSE;
10271 player->adjust_subtitle_pos = 0;
10273 player->total_bitrate = 0;
10274 player->total_maximum_bitrate = 0;
10276 _mmplayer_track_initialize(player);
10277 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10279 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10280 player->bitrate[i] = 0;
10281 player->maximum_bitrate[i] = 0;
10284 if (player->v_stream_caps) {
10285 gst_caps_unref(player->v_stream_caps);
10286 player->v_stream_caps = NULL;
10289 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10291 /* clean found parsers */
10292 if (player->parsers) {
10293 GList *parsers = player->parsers;
10294 for (; parsers; parsers = g_list_next(parsers)) {
10295 gchar *name = parsers->data;
10296 MMPLAYER_FREEIF(name);
10298 g_list_free(player->parsers);
10299 player->parsers = NULL;
10302 /* clean found audio decoders */
10303 if (player->audio_decoders) {
10304 GList *a_dec = player->audio_decoders;
10305 for (; a_dec; a_dec = g_list_next(a_dec)) {
10306 gchar *name = a_dec->data;
10307 MMPLAYER_FREEIF(name);
10309 g_list_free(player->audio_decoders);
10310 player->audio_decoders = NULL;
10317 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10319 MMPlayerGstElement *mainbin = NULL;
10320 MMMessageParamType msg_param = {0,};
10321 GstElement *element = NULL;
10322 MMHandleType attrs = 0;
10324 enum MainElementID elemId = MMPLAYER_M_NUM;
10328 if ((player == NULL) ||
10329 (player->pipeline == NULL) ||
10330 (player->pipeline->mainbin == NULL)) {
10331 LOGE("player is null.\n");
10335 mainbin = player->pipeline->mainbin;
10336 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10338 attrs = MMPLAYER_GET_ATTRS(player);
10340 LOGE("fail to get attributes.\n");
10344 /* Initialize Player values */
10345 __mmplayer_initialize_next_play(player);
10347 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10349 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10350 LOGE("failed to parse profile\n");
10351 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10355 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10356 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10357 LOGE("it's dash or hls. not support.");
10358 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10363 switch (player->profile.uri_type) {
10365 case MM_PLAYER_URI_TYPE_FILE:
10367 LOGD("using filesrc for 'file://' handler.\n");
10368 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10369 LOGE("failed to get storage info");
10373 element = gst_element_factory_make("filesrc", "source");
10376 LOGE("failed to create filesrc\n");
10380 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10383 case MM_PLAYER_URI_TYPE_URL_HTTP:
10385 gchar *user_agent, *cookies, **cookie_list;
10386 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10387 user_agent = cookies = NULL;
10388 cookie_list = NULL;
10390 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10392 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10395 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10397 /* get attribute */
10398 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10399 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10401 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10402 LOGD("get timeout from ini\n");
10403 http_timeout = player->ini.http_timeout;
10406 /* get attribute */
10407 SECURE_LOGD("location : %s\n", player->profile.uri);
10408 SECURE_LOGD("cookies : %s\n", cookies);
10409 SECURE_LOGD("user_agent : %s\n", user_agent);
10410 LOGD("timeout : %d\n", http_timeout);
10412 /* setting property to streaming source */
10413 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10414 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10415 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10417 /* parsing cookies */
10418 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10419 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10421 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10425 LOGE("not support uri type %d\n", player->profile.uri_type);
10430 LOGE("no source element was created.\n");
10434 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10435 LOGE("failed to add source element to pipeline\n");
10436 gst_object_unref(GST_OBJECT(element));
10441 /* take source element */
10442 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10443 mainbin[MMPLAYER_M_SRC].gst = element;
10447 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10448 if (player->streamer == NULL) {
10449 player->streamer = __mm_player_streaming_create();
10450 __mm_player_streaming_initialize(player->streamer);
10453 elemId = MMPLAYER_M_TYPEFIND;
10454 element = gst_element_factory_make("typefind", "typefinder");
10455 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10456 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10458 elemId = MMPLAYER_M_AUTOPLUG;
10459 element = __mmplayer_create_decodebin(player);
10462 /* check autoplug element is OK */
10464 LOGE("can not create element(%d)\n", elemId);
10468 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10469 LOGE("failed to add sinkbin to pipeline\n");
10470 gst_object_unref(GST_OBJECT(element));
10475 mainbin[elemId].id = elemId;
10476 mainbin[elemId].gst = element;
10478 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10479 LOGE("Failed to link src - autoplug(or typefind)\n");
10483 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10484 LOGE("Failed to change state of src element\n");
10488 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10489 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10490 LOGE("Failed to change state of decodebin\n");
10494 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10495 LOGE("Failed to change state of src element\n");
10500 player->gapless.stream_changed = TRUE;
10501 player->gapless.running = TRUE;
10507 MMPLAYER_PLAYBACK_UNLOCK(player);
10509 if (!player->msg_posted) {
10510 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10511 player->msg_posted = TRUE;
10518 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10520 mm_player_selector_t *selector = &player->selector[type];
10521 MMPlayerGstElement *sinkbin = NULL;
10522 enum MainElementID selectorId = MMPLAYER_M_NUM;
10523 enum MainElementID sinkId = MMPLAYER_M_NUM;
10524 GstPad *srcpad = NULL;
10525 GstPad *sinkpad = NULL;
10526 gboolean send_notice = FALSE;
10529 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10531 LOGD("type %d", type);
10534 case MM_PLAYER_TRACK_TYPE_AUDIO:
10535 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10536 sinkId = MMPLAYER_A_BIN;
10537 sinkbin = player->pipeline->audiobin;
10539 case MM_PLAYER_TRACK_TYPE_VIDEO:
10540 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10541 sinkId = MMPLAYER_V_BIN;
10542 sinkbin = player->pipeline->videobin;
10543 send_notice = TRUE;
10545 case MM_PLAYER_TRACK_TYPE_TEXT:
10546 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10547 sinkId = MMPLAYER_T_BIN;
10548 sinkbin = player->pipeline->textbin;
10551 LOGE("requested type is not supportable");
10556 if (player->pipeline->mainbin[selectorId].gst) {
10559 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10561 if (selector->event_probe_id != 0)
10562 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10563 selector->event_probe_id = 0;
10565 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10566 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10568 if (srcpad && sinkpad) {
10569 /* after getting drained signal there is no data flows, so no need to do pad_block */
10570 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10571 gst_pad_unlink(srcpad, sinkpad);
10573 /* send custom event to sink pad to handle it at video sink */
10575 LOGD("send custom event to sinkpad");
10576 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10577 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10578 gst_pad_send_event(sinkpad, event);
10582 gst_object_unref(sinkpad);
10585 gst_object_unref(srcpad);
10588 LOGD("selector release");
10590 /* release and unref requests pad from the selector */
10591 for (n = 0; n < selector->channels->len; n++) {
10592 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10593 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10595 g_ptr_array_set_size(selector->channels, 0);
10597 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10598 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10600 player->pipeline->mainbin[selectorId].gst = NULL;
10608 __mmplayer_deactivate_old_path(mm_player_t *player)
10611 MMPLAYER_RETURN_IF_FAIL(player);
10613 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10614 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10615 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10616 LOGE("deactivate selector error");
10620 _mmplayer_track_destroy(player);
10621 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10623 if (player->streamer) {
10624 __mm_player_streaming_deinitialize(player->streamer);
10625 __mm_player_streaming_destroy(player->streamer);
10626 player->streamer = NULL;
10629 MMPLAYER_PLAYBACK_LOCK(player);
10630 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10637 if (!player->msg_posted) {
10638 MMMessageParamType msg = {0,};
10641 msg.code = MM_ERROR_PLAYER_INTERNAL;
10642 LOGE("next_uri_play> deactivate error");
10644 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10645 player->msg_posted = TRUE;
10650 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10652 int result = MM_ERROR_NONE;
10653 mm_player_t* player = (mm_player_t*) hplayer;
10656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10659 player->http_file_buffering_path = (gchar*)file_path;
10660 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10666 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10668 int result = MM_ERROR_NONE;
10669 mm_player_t* player = (mm_player_t*) hplayer;
10672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10674 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10675 if (mmf_attrs_commit(player->attrs)) {
10676 LOGE("failed to commit the original uri.\n");
10677 result = MM_ERROR_PLAYER_INTERNAL;
10679 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10680 LOGE("failed to add the original uri in the uri list.\n");
10687 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10689 mm_player_t* player = (mm_player_t*) hplayer;
10690 guint num_of_list = 0;
10694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10695 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10697 if (player->pipeline && player->pipeline->textbin) {
10698 LOGE("subtitle path is enabled.\n");
10699 return MM_ERROR_PLAYER_INVALID_STATE;
10702 num_of_list = g_list_length(player->uri_info.uri_list);
10704 if (is_first_path == TRUE) {
10705 if (num_of_list == 0) {
10706 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10707 LOGD("add original path : %s", uri);
10709 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10710 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10712 LOGD("change original path : %s", uri);
10715 MMHandleType attrs = 0;
10716 attrs = MMPLAYER_GET_ATTRS(player);
10718 if (num_of_list == 0) {
10719 char *original_uri = NULL;
10722 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10724 if (!original_uri) {
10725 LOGE("there is no original uri.");
10726 return MM_ERROR_PLAYER_INVALID_STATE;
10729 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10730 player->uri_info.uri_idx = 0;
10732 LOGD("add original path at first : %s(%d)", original_uri);
10736 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10737 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10741 return MM_ERROR_NONE;
10744 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10746 mm_player_t* player = (mm_player_t*) hplayer;
10747 char *next_uri = NULL;
10748 guint num_of_list = 0;
10751 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10753 num_of_list = g_list_length(player->uri_info.uri_list);
10755 if (num_of_list > 0) {
10756 gint uri_idx = player->uri_info.uri_idx;
10758 if (uri_idx < num_of_list-1)
10763 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10764 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10766 *uri = g_strdup(next_uri);
10770 return MM_ERROR_NONE;
10774 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10775 GstCaps *caps, gpointer data)
10777 mm_player_t* player = (mm_player_t*)data;
10778 const gchar* klass = NULL;
10779 const gchar* mime = NULL;
10780 gchar* caps_str = NULL;
10782 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10783 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10784 caps_str = gst_caps_to_string(caps);
10786 LOGW("unknown type of caps : %s from %s",
10787 caps_str, GST_ELEMENT_NAME(elem));
10789 MMPLAYER_FREEIF(caps_str);
10791 /* There is no available codec. */
10792 __mmplayer_check_not_supported_codec(player, klass, mime);
10796 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10797 GstCaps * caps, gpointer data)
10799 mm_player_t* player = (mm_player_t*)data;
10800 const char* mime = NULL;
10801 gboolean ret = TRUE;
10803 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10804 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10806 if (g_str_has_prefix(mime, "audio")) {
10807 GstStructure* caps_structure = NULL;
10808 gint samplerate = 0;
10810 gchar *caps_str = NULL;
10812 caps_structure = gst_caps_get_structure(caps, 0);
10813 gst_structure_get_int(caps_structure, "rate", &samplerate);
10814 gst_structure_get_int(caps_structure, "channels", &channels);
10816 if ((channels > 0 && samplerate == 0)) {
10817 LOGD("exclude audio...");
10821 caps_str = gst_caps_to_string(caps);
10822 /* set it directly because not sent by TAG */
10823 if (g_strrstr(caps_str, "mobile-xmf"))
10824 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10825 MMPLAYER_FREEIF(caps_str);
10826 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10827 MMMessageParamType msg_param;
10828 memset(&msg_param, 0, sizeof(MMMessageParamType));
10829 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10830 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10831 LOGD("video file is not supported on this device");
10833 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10834 LOGD("already video linked");
10837 LOGD("found new stream");
10844 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10846 int ret = MM_ERROR_NONE;
10848 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10850 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10851 GstStructure* str = NULL;
10853 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10855 LOGD("audio codec type: %d", codec_type);
10856 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10857 /* sw codec will be skipped */
10858 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10859 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10860 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10861 ret = MM_ERROR_PLAYER_INTERNAL;
10865 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10866 /* hw codec will be skipped */
10867 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10868 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10869 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10870 ret = MM_ERROR_PLAYER_INTERNAL;
10875 str = gst_caps_get_structure(caps, 0);
10877 gst_structure_get_int(str, "channels", &channels);
10879 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10880 if (player->max_audio_channels < channels)
10881 player->max_audio_channels = channels;
10883 /* set stream information */
10884 if (!player->audiodec_linked)
10885 __mmplayer_set_audio_attrs(player, caps);
10887 /* update codec info */
10888 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10889 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10890 player->audiodec_linked = 1;
10892 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10894 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10896 LOGD("video codec type: %d", codec_type);
10897 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10898 /* sw codec is skipped */
10899 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10900 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10901 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10902 ret = MM_ERROR_PLAYER_INTERNAL;
10906 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10907 /* hw codec is skipped */
10908 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10909 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10910 ret = MM_ERROR_PLAYER_INTERNAL;
10915 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10916 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10918 /* mark video decoder for acquire */
10919 if (player->video_decoder_resource == NULL) {
10920 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10921 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10922 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10923 &player->video_decoder_resource)
10924 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10925 LOGE("could not mark video_decoder resource for acquire");
10926 ret = MM_ERROR_PLAYER_INTERNAL;
10930 LOGW("video decoder resource is already acquired, skip it.");
10931 ret = MM_ERROR_PLAYER_INTERNAL;
10935 player->interrupted_by_resource = FALSE;
10936 /* acquire resources for video playing */
10937 if (mm_resource_manager_commit(player->resource_manager)
10938 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10939 LOGE("could not acquire resources for video decoding\n");
10940 ret = MM_ERROR_PLAYER_INTERNAL;
10945 /* update codec info */
10946 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10947 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10948 player->videodec_linked = 1;
10956 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10957 GstCaps* caps, GstElementFactory* factory, gpointer data)
10959 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10960 We are defining our own and will be removed when it actually exposed */
10962 GST_AUTOPLUG_SELECT_TRY,
10963 GST_AUTOPLUG_SELECT_EXPOSE,
10964 GST_AUTOPLUG_SELECT_SKIP
10965 } GstAutoplugSelectResult;
10967 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10968 mm_player_t* player = (mm_player_t*)data;
10970 gchar* factory_name = NULL;
10971 gchar* caps_str = NULL;
10972 const gchar* klass = NULL;
10975 factory_name = GST_OBJECT_NAME(factory);
10976 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10977 caps_str = gst_caps_to_string(caps);
10979 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10981 /* store type string */
10982 if (player->type == NULL) {
10983 player->type = gst_caps_to_string(caps);
10984 __mmplayer_update_content_type_info(player);
10987 /* filtering exclude keyword */
10988 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10989 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10990 LOGW("skipping [%s] by exculde keyword [%s]\n",
10991 factory_name, player->ini.exclude_element_keyword[idx]);
10993 result = GST_AUTOPLUG_SELECT_SKIP;
10998 /* exclude webm format */
10999 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
11000 * because webm format is not supportable.
11001 * If webm is disabled in "autoplug-continue", there is no state change
11002 * failure or error because the decodebin will expose the pad directly.
11003 * It make MSL invoke _prepare_async_callback.
11004 * So, we need to disable webm format in "autoplug-select" */
11005 if (caps_str && strstr(caps_str, "webm")) {
11006 LOGW("webm is not supported");
11007 result = GST_AUTOPLUG_SELECT_SKIP;
11011 /* check factory class for filtering */
11012 /* NOTE : msl don't need to use image plugins.
11013 * So, those plugins should be skipped for error handling.
11015 if (g_strrstr(klass, "Codec/Decoder/Image")) {
11016 LOGD("skipping [%s] by not required\n", factory_name);
11017 result = GST_AUTOPLUG_SELECT_SKIP;
11021 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
11022 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
11023 // TO CHECK : subtitle if needed, add subparse exception.
11024 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
11025 result = GST_AUTOPLUG_SELECT_SKIP;
11029 if (g_strrstr(factory_name, "mpegpsdemux")) {
11030 LOGD("skipping PS container - not support\n");
11031 result = GST_AUTOPLUG_SELECT_SKIP;
11035 if (g_strrstr(factory_name, "mssdemux"))
11036 player->smooth_streaming = TRUE;
11038 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
11039 (g_strrstr(klass, "Codec/Decoder/Video"))) {
11042 GstStructure *str = NULL;
11043 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11045 /* don't make video because of not required */
11046 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11047 (player->set_mode.media_packet_video_stream == FALSE)) {
11048 LOGD("no video because it's not required. -> return expose");
11049 result = GST_AUTOPLUG_SELECT_EXPOSE;
11053 /* get w/h for omx state-tune */
11054 /* FIXME: deprecated? */
11055 str = gst_caps_get_structure(caps, 0);
11056 gst_structure_get_int(str, "width", &width);
11059 if (player->v_stream_caps) {
11060 gst_caps_unref(player->v_stream_caps);
11061 player->v_stream_caps = NULL;
11064 player->v_stream_caps = gst_caps_copy(caps);
11065 LOGD("take caps for video state tune");
11066 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11070 if (g_strrstr(klass, "Codec/Decoder")) {
11071 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11072 LOGD("skipping %s codec", factory_name);
11073 result = GST_AUTOPLUG_SELECT_SKIP;
11079 MMPLAYER_FREEIF(caps_str);
11085 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11088 //mm_player_t* player = (mm_player_t*)data;
11089 GstCaps* caps = NULL;
11091 LOGD("[Decodebin2] pad-removed signal\n");
11093 caps = gst_pad_query_caps(new_pad, NULL);
11095 gchar* caps_str = NULL;
11096 caps_str = gst_caps_to_string(caps);
11098 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11100 MMPLAYER_FREEIF(caps_str);
11101 gst_caps_unref(caps);
11106 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11108 mm_player_t* player = (mm_player_t*)data;
11109 GstIterator *iter = NULL;
11110 GValue item = { 0, };
11111 GstPad *pad = NULL;
11112 gboolean done = FALSE;
11113 gboolean is_all_drained = TRUE;
11116 MMPLAYER_RETURN_IF_FAIL(player);
11118 LOGD("__mmplayer_gst_decode_drained");
11120 if (player->use_deinterleave == TRUE) {
11121 LOGD("group playing mode.");
11125 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11126 LOGW("Fail to get cmd lock");
11130 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11131 !__mmplayer_verify_next_play_path(player)) {
11132 LOGD("decoding is finished.");
11133 __mmplayer_reset_gapless_state(player);
11134 MMPLAYER_CMD_UNLOCK(player);
11138 player->gapless.reconfigure = TRUE;
11140 /* check decodebin src pads whether they received EOS or not */
11141 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11144 switch (gst_iterator_next(iter, &item)) {
11145 case GST_ITERATOR_OK:
11146 pad = g_value_get_object(&item);
11147 if (pad && !GST_PAD_IS_EOS(pad)) {
11148 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11149 is_all_drained = FALSE;
11152 g_value_reset(&item);
11154 case GST_ITERATOR_RESYNC:
11155 gst_iterator_resync(iter);
11157 case GST_ITERATOR_ERROR:
11158 case GST_ITERATOR_DONE:
11163 g_value_unset(&item);
11164 gst_iterator_free(iter);
11166 if (!is_all_drained) {
11167 LOGD("Wait util the all pads get EOS.");
11168 MMPLAYER_CMD_UNLOCK(player);
11173 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11174 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11176 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11177 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11178 __mmplayer_deactivate_old_path(player);
11179 MMPLAYER_CMD_UNLOCK(player);
11185 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11187 mm_player_t* player = (mm_player_t*)data;
11188 const gchar* klass = NULL;
11189 gchar* factory_name = NULL;
11191 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11192 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11194 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11196 if (__mmplayer_add_dump_buffer_probe(player, element))
11197 LOGD("add buffer probe");
11200 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11201 gchar* selected = NULL;
11202 selected = g_strdup(GST_ELEMENT_NAME(element));
11203 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11207 if (g_strrstr(klass, "Parser")) {
11208 gchar* selected = NULL;
11210 selected = g_strdup(factory_name);
11211 player->parsers = g_list_append(player->parsers, selected);
11214 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11215 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11216 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11218 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11219 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11221 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11222 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11223 "max-video-width", player->adaptive_info.limit.width,
11224 "max-video-height", player->adaptive_info.limit.height, NULL);
11226 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11227 /* FIXIT : first value will be overwritten if there's more
11228 * than 1 demuxer/parser
11231 //LOGD("plugged element is demuxer. take it\n");
11232 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11233 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11235 /*Added for multi audio support */ // Q. del?
11236 if (g_strrstr(klass, "Demux")) {
11237 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11238 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11242 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11243 int surface_type = 0;
11245 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11248 // to support trust-zone only
11249 if (g_strrstr(factory_name, "asfdemux")) {
11250 LOGD("set file-location %s\n", player->profile.uri);
11251 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11253 if (player->video_hub_download_mode == TRUE)
11254 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11255 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11256 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11257 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11258 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11259 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11260 (__mmplayer_is_only_mp3_type(player->type))) {
11261 LOGD("[mpegaudioparse] set streaming pull mode.");
11262 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11264 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11265 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11268 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11269 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11270 LOGD("plugged element is multiqueue. take it\n");
11272 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11273 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11275 if (!MMPLAYER_IS_HTTP_PD(player) &&
11276 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11277 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11278 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11279 __mm_player_streaming_set_multiqueue(player->streamer,
11282 player->ini.http_buffering_time,
11284 player->ini.http_buffering_limit);
11286 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11293 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11296 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11298 if (MMPLAYER_IS_STREAMING(player))
11301 /* This callback can be set to music player only. */
11302 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11303 LOGW("audio callback is not supported for video");
11307 if (player->audio_stream_cb) {
11308 GstPad *pad = NULL;
11310 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11313 LOGE("failed to get sink pad from audiosink to probe data\n");
11316 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11317 __mmplayer_audio_stream_probe, player, NULL);
11319 gst_object_unref(pad);
11323 LOGE("There is no audio callback to configure.\n");
11333 __mmplayer_release_misc(mm_player_t* player)
11336 bool cur_mode = player->set_mode.rich_audio;
11339 MMPLAYER_RETURN_IF_FAIL(player);
11341 player->video_stream_cb = NULL;
11342 player->video_stream_cb_user_param = NULL;
11343 player->video_stream_prerolled = FALSE;
11345 player->audio_stream_cb = NULL;
11346 player->audio_stream_render_cb_ex = NULL;
11347 player->audio_stream_cb_user_param = NULL;
11348 player->audio_stream_sink_sync = false;
11350 player->video_stream_changed_cb = NULL;
11351 player->video_stream_changed_cb_user_param = NULL;
11353 player->audio_stream_changed_cb = NULL;
11354 player->audio_stream_changed_cb_user_param = NULL;
11356 player->sent_bos = FALSE;
11357 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11359 player->doing_seek = FALSE;
11361 player->total_bitrate = 0;
11362 player->total_maximum_bitrate = 0;
11364 player->not_found_demuxer = 0;
11366 player->last_position = 0;
11367 player->duration = 0;
11368 player->http_content_size = 0;
11369 player->not_supported_codec = MISSING_PLUGIN_NONE;
11370 player->can_support_codec = FOUND_PLUGIN_NONE;
11371 player->pending_seek.is_pending = FALSE;
11372 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11373 player->pending_seek.pos = 0;
11374 player->msg_posted = FALSE;
11375 player->has_many_types = FALSE;
11376 player->max_audio_channels = 0;
11377 player->video_share_api_delta = 0;
11378 player->video_share_clock_delta = 0;
11379 player->is_subtitle_force_drop = FALSE;
11380 player->play_subtitle = FALSE;
11381 player->adjust_subtitle_pos = 0;
11382 player->last_multiwin_status = FALSE;
11383 player->has_closed_caption = FALSE;
11384 player->set_mode.media_packet_video_stream = FALSE;
11385 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11386 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11388 player->set_mode.rich_audio = cur_mode;
11390 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11391 player->bitrate[i] = 0;
11392 player->maximum_bitrate[i] = 0;
11395 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11397 /* remove media stream cb(appsrc cb) */
11398 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11399 player->media_stream_buffer_status_cb[i] = NULL;
11400 player->media_stream_seek_data_cb[i] = NULL;
11401 player->buffer_cb_user_param[i] = NULL;
11402 player->seek_cb_user_param[i] = NULL;
11404 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11406 /* free memory related to audio effect */
11407 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11409 if (player->adaptive_info.var_list) {
11410 g_list_free_full(player->adaptive_info.var_list, g_free);
11411 player->adaptive_info.var_list = NULL;
11414 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11415 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11416 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11418 /* Reset video360 settings to their defaults in case if the pipeline is to be
11421 player->video360_metadata.is_spherical = -1;
11422 player->is_openal_plugin_used = FALSE;
11424 player->is_content_spherical = FALSE;
11425 player->is_video360_enabled = TRUE;
11426 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11427 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11428 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11429 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11430 player->video360_zoom = 1.0f;
11431 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11432 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11434 player->sound.rg_enable = false;
11440 __mmplayer_release_misc_post(mm_player_t* player)
11442 char *original_uri = NULL;
11445 /* player->pipeline is already released before. */
11447 MMPLAYER_RETURN_IF_FAIL(player);
11449 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11451 /* clean found parsers */
11452 if (player->parsers) {
11453 GList *parsers = player->parsers;
11454 for (; parsers; parsers = g_list_next(parsers)) {
11455 gchar *name = parsers->data;
11456 MMPLAYER_FREEIF(name);
11458 g_list_free(player->parsers);
11459 player->parsers = NULL;
11462 /* clean found audio decoders */
11463 if (player->audio_decoders) {
11464 GList *a_dec = player->audio_decoders;
11465 for (; a_dec; a_dec = g_list_next(a_dec)) {
11466 gchar *name = a_dec->data;
11467 MMPLAYER_FREEIF(name);
11469 g_list_free(player->audio_decoders);
11470 player->audio_decoders = NULL;
11473 /* clean the uri list except original uri */
11474 if (player->uri_info.uri_list) {
11475 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11477 if (player->attrs) {
11478 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11479 LOGD("restore original uri = %s\n", original_uri);
11481 if (mmf_attrs_commit(player->attrs))
11482 LOGE("failed to commit the original uri.\n");
11485 GList *uri_list = player->uri_info.uri_list;
11486 for (; uri_list; uri_list = g_list_next(uri_list)) {
11487 gchar *uri = uri_list->data;
11488 MMPLAYER_FREEIF(uri);
11490 g_list_free(player->uri_info.uri_list);
11491 player->uri_info.uri_list = NULL;
11494 /* clear the audio stream buffer list */
11495 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11497 /* clear the video stream bo list */
11498 __mmplayer_video_stream_destroy_bo_list(player);
11499 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11501 if (player->profile.input_mem.buf) {
11502 free(player->profile.input_mem.buf);
11503 player->profile.input_mem.buf = NULL;
11505 player->profile.input_mem.len = 0;
11506 player->profile.input_mem.offset = 0;
11508 player->uri_info.uri_idx = 0;
11512 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11514 GstElement *element = NULL;
11517 LOGD("creating %s to plug\n", name);
11519 element = gst_element_factory_make(name, NULL);
11521 LOGE("failed to create queue\n");
11525 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11526 LOGE("failed to set state READY to %s\n", name);
11527 gst_object_unref(element);
11531 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11532 LOGE("failed to add %s\n", name);
11533 gst_object_unref(element);
11537 sinkpad = gst_element_get_static_pad(element, "sink");
11539 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11540 LOGE("failed to link %s\n", name);
11541 gst_object_unref(sinkpad);
11542 gst_object_unref(element);
11546 LOGD("linked %s to pipeline successfully\n", name);
11548 gst_object_unref(sinkpad);
11554 __mmplayer_check_subtitle(mm_player_t* player)
11556 MMHandleType attrs = 0;
11557 char *subtitle_uri = NULL;
11561 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11563 /* get subtitle attribute */
11564 attrs = MMPLAYER_GET_ATTRS(player);
11568 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11569 if (!subtitle_uri || !strlen(subtitle_uri))
11572 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11573 player->is_external_subtitle_present = TRUE;
11581 __mmplayer_can_extract_pcm(mm_player_t* player)
11583 MMHandleType attrs = 0;
11584 gboolean sound_extraction = FALSE;
11586 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11588 attrs = MMPLAYER_GET_ATTRS(player);
11590 LOGE("fail to get attributes.");
11594 /* get sound_extraction property */
11595 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11597 if (!sound_extraction) {
11598 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11606 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11609 MMMessageParamType msg_param;
11610 gchar *msg_src_element = NULL;
11611 GstStructure *s = NULL;
11612 guint error_id = 0;
11613 gchar *error_string = NULL;
11617 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11618 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11620 s = gst_structure_copy(gst_message_get_structure(message));
11623 if (!gst_structure_get_uint(s, "error_id", &error_id))
11624 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11626 switch (error_id) {
11627 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11628 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11630 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11631 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11633 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11634 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11636 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11637 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11639 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11640 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11642 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11643 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11645 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11646 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11648 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11649 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11651 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11652 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11654 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11655 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11657 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11658 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11660 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11661 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11663 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11664 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11666 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11667 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11669 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11670 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11672 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11673 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11675 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11676 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11678 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11679 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11681 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11682 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11684 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11685 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11687 case MMPLAYER_STREAMING_ERROR_GONE:
11688 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11690 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11691 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11693 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11694 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11696 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11697 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11699 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11700 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11702 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11703 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11705 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11706 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11708 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11709 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11711 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11712 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11714 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11715 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11717 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11718 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11720 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11721 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11723 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11724 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11726 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11727 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11729 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11730 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11732 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11733 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11735 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11736 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11738 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11739 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11741 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11742 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11744 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11745 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11747 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11748 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11750 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11751 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11753 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11754 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11756 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11757 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11759 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11760 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11764 gst_structure_free(s);
11765 return MM_ERROR_PLAYER_STREAMING_FAIL;
11769 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11771 msg_param.data = (void *) error_string;
11773 if (message->src) {
11774 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11776 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11777 msg_src_element, msg_param.code, (char*)msg_param.data);
11780 /* post error to application */
11781 if (!player->msg_posted) {
11782 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11784 /* don't post more if one was sent already */
11785 player->msg_posted = TRUE;
11787 LOGD("skip error post because it's sent already.\n");
11789 gst_structure_free(s);
11791 g_free(error_string);
11798 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11800 MMPLAYER_RETURN_IF_FAIL(player);
11802 /* post now if delay is zero */
11803 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11804 LOGD("eos delay is zero. posting EOS now\n");
11805 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11807 if (player->set_mode.pcm_extraction)
11808 __mmplayer_cancel_eos_timer(player);
11813 /* cancel if existing */
11814 __mmplayer_cancel_eos_timer(player);
11816 /* init new timeout */
11817 /* NOTE : consider give high priority to this timer */
11818 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11820 player->eos_timer = g_timeout_add(delay_in_ms,
11821 __mmplayer_eos_timer_cb, player);
11823 player->context.global_default = g_main_context_default();
11824 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11826 /* check timer is valid. if not, send EOS now */
11827 if (player->eos_timer == 0) {
11828 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11829 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11834 __mmplayer_cancel_eos_timer(mm_player_t* player)
11836 MMPLAYER_RETURN_IF_FAIL(player);
11838 if (player->eos_timer) {
11839 LOGD("cancel eos timer");
11840 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11841 player->eos_timer = 0;
11848 __mmplayer_eos_timer_cb(gpointer u_data)
11850 mm_player_t* player = NULL;
11851 MMHandleType attrs = 0;
11854 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11856 player = (mm_player_t*) u_data;
11857 attrs = MMPLAYER_GET_ATTRS(player);
11859 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11862 gint ret_value = 0;
11863 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11864 if (ret_value != MM_ERROR_NONE)
11865 LOGE("seeking to 0 failed in repeat play");
11868 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11871 /* we are returning FALSE as we need only one posting */
11875 /* sending event to one of sinkelements */
11877 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11879 GstEvent * event2 = NULL;
11880 GList *sinks = NULL;
11881 gboolean res = FALSE;
11884 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11885 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11887 /* While adding subtitles in live feeds seek is getting called.
11888 Adding defensive check in framework layer.*/
11889 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11890 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11891 LOGE("Should not send seek event during live playback");
11896 if (player->play_subtitle)
11897 event2 = gst_event_copy((const GstEvent *)event);
11899 sinks = player->sink_elements;
11901 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11903 if (GST_IS_ELEMENT(sink)) {
11904 /* keep ref to the event */
11905 gst_event_ref(event);
11907 if ((res = gst_element_send_event(sink, event))) {
11908 LOGD("sending event[%s] to sink element [%s] success!\n",
11909 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11911 /* rtsp case, asyn_done is not called after seek during pause state */
11912 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11913 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11914 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11915 LOGD("RTSP seek completed, after pause state..\n");
11916 player->doing_seek = FALSE;
11917 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11923 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11924 sinks = g_list_next(sinks);
11931 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11932 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11935 sinks = g_list_next(sinks);
11938 /* Note : Textbin is not linked to the video or audio bin.
11939 * It needs to send the event to the text sink seperatelly.
11941 if (player->play_subtitle && player->pipeline) {
11942 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11944 if (GST_IS_ELEMENT(text_sink)) {
11945 /* keep ref to the event */
11946 gst_event_ref(event2);
11948 if ((res = gst_element_send_event(text_sink, event2)))
11949 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11950 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11952 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11953 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11955 gst_event_unref(event2);
11959 gst_event_unref(event);
11967 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11971 MMPLAYER_RETURN_IF_FAIL(player);
11972 MMPLAYER_RETURN_IF_FAIL(sink);
11974 player->sink_elements =
11975 g_list_append(player->sink_elements, sink);
11981 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11985 MMPLAYER_RETURN_IF_FAIL(player);
11986 MMPLAYER_RETURN_IF_FAIL(sink);
11988 player->sink_elements =
11989 g_list_remove(player->sink_elements, sink);
11995 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11996 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11997 gint64 cur, GstSeekType stop_type, gint64 stop)
11999 GstEvent* event = NULL;
12000 gboolean result = FALSE;
12004 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12006 if (player->pipeline && player->pipeline->textbin)
12007 __mmplayer_drop_subtitle(player, FALSE);
12009 event = gst_event_new_seek(rate, format, flags, cur_type,
12010 cur, stop_type, stop);
12012 result = __gst_send_event_to_sink(player, event);
12019 /* NOTE : be careful with calling this api. please refer to below glib comment
12020 * glib comment : Note that there is a bug in GObject that makes this function much
12021 * less useful than it might seem otherwise. Once gobject is disposed, the callback
12022 * will no longer be called, but, the signal handler is not currently disconnected.
12023 * If the instance is itself being freed at the same time than this doesn't matter,
12024 * since the signal will automatically be removed, but if instance persists,
12025 * then the signal handler will leak. You should not remove the signal yourself
12026 * because in a future versions of GObject, the handler will automatically be
12029 * It's possible to work around this problem in a way that will continue to work
12030 * with future versions of GObject by checking that the signal handler is still
12031 * connected before disconnected it:
12033 * if (g_signal_handler_is_connected(instance, id))
12034 * g_signal_handler_disconnect(instance, id);
12037 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
12039 GList* sig_list = NULL;
12040 MMPlayerSignalItem* item = NULL;
12044 MMPLAYER_RETURN_IF_FAIL(player);
12046 LOGD("release signals type : %d", type);
12048 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12049 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12050 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12051 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12052 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12053 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12057 sig_list = player->signals[type];
12059 for (; sig_list; sig_list = sig_list->next) {
12060 item = sig_list->data;
12062 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12063 if (g_signal_handler_is_connected(item->obj, item->sig))
12064 g_signal_handler_disconnect(item->obj, item->sig);
12067 MMPLAYER_FREEIF(item);
12070 g_list_free(player->signals[type]);
12071 player->signals[type] = NULL;
12078 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12080 mm_player_t* player = 0;
12081 int prev_display_surface_type = 0;
12082 void *prev_display_overlay = NULL;
12083 const gchar *klass = NULL;
12084 gchar *cur_videosink_name = NULL;
12087 int num_of_dec = 2; /* DEC1, DEC2 */
12091 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12092 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12094 player = MM_PLAYER_CAST(handle);
12096 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12097 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12099 return MM_ERROR_INVALID_ARGUMENT;
12102 /* load previous attributes */
12103 if (player->attrs) {
12104 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12105 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12106 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12107 if (prev_display_surface_type == surface_type) {
12108 LOGD("incoming display surface type is same as previous one, do nothing..");
12110 return MM_ERROR_NONE;
12113 LOGE("failed to load attributes");
12115 return MM_ERROR_PLAYER_INTERNAL;
12118 /* check videosink element is created */
12119 if (!player->pipeline || !player->pipeline->videobin ||
12120 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12121 LOGD("videosink element is not yet ready");
12123 /* videobin is not created yet, so we just set attributes related to display surface */
12124 LOGD("store display attribute for given surface type(%d)", surface_type);
12125 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12126 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12127 if (mmf_attrs_commit(player->attrs)) {
12128 LOGE("failed to commit attribute");
12130 return MM_ERROR_PLAYER_INTERNAL;
12133 return MM_ERROR_NONE;
12135 /* get player command status */
12136 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12137 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12139 return MM_ERROR_PLAYER_INVALID_STATE;
12142 /* surface change */
12143 for (i = 0 ; i < num_of_dec ; i++) {
12144 if (player->pipeline->mainbin &&
12145 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12146 GstElementFactory *decfactory;
12147 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12149 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12150 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12151 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12152 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12156 LOGW("success to changing display surface(%d)", surface_type);
12158 return MM_ERROR_NONE;
12160 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12161 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12165 LOGW("success to changing display surface(%d)", surface_type);
12167 return MM_ERROR_NONE;
12170 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12171 ret = MM_ERROR_PLAYER_INTERNAL;
12180 /* rollback to previous attributes */
12181 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12182 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12183 if (mmf_attrs_commit(player->attrs)) {
12184 LOGE("failed to commit attributes to rollback");
12186 return MM_ERROR_PLAYER_INTERNAL;
12192 /* NOTE : It does not support some use cases, eg using colorspace converter */
12194 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12196 GstPad *src_pad_dec = NULL;
12197 GstPad *sink_pad_videosink = NULL;
12198 GstPad *sink_pad_videobin = NULL;
12199 GstClock *clock = NULL;
12200 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12201 int ret = MM_ERROR_NONE;
12202 gboolean is_audiobin_created = TRUE;
12206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12207 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12208 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12210 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12211 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12213 /* get information whether if audiobin is created */
12214 if (!player->pipeline->audiobin ||
12215 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12216 LOGW("audiobin is null, this video content may not have audio data");
12217 is_audiobin_created = FALSE;
12220 /* get current state of player */
12221 previous_state = MMPLAYER_CURRENT_STATE(player);
12222 LOGD("previous state(%d)", previous_state);
12225 /* get src pad of decoder and block it */
12226 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12227 if (!src_pad_dec) {
12228 LOGE("failed to get src pad from decode in mainbin");
12229 return MM_ERROR_PLAYER_INTERNAL;
12232 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12233 LOGW("trying to block pad(video)");
12234 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12235 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12238 LOGE("failed to set block pad(video)");
12239 return MM_ERROR_PLAYER_INTERNAL;
12241 LOGW("pad is blocked(video)");
12243 /* no data flows, so no need to do pad_block */
12244 if (player->doing_seek)
12245 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12247 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12251 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12252 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12253 LOGE("failed to remove previous ghost_pad for videobin");
12254 return MM_ERROR_PLAYER_INTERNAL;
12257 /* change state of videobin to NULL */
12258 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12259 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12260 if (ret != GST_STATE_CHANGE_SUCCESS) {
12261 LOGE("failed to change state of videobin to NULL");
12262 return MM_ERROR_PLAYER_INTERNAL;
12265 /* unlink between decoder and videobin and remove previous videosink from videobin */
12266 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12267 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12268 LOGE("failed to remove former videosink from videobin");
12269 return MM_ERROR_PLAYER_INTERNAL;
12272 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12274 /* create a new videosink and add it to videobin */
12275 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12276 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12277 LOGE("failed to create videosink element\n");
12279 return MM_ERROR_PLAYER_INTERNAL;
12281 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12282 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12283 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12285 /* save attributes */
12286 if (player->attrs) {
12287 /* set a new display surface type */
12288 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12289 /* set a new diplay overlay */
12290 switch (surface_type) {
12291 case MM_DISPLAY_SURFACE_OVERLAY:
12292 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12293 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12296 LOGE("invalid type(%d) for changing display surface", surface_type);
12298 return MM_ERROR_INVALID_ARGUMENT;
12300 if (mmf_attrs_commit(player->attrs)) {
12301 LOGE("failed to commit");
12303 return MM_ERROR_PLAYER_INTERNAL;
12306 LOGE("player->attrs is null, failed to save attributes");
12308 return MM_ERROR_PLAYER_INTERNAL;
12311 /* update video param */
12312 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12313 LOGE("failed to update video param");
12314 return MM_ERROR_PLAYER_INTERNAL;
12317 /* change state of videobin to READY */
12318 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12319 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12320 if (ret != GST_STATE_CHANGE_SUCCESS) {
12321 LOGE("failed to change state of videobin to READY");
12322 return MM_ERROR_PLAYER_INTERNAL;
12325 /* change ghostpad */
12326 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12327 if (!sink_pad_videosink) {
12328 LOGE("failed to get sink pad from videosink element");
12329 return MM_ERROR_PLAYER_INTERNAL;
12331 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12332 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12333 LOGE("failed to set active to ghost_pad");
12334 return MM_ERROR_PLAYER_INTERNAL;
12336 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12337 LOGE("failed to change ghostpad for videobin");
12338 return MM_ERROR_PLAYER_INTERNAL;
12340 gst_object_unref(sink_pad_videosink);
12342 /* link decoder with videobin */
12343 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12344 if (!sink_pad_videobin) {
12345 LOGE("failed to get sink pad from videobin");
12346 return MM_ERROR_PLAYER_INTERNAL;
12348 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12349 LOGE("failed to link");
12350 return MM_ERROR_PLAYER_INTERNAL;
12352 gst_object_unref(sink_pad_videobin);
12354 /* clock setting for a new videosink plugin */
12355 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12356 so we set it from audiosink plugin or pipeline(system clock) */
12357 if (!is_audiobin_created) {
12358 LOGW("audiobin is not created, get clock from pipeline..");
12359 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12361 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12365 GstClockTime base_time;
12366 LOGD("set the clock to videosink");
12367 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12368 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12370 LOGD("got clock of videosink");
12371 now = gst_clock_get_time(clock);
12372 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12373 LOGD("at time %" GST_TIME_FORMAT ", base %"
12374 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12376 LOGE("failed to get clock of videosink after setting clock");
12377 return MM_ERROR_PLAYER_INTERNAL;
12380 LOGW("failed to get clock, maybe it is the time before first playing");
12382 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12383 /* change state of videobin to PAUSED */
12384 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12385 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12386 if (ret != GST_STATE_CHANGE_FAILURE) {
12387 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12389 LOGE("failed to change state of videobin to PLAYING");
12390 return MM_ERROR_PLAYER_INTERNAL;
12393 /* release blocked and unref src pad of video decoder */
12395 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12396 LOGE("failed to set pad blocked FALSE(video)");
12397 return MM_ERROR_PLAYER_INTERNAL;
12400 LOGW("pad is unblocked(video)");
12402 if (player->doing_seek)
12403 LOGW("not completed seek(%d)", player->doing_seek);
12404 /* change state of videobin to PAUSED */
12405 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12406 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12407 if (ret != GST_STATE_CHANGE_FAILURE) {
12408 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12410 LOGE("failed to change state of videobin to PLAYING");
12411 return MM_ERROR_PLAYER_INTERNAL;
12414 /* already skipped pad block */
12415 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12418 /* do get/set position for new videosink plugin */
12420 unsigned long position = 0;
12421 gint64 pos_msec = 0;
12423 LOGD("do get/set position for new videosink plugin");
12424 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12425 LOGE("failed to get position");
12426 return MM_ERROR_PLAYER_INTERNAL;
12428 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12429 /* accurate seek */
12430 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12431 LOGE("failed to set position");
12432 return MM_ERROR_PLAYER_INTERNAL;
12435 /* key unit seek */
12436 pos_msec = position * G_GINT64_CONSTANT(1000000);
12437 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12438 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12439 GST_SEEK_TYPE_SET, pos_msec,
12440 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12442 LOGE("failed to set position");
12443 return MM_ERROR_PLAYER_INTERNAL;
12449 gst_object_unref(src_pad_dec);
12450 LOGD("success to change sink");
12454 return MM_ERROR_NONE;
12458 /* Note : if silent is true, then subtitle would not be displayed. :*/
12459 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12461 mm_player_t* player = (mm_player_t*) hplayer;
12465 /* check player handle */
12466 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12468 player->set_mode.subtitle_off = silent;
12470 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12474 return MM_ERROR_NONE;
12477 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12479 MMPlayerGstElement* mainbin = NULL;
12480 MMPlayerGstElement* textbin = NULL;
12481 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12482 GstState current_state = GST_STATE_VOID_PENDING;
12483 GstState element_state = GST_STATE_VOID_PENDING;
12484 GstState element_pending_state = GST_STATE_VOID_PENDING;
12486 GstEvent *event = NULL;
12487 int result = MM_ERROR_NONE;
12489 GstClock *curr_clock = NULL;
12490 GstClockTime base_time, start_time, curr_time;
12495 /* check player handle */
12496 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12497 player->pipeline &&
12498 player->pipeline->mainbin &&
12499 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12501 mainbin = player->pipeline->mainbin;
12502 textbin = player->pipeline->textbin;
12504 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12506 // sync clock with current pipeline
12507 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12508 curr_time = gst_clock_get_time(curr_clock);
12510 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12511 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12513 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12514 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12516 if (current_state > GST_STATE_READY) {
12517 // sync state with current pipeline
12518 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12519 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12520 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12522 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12523 if (GST_STATE_CHANGE_FAILURE == ret) {
12524 LOGE("fail to state change.\n");
12525 result = MM_ERROR_PLAYER_INTERNAL;
12530 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12531 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12534 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12535 gst_object_unref(curr_clock);
12538 // seek to current position
12539 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12540 result = MM_ERROR_PLAYER_INVALID_STATE;
12541 LOGE("gst_element_query_position failed, invalid state\n");
12545 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12546 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);
12548 __gst_send_event_to_sink(player, event);
12550 result = MM_ERROR_PLAYER_INTERNAL;
12551 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12555 /* sync state with current pipeline */
12556 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12557 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12558 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12560 return MM_ERROR_NONE;
12563 /* release text pipeline resource */
12564 player->textsink_linked = 0;
12566 /* release signal */
12567 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12569 /* release textbin with it's childs */
12570 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12571 MMPLAYER_FREEIF(player->pipeline->textbin);
12572 player->pipeline->textbin = NULL;
12574 /* release subtitle elem */
12575 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12576 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12582 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12584 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12585 GstState current_state = GST_STATE_VOID_PENDING;
12587 MMHandleType attrs = 0;
12588 MMPlayerGstElement* mainbin = NULL;
12589 MMPlayerGstElement* textbin = NULL;
12591 gchar* subtitle_uri = NULL;
12592 int result = MM_ERROR_NONE;
12593 const gchar *charset = NULL;
12597 /* check player handle */
12598 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12599 player->pipeline &&
12600 player->pipeline->mainbin &&
12601 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12602 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12604 mainbin = player->pipeline->mainbin;
12605 textbin = player->pipeline->textbin;
12607 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12608 if (current_state < GST_STATE_READY) {
12609 result = MM_ERROR_PLAYER_INVALID_STATE;
12610 LOGE("Pipeline is not in proper state\n");
12614 attrs = MMPLAYER_GET_ATTRS(player);
12616 LOGE("cannot get content attribute\n");
12617 result = MM_ERROR_PLAYER_INTERNAL;
12621 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12622 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12623 LOGE("subtitle uri is not proper filepath\n");
12624 result = MM_ERROR_PLAYER_INVALID_URI;
12628 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12629 LOGE("failed to get storage info of subtitle path");
12630 result = MM_ERROR_PLAYER_INVALID_URI;
12634 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12635 LOGD("new subtitle file path is [%s]\n", filepath);
12637 if (!strcmp(filepath, subtitle_uri)) {
12638 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12641 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12642 if (mmf_attrs_commit(player->attrs)) {
12643 LOGE("failed to commit.\n");
12648 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12649 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12650 player->subtitle_language_list = NULL;
12651 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12653 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12654 if (ret != GST_STATE_CHANGE_SUCCESS) {
12655 LOGE("failed to change state of textbin to READY");
12656 result = MM_ERROR_PLAYER_INTERNAL;
12660 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12661 if (ret != GST_STATE_CHANGE_SUCCESS) {
12662 LOGE("failed to change state of subparse to READY");
12663 result = MM_ERROR_PLAYER_INTERNAL;
12667 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12668 if (ret != GST_STATE_CHANGE_SUCCESS) {
12669 LOGE("failed to change state of filesrc to READY");
12670 result = MM_ERROR_PLAYER_INTERNAL;
12674 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12676 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12678 charset = util_get_charset(filepath);
12680 LOGD("detected charset is %s\n", charset);
12681 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12684 result = _mmplayer_sync_subtitle_pipeline(player);
12691 /* API to switch between external subtitles */
12692 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12694 int result = MM_ERROR_NONE;
12695 mm_player_t* player = (mm_player_t*)hplayer;
12700 /* check player handle */
12701 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12703 /* filepath can be null in idle state */
12705 /* check file path */
12706 if ((path = strstr(filepath, "file://")))
12707 result = util_exist_file_path(path + 7);
12709 result = util_exist_file_path(filepath);
12711 if (result != MM_ERROR_NONE) {
12712 LOGE("invalid subtitle path 0x%X", result);
12713 return result; /* file not found or permission denied */
12717 if (!player->pipeline) {
12719 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12720 if (mmf_attrs_commit(player->attrs)) {
12721 LOGE("failed to commit"); /* subtitle path will not be created */
12722 return MM_ERROR_PLAYER_INTERNAL;
12725 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12726 /* check filepath */
12727 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12729 if (!__mmplayer_check_subtitle(player)) {
12730 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12731 if (mmf_attrs_commit(player->attrs)) {
12732 LOGE("failed to commit");
12733 return MM_ERROR_PLAYER_INTERNAL;
12736 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12737 LOGE("fail to create text pipeline");
12738 return MM_ERROR_PLAYER_INTERNAL;
12741 result = _mmplayer_sync_subtitle_pipeline(player);
12743 result = __mmplayer_change_external_subtitle_language(player, filepath);
12746 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12747 player->is_external_subtitle_added_now = TRUE;
12749 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12750 if (!player->subtitle_language_list) {
12751 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12752 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12753 LOGW("subtitle language list is not updated yet");
12755 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12763 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12765 int result = MM_ERROR_NONE;
12766 gchar* change_pad_name = NULL;
12767 GstPad* sinkpad = NULL;
12768 MMPlayerGstElement* mainbin = NULL;
12769 enum MainElementID elemId = MMPLAYER_M_NUM;
12770 GstCaps* caps = NULL;
12771 gint total_track_num = 0;
12775 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12776 MM_ERROR_PLAYER_NOT_INITIALIZED);
12778 LOGD("Change Track(%d) to %d\n", type, index);
12780 mainbin = player->pipeline->mainbin;
12782 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12783 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12784 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12785 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12787 /* Changing Video Track is not supported. */
12788 LOGE("Track Type Error\n");
12792 if (mainbin[elemId].gst == NULL) {
12793 result = MM_ERROR_PLAYER_NO_OP;
12794 LOGD("Req track doesn't exist\n");
12798 total_track_num = player->selector[type].total_track_num;
12799 if (total_track_num <= 0) {
12800 result = MM_ERROR_PLAYER_NO_OP;
12801 LOGD("Language list is not available \n");
12805 if ((index < 0) || (index >= total_track_num)) {
12806 result = MM_ERROR_INVALID_ARGUMENT;
12807 LOGD("Not a proper index : %d \n", index);
12811 /*To get the new pad from the selector*/
12812 change_pad_name = g_strdup_printf("sink_%u", index);
12813 if (change_pad_name == NULL) {
12814 result = MM_ERROR_PLAYER_INTERNAL;
12815 LOGD("Pad does not exists\n");
12819 LOGD("new active pad name: %s\n", change_pad_name);
12821 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12822 if (sinkpad == NULL) {
12823 LOGD("sinkpad is NULL");
12824 result = MM_ERROR_PLAYER_INTERNAL;
12828 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12829 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12831 caps = gst_pad_get_current_caps(sinkpad);
12832 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12835 gst_object_unref(sinkpad);
12837 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12838 __mmplayer_set_audio_attrs(player, caps);
12842 MMPLAYER_FREEIF(change_pad_name);
12846 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12848 int result = MM_ERROR_NONE;
12849 mm_player_t* player = NULL;
12850 MMPlayerGstElement* mainbin = NULL;
12852 gint current_active_index = 0;
12854 GstState current_state = GST_STATE_VOID_PENDING;
12855 GstEvent* event = NULL;
12860 player = (mm_player_t*)hplayer;
12861 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12863 if (!player->pipeline) {
12864 LOGE("Track %d pre setting -> %d\n", type, index);
12866 player->selector[type].active_pad_index = index;
12870 mainbin = player->pipeline->mainbin;
12872 current_active_index = player->selector[type].active_pad_index;
12874 /*If index is same as running index no need to change the pad*/
12875 if (current_active_index == index)
12878 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12879 result = MM_ERROR_PLAYER_INVALID_STATE;
12883 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12884 if (current_state < GST_STATE_PAUSED) {
12885 result = MM_ERROR_PLAYER_INVALID_STATE;
12886 LOGW("Pipeline not in porper state\n");
12890 result = __mmplayer_change_selector_pad(player, type, index);
12891 if (result != MM_ERROR_NONE) {
12892 LOGE("change selector pad error\n");
12896 player->selector[type].active_pad_index = index;
12898 if (current_state == GST_STATE_PLAYING) {
12899 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);
12901 __gst_send_event_to_sink(player, event);
12903 result = MM_ERROR_PLAYER_INTERNAL;
12912 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12914 mm_player_t* player = (mm_player_t*) hplayer;
12918 /* check player handle */
12919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12921 *silent = player->set_mode.subtitle_off;
12923 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12927 return MM_ERROR_NONE;
12931 __is_ms_buff_src(mm_player_t* player)
12933 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12935 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12939 __has_suffix(mm_player_t* player, const gchar* suffix)
12941 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12942 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12944 gboolean ret = FALSE;
12945 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12946 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12948 if (g_str_has_suffix(player->profile.uri, suffix))
12951 MMPLAYER_FREEIF(t_url);
12952 MMPLAYER_FREEIF(t_suffix);
12958 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12960 mm_player_t* player = (mm_player_t*) hplayer;
12962 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12964 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12965 MMPLAYER_PRINT_STATE(player);
12966 LOGE("wrong-state : can't set the download mode to parse");
12967 return MM_ERROR_PLAYER_INVALID_STATE;
12970 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12971 player->video_hub_download_mode = mode;
12973 return MM_ERROR_NONE;
12977 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12979 mm_player_t* player = (mm_player_t*) hplayer;
12981 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12983 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12984 player->sync_handler = enable;
12986 return MM_ERROR_NONE;
12990 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12992 long long clock_delta,
12993 long long video_time,
12994 long long media_clock,
12995 long long audio_time)
12997 mm_player_t* player = (mm_player_t*) hplayer;
12998 MMPlayerGstElement* mainbin = NULL;
12999 GstClockTime start_time_audio = 0, start_time_video = 0;
13000 GstClockTimeDiff base_time = 0, new_base_time = 0;
13001 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13002 gint64 api_delta = 0;
13003 gint64 position = 0, position_delta = 0;
13004 gint64 adj_base_time = 0;
13005 GstClock *curr_clock = NULL;
13006 GstClockTime curr_time = 0;
13007 gboolean query_ret = TRUE;
13008 int result = MM_ERROR_NONE;
13012 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13013 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13014 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13016 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
13018 if ((video_time < 0) || (player->doing_seek)) {
13019 LOGD("skip setting master clock. %lld", video_time);
13023 mainbin = player->pipeline->mainbin;
13025 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13026 curr_time = gst_clock_get_time(curr_clock);
13028 current_state = MMPLAYER_CURRENT_STATE(player);
13030 if (current_state == MM_PLAYER_STATE_PLAYING)
13031 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13033 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
13035 position = player->last_position;
13036 LOGD("query fail. %lld", position);
13039 clock *= GST_USECOND;
13040 clock_delta *= GST_USECOND;
13042 api_delta = clock - curr_time;
13043 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
13044 player->video_share_api_delta = api_delta;
13046 clock_delta += (api_delta - player->video_share_api_delta);
13048 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13049 player->video_share_clock_delta = (gint64)clock_delta;
13051 position_delta = (position/GST_USECOND) - video_time;
13052 position_delta *= GST_USECOND;
13054 adj_base_time = position_delta;
13055 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
13058 gint64 new_play_time = 0;
13059 gint64 network_delay = 0;
13061 video_time *= GST_USECOND;
13063 network_delay = clock_delta - player->video_share_clock_delta;
13064 new_play_time = video_time + network_delay;
13066 adj_base_time = position - new_play_time;
13068 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13069 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13072 /* Adjust Current Stream Time with base_time of sink
13073 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13074 * 2. Set new base time
13075 * if adj_base_time is positive value, the stream time will be decreased.
13076 * 3. If seek event is occurred, the start time will be reset. */
13077 if ((player->pipeline->audiobin) &&
13078 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13079 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13081 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13082 LOGD("audio sink : gst_element_set_start_time -> NONE");
13083 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13086 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13089 if ((player->pipeline->videobin) &&
13090 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13091 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13093 if (start_time_video != GST_CLOCK_TIME_NONE) {
13094 LOGD("video sink : gst_element_set_start_time -> NONE");
13095 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13098 // if videobin exist, get base_time from videobin.
13099 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13102 new_base_time = base_time + adj_base_time;
13104 if ((player->pipeline->audiobin) &&
13105 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13106 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13108 if ((player->pipeline->videobin) &&
13109 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13110 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13119 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13120 long long *video_time,
13121 long long *media_clock,
13122 long long *audio_time)
13124 mm_player_t* player = (mm_player_t*) hplayer;
13125 MMPlayerGstElement* mainbin = NULL;
13126 GstClock *curr_clock = NULL;
13127 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13128 gint64 position = 0;
13129 gboolean query_ret = TRUE;
13133 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13134 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13135 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13137 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13138 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13139 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13141 mainbin = player->pipeline->mainbin;
13143 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13145 current_state = MMPLAYER_CURRENT_STATE(player);
13147 if (current_state != MM_PLAYER_STATE_PAUSED)
13148 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13150 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13152 position = player->last_position;
13154 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13156 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13159 gst_object_unref(curr_clock);
13163 return MM_ERROR_NONE;
13167 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13169 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13170 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13172 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13173 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13177 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13178 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13179 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13180 mm_player_dump_t *dump_s;
13181 dump_s = g_malloc(sizeof(mm_player_dump_t));
13183 if (dump_s == NULL) {
13184 LOGE("malloc fail");
13188 dump_s->dump_element_file = NULL;
13189 dump_s->dump_pad = NULL;
13190 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13192 if (dump_s->dump_pad) {
13193 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13194 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]);
13195 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13196 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);
13197 /* add list for removed buffer probe and close FILE */
13198 player->dump_list = g_list_append(player->dump_list, dump_s);
13199 LOGD("%s sink pad added buffer probe for dump", factory_name);
13204 LOGE("failed to get %s sink pad added", factory_name);
13213 static GstPadProbeReturn
13214 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13216 FILE *dump_data = (FILE *) u_data;
13217 // int written = 0;
13218 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13219 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13221 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13223 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13225 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13227 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13229 return GST_PAD_PROBE_OK;
13233 __mmplayer_release_dump_list(GList *dump_list)
13236 GList *d_list = dump_list;
13237 for (; d_list; d_list = g_list_next(d_list)) {
13238 mm_player_dump_t *dump_s = d_list->data;
13239 if (dump_s->dump_pad) {
13240 if (dump_s->probe_handle_id)
13241 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13243 if (dump_s->dump_element_file) {
13244 fclose(dump_s->dump_element_file);
13245 dump_s->dump_element_file = NULL;
13247 MMPLAYER_FREEIF(dump_s);
13249 g_list_free(dump_list);
13255 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13257 mm_player_t* player = (mm_player_t*) hplayer;
13261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13262 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13264 *exist = player->has_closed_caption;
13268 return MM_ERROR_NONE;
13271 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13275 // LOGD("unref internal gst buffer %p", buffer);
13276 gst_buffer_unref((GstBuffer *)buffer);
13283 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13285 mm_player_t *player = (mm_player_t*)user_data;
13286 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13287 guint64 current_level_bytes = 0;
13289 MMPLAYER_RETURN_IF_FAIL(player);
13291 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13293 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13294 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13296 if (player->media_stream_buffer_status_cb[type])
13297 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13298 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13303 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13305 mm_player_t *player = (mm_player_t*)user_data;
13306 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13307 guint64 current_level_bytes = 0;
13309 MMPLAYER_RETURN_IF_FAIL(player);
13311 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13313 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13315 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13316 if (player->media_stream_buffer_status_cb[type])
13317 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13318 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13322 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13324 mm_player_t *player = (mm_player_t*)user_data;
13325 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13326 guint64 current_level_bytes = 0;
13328 MMPLAYER_RETURN_IF_FAIL(player);
13330 LOGI("app-src: feed subtitle\n");
13332 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13334 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13335 if (player->media_stream_buffer_status_cb[type])
13336 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13338 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13342 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13344 mm_player_t *player = (mm_player_t*)user_data;
13345 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13346 guint64 current_level_bytes = 0;
13348 MMPLAYER_RETURN_IF_FAIL(player);
13350 LOGI("app-src: audio buffer is full.\n");
13352 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13354 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13356 if (player->media_stream_buffer_status_cb[type])
13357 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13359 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13363 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13365 mm_player_t *player = (mm_player_t*)user_data;
13366 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13367 guint64 current_level_bytes = 0;
13369 MMPLAYER_RETURN_IF_FAIL(player);
13371 LOGI("app-src: video buffer is full.\n");
13373 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13375 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13376 if (player->media_stream_buffer_status_cb[type])
13377 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13379 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13383 __gst_seek_audio_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_AUDIO;
13388 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13390 LOGD("app-src: seek audio data %llu\n", position);
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 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13403 mm_player_t *player = (mm_player_t*)user_data;
13404 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13406 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13408 LOGD("app-src: seek video data %llu\n", position);
13409 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13410 if (player->media_stream_seek_data_cb[type])
13411 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13412 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13418 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13420 mm_player_t *player = (mm_player_t*)user_data;
13421 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13423 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13425 LOGD("app-src: seek subtitle data\n");
13426 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13428 if (player->media_stream_seek_data_cb[type])
13429 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13430 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13436 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13438 mm_player_t* player = (mm_player_t*) hplayer;
13442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13444 player->pcm_samplerate = samplerate;
13445 player->pcm_channel = channel;
13448 return MM_ERROR_NONE;
13451 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13453 mm_player_t* player = (mm_player_t*) hplayer;
13457 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13458 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13460 if (MMPLAYER_IS_STREAMING(player))
13461 *timeout = player->ini.live_state_change_timeout;
13463 *timeout = player->ini.localplayback_state_change_timeout;
13465 LOGD("timeout = %d\n", *timeout);
13468 return MM_ERROR_NONE;
13471 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13473 mm_player_t* player = (mm_player_t*) hplayer;
13477 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13478 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13480 *num = player->video_num_buffers;
13481 *extra_num = player->video_extra_num_buffers;
13483 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13486 return MM_ERROR_NONE;
13490 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13494 MMPLAYER_RETURN_IF_FAIL(player);
13496 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13498 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13499 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13500 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13501 player->storage_info[i].id = -1;
13502 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13504 if (path_type != MMPLAYER_PATH_MAX)
13512 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13514 int ret = MM_ERROR_NONE;
13515 mm_player_t* player = (mm_player_t*)hplayer;
13516 MMMessageParamType msg_param = {0, };
13519 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13521 LOGW("state changed storage %d:%d", id, state);
13523 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13524 return MM_ERROR_NONE;
13526 /* FIXME: text path should be handled seperately. */
13527 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13528 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13529 LOGW("external storage is removed");
13531 if (player->msg_posted == FALSE) {
13532 memset(&msg_param, 0, sizeof(MMMessageParamType));
13533 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13534 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13535 player->msg_posted = TRUE;
13538 /* unrealize the player */
13539 ret = _mmplayer_unrealize(hplayer);
13540 if (ret != MM_ERROR_NONE)
13541 LOGE("failed to unrealize");
13548 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13550 int ret = MM_ERROR_NONE;
13551 mm_player_t* player = (mm_player_t*) hplayer;
13552 int idx = 0, total = 0;
13553 gchar *result = NULL, *tmp = NULL;
13556 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13557 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13559 total = *num = g_list_length(player->adaptive_info.var_list);
13561 LOGW("There is no stream variant info.");
13565 result = g_strdup("");
13566 for (idx = 0 ; idx < total ; idx++) {
13567 VariantData *v_data = NULL;
13568 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13571 gchar data[64] = {0};
13572 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13574 tmp = g_strconcat(result, data, NULL);
13578 LOGW("There is no variant data in %d", idx);
13583 *var_info = (char *)result;
13585 LOGD("variant info %d:%s", *num, *var_info);
13590 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13592 int ret = MM_ERROR_NONE;
13593 mm_player_t* player = (mm_player_t*) hplayer;
13596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13598 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13600 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13601 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13602 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13604 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13605 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13606 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13607 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13609 /* FIXME: seek to current position for applying new variant limitation */
13617 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13619 int ret = MM_ERROR_NONE;
13620 mm_player_t* player = (mm_player_t*) hplayer;
13623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13624 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13626 *bandwidth = player->adaptive_info.limit.bandwidth;
13627 *width = player->adaptive_info.limit.width;
13628 *height = player->adaptive_info.limit.height;
13630 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13636 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13638 int ret = MM_ERROR_NONE;
13639 mm_player_t* player = (mm_player_t*) hplayer;
13642 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13644 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13645 LOGW("buffer_ms will not be applied.");
13648 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13650 if (player->streamer == NULL) {
13651 player->streamer = __mm_player_streaming_create();
13652 __mm_player_streaming_initialize(player->streamer);
13655 if (buffer_ms >= 0)
13656 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13658 if (rebuffer_ms >= 0)
13659 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13666 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13668 int ret = MM_ERROR_NONE;
13669 mm_player_t* player = (mm_player_t*) hplayer;
13672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13673 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13675 if (player->streamer == NULL) {
13676 player->streamer = __mm_player_streaming_create();
13677 __mm_player_streaming_initialize(player->streamer);
13680 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13681 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13683 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13689 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13691 #define IDX_FIRST_SW_CODEC 0
13692 mm_player_t* player = (mm_player_t*) hplayer;
13693 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13694 MMHandleType attrs = 0;
13697 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13699 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13700 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13701 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13703 switch (stream_type) {
13704 case MM_PLAYER_STREAM_TYPE_AUDIO:
13705 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13706 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13707 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13708 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13709 LOGE("There is no a codec for codec_type %d", codec_type);
13710 return MM_ERROR_PLAYER_NO_OP;
13713 case MM_PLAYER_STREAM_TYPE_VIDEO:
13714 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13715 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13716 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13717 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13718 LOGE("There is no v codec for codec_type %d", codec_type);
13719 return MM_ERROR_PLAYER_NO_OP;
13724 LOGE("Invalid stream type %d", stream_type);
13725 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13729 LOGD("update %s codec_type to %d", attr_name, codec_type);
13731 attrs = MMPLAYER_GET_ATTRS(player);
13732 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13734 if (mmf_attrs_commit(player->attrs)) {
13735 LOGE("failed to commit codec_type attributes");
13736 return MM_ERROR_PLAYER_INTERNAL;
13740 return MM_ERROR_NONE;
13744 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13746 mm_player_t* player = (mm_player_t*) hplayer;
13747 GstElement* rg_vol_element = NULL;
13751 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13753 player->sound.rg_enable = enabled;
13755 /* just hold rgvolume enable value if pipeline is not ready */
13756 if (!player->pipeline || !player->pipeline->audiobin) {
13757 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13758 return MM_ERROR_NONE;
13761 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13763 if (!rg_vol_element) {
13764 LOGD("rgvolume element is not created");
13765 return MM_ERROR_PLAYER_INTERNAL;
13769 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13771 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13775 return MM_ERROR_NONE;
13779 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13781 mm_player_t* player = (mm_player_t*) hplayer;
13782 GstElement* rg_vol_element = NULL;
13783 gboolean enable = FALSE;
13787 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13788 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13790 /* just hold enable_rg value if pipeline is not ready */
13791 if (!player->pipeline || !player->pipeline->audiobin) {
13792 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13793 *enabled = player->sound.rg_enable;
13794 return MM_ERROR_NONE;
13797 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13799 if (!rg_vol_element) {
13800 LOGD("rgvolume element is not created");
13801 return MM_ERROR_PLAYER_INTERNAL;
13804 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13809 return MM_ERROR_NONE;