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 */
101 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
102 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
104 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
105 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
107 /*---------------------------------------------------------------------------
108 | LOCAL CONSTANT DEFINITIONS: |
109 ---------------------------------------------------------------------------*/
111 /*---------------------------------------------------------------------------
112 | LOCAL DATA TYPE DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | GLOBAL VARIABLE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
119 /*---------------------------------------------------------------------------
120 | LOCAL VARIABLE DEFINITIONS: |
121 ---------------------------------------------------------------------------*/
122 static sound_stream_info_h stream_info;
124 /*---------------------------------------------------------------------------
125 | LOCAL FUNCTION PROTOTYPES: |
126 ---------------------------------------------------------------------------*/
127 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
128 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
129 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
130 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
131 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
132 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
133 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
135 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
136 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
137 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
138 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
139 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
140 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
141 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
142 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
143 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
144 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
145 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
146 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
147 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
148 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
149 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
150 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
151 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
153 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
154 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
155 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
156 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mm_player_t* player);
158 static void __mmplayer_release_misc_post(mm_player_t* player);
159 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
160 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
161 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
162 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
163 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
164 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
165 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
167 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
169 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
171 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
172 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
173 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
174 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
175 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
176 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
177 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
178 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
179 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
180 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
181 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
182 static gpointer __mmplayer_next_play_thread(gpointer data);
183 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
185 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
186 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
187 static void __mmplayer_release_dump_list(GList *dump_list);
189 static int __gst_realize(mm_player_t* player);
190 static int __gst_unrealize(mm_player_t* player);
191 static int __gst_start(mm_player_t* player);
192 static int __gst_stop(mm_player_t* player);
193 static int __gst_pause(mm_player_t* player, gboolean async);
194 static int __gst_resume(mm_player_t* player, gboolean async);
195 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
196 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
197 gint64 cur, GstSeekType stop_type, gint64 stop);
198 static int __gst_pending_seek(mm_player_t* player);
200 static int __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called);
201 static int __gst_get_position(mm_player_t* player, int format, unsigned long *position);
202 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
203 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
204 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
206 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
208 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
209 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
212 static gboolean __is_ms_buff_src(mm_player_t* player);
213 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
215 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
216 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
217 static int __mmplayer_start_streaming_ext(mm_player_t *player);
218 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
219 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
221 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
222 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
223 static void __mmplayer_check_pipeline(mm_player_t* player);
224 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
225 static void __mmplayer_deactivate_old_path(mm_player_t *player);
227 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
228 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
230 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
231 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
232 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
233 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
234 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
235 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
236 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
237 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
238 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
239 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
240 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
241 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
242 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
243 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
244 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
245 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
247 /*===========================================================================================
249 | FUNCTION DEFINITIONS |
251 ========================================================================================== */
255 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
259 count = gst_tag_list_get_tag_size(list, tag);
261 LOGD("count = %d", count);
263 for (i = 0; i < count; i++) {
266 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
267 if (!gst_tag_list_get_string_index(list, tag, i, &str))
268 g_assert_not_reached();
270 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
273 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
275 g_print(" : %s\n", str);
282 /* This function should be called after the pipeline goes PAUSED or higher
285 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
287 static gboolean has_duration = FALSE;
288 static gboolean has_video_attrs = FALSE;
289 static gboolean has_audio_attrs = FALSE;
290 static gboolean has_bitrate = FALSE;
291 gboolean missing_only = FALSE;
292 gboolean all = FALSE;
294 GstStructure* p = NULL;
295 MMHandleType attrs = 0;
301 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
303 /* check player state here */
304 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
305 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
306 /* give warning now only */
307 LOGW("be careful. content attributes may not available in this state ");
310 /* get content attribute first */
311 attrs = MMPLAYER_GET_ATTRS(player);
313 LOGE("cannot get content attribute");
317 /* get update flag */
319 if (flag & ATTR_MISSING_ONLY) {
321 LOGD("updating missed attr only");
324 if (flag & ATTR_ALL) {
326 has_duration = FALSE;
327 has_video_attrs = FALSE;
328 has_audio_attrs = FALSE;
331 LOGD("updating all attrs");
334 if (missing_only && all) {
335 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
336 missing_only = FALSE;
339 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
340 LOGD("try to update duration");
341 has_duration = FALSE;
343 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
344 player->duration = dur_nsec;
345 LOGW("duration : %lld msec", GST_TIME_AS_MSECONDS(dur_nsec));
348 if (player->duration < 0) {
349 LOGW("duration : %lld is Non-Initialized !!! \n", player->duration);
350 player->duration = 0;
353 /* update streaming service type */
354 player->streaming_type = __mmplayer_get_stream_service_type(player);
356 /* check duration is OK */
357 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
358 /* FIXIT : find another way to get duration here. */
359 LOGE("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
362 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(dur_nsec));
367 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
368 /* update audio params
369 NOTE : We need original audio params and it can be only obtained from src pad of audio
370 decoder. Below code only valid when we are not using 'resampler' just before
373 LOGD("try to update audio attrs");
374 has_audio_attrs = FALSE;
376 if (player->pipeline->audiobin &&
377 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
378 GstCaps *caps_a = NULL;
380 gint samplerate = 0, channels = 0;
382 pad = gst_element_get_static_pad(
383 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
386 caps_a = gst_pad_get_current_caps(pad);
389 p = gst_caps_get_structure(caps_a, 0);
391 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
393 gst_structure_get_int(p, "rate", &samplerate);
394 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
396 gst_structure_get_int(p, "channels", &channels);
397 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
399 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
401 gst_caps_unref(caps_a);
404 has_audio_attrs = TRUE;
406 LOGW("not ready to get audio caps");
408 gst_object_unref(pad);
410 LOGW("failed to get pad from audiosink");
414 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
415 LOGD("try to update video attrs");
416 has_video_attrs = FALSE;
418 if (player->pipeline->videobin &&
419 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
420 GstCaps *caps_v = NULL;
425 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
427 caps_v = gst_pad_get_current_caps(pad);
429 /* Use v_stream_caps, if fail to get video_sink sink pad*/
430 if (!caps_v && player->v_stream_caps) {
431 caps_v = player->v_stream_caps;
432 gst_caps_ref(caps_v);
436 p = gst_caps_get_structure(caps_v, 0);
437 gst_structure_get_int(p, "width", &width);
438 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
440 gst_structure_get_int(p, "height", &height);
441 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
443 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
445 SECURE_LOGD("width : %d height : %d", width, height);
447 gst_caps_unref(caps_v);
451 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
452 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
455 has_video_attrs = TRUE;
457 LOGD("no negitiated caps from videosink");
458 gst_object_unref(pad);
461 LOGD("no videosink sink pad");
466 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
469 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
470 if (player->duration) {
471 guint64 data_size = 0;
473 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
474 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
476 if (stat(path, &sb) == 0)
477 data_size = (guint64)sb.st_size;
478 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
479 data_size = player->http_content_size;
481 LOGD("try to update bitrate : data_size = %lld", data_size);
485 guint64 msec_dur = 0;
487 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
489 bitrate = data_size * 8 * 1000 / msec_dur;
490 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
491 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
495 LOGD("player duration is less than 0");
499 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
500 if (player->total_bitrate) {
501 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
509 if (mmf_attrs_commit(attrs)) {
510 LOGE("failed to update attributes\n");
519 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
521 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
525 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
527 player->pipeline->mainbin &&
528 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
529 STREAMING_SERVICE_NONE);
531 /* streaming service type if streaming */
532 if (!MMPLAYER_IS_STREAMING(player))
533 return STREAMING_SERVICE_NONE;
535 if (MMPLAYER_IS_HTTP_STREAMING(player))
536 streaming_type = (player->duration == 0) ?
537 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
539 switch (streaming_type) {
540 case STREAMING_SERVICE_LIVE:
541 LOGD("it's live streaming");
543 case STREAMING_SERVICE_VOD:
544 LOGD("it's vod streaming");
547 LOGE("should not get here");
553 return streaming_type;
557 /* this function sets the player state and also report
558 * it to applicaton by calling callback function
561 __mmplayer_set_state(mm_player_t* player, int state)
563 MMMessageParamType msg = {0, };
564 gboolean post_bos = FALSE;
566 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
568 if (MMPLAYER_CURRENT_STATE(player) == state) {
569 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
570 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
571 return MM_ERROR_NONE;
574 /* update player states */
575 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
576 MMPLAYER_CURRENT_STATE(player) = state;
578 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
579 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
582 MMPLAYER_PRINT_STATE(player);
584 switch (MMPLAYER_CURRENT_STATE(player)) {
585 case MM_PLAYER_STATE_NULL:
586 case MM_PLAYER_STATE_READY:
589 case MM_PLAYER_STATE_PAUSED:
591 if (!player->sent_bos) {
592 /* rtsp case, get content attrs by GstMessage */
593 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
594 /* it's first time to update all content attrs. */
595 _mmplayer_update_content_attrs(player, ATTR_ALL);
599 /* add audio callback probe if condition is satisfied */
600 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
601 __mmplayer_configure_audio_callback(player);
603 /* FIXIT : handle return value */
607 case MM_PLAYER_STATE_PLAYING:
609 /* try to get content metadata */
610 if (!player->sent_bos) {
611 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
612 * c-api since c-api doesn't use _start() anymore. It may not work propery with
613 * legacy mmfw-player api */
614 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
617 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
618 if (!player->sent_bos)
619 __mmplayer_handle_missed_plugin(player);
622 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
623 /* initialize because auto resume is done well. */
624 player->resumed_by_rewind = FALSE;
625 player->playback_rate = 1.0;
628 if (!player->sent_bos) {
629 /* check audio codec field is set or not
630 * we can get it from typefinder or codec's caps.
632 gchar *audio_codec = NULL;
633 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
635 /* The codec format can't be sent for audio only case like amr, mid etc.
636 * Because, parser don't make related TAG.
637 * So, if it's not set yet, fill it with found data.
640 if (g_strrstr(player->type, "audio/midi"))
641 audio_codec = g_strdup("MIDI");
642 else if (g_strrstr(player->type, "audio/x-amr"))
643 audio_codec = g_strdup("AMR");
644 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
645 audio_codec = g_strdup("AAC");
647 audio_codec = g_strdup("unknown");
648 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
650 MMPLAYER_FREEIF(audio_codec);
651 if (mmf_attrs_commit(player->attrs))
652 LOGE("failed to update attributes\n");
654 LOGD("set audio codec type with caps\n");
662 case MM_PLAYER_STATE_NONE:
664 LOGW("invalid target state, there is nothing to do.\n");
669 /* post message to application */
670 if (MMPLAYER_TARGET_STATE(player) == state) {
671 /* fill the message with state of player */
672 msg.union_type = MM_MSG_UNION_STATE;
673 msg.state.previous = MMPLAYER_PREV_STATE(player);
674 msg.state.current = MMPLAYER_CURRENT_STATE(player);
676 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
678 /* state changed by resource callback */
679 if (player->interrupted_by_resource) {
680 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
681 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
682 } else { /* state changed by usecase */
683 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
686 LOGD("intermediate state, do nothing.\n");
687 MMPLAYER_PRINT_STATE(player);
688 return MM_ERROR_NONE;
692 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
693 player->sent_bos = TRUE;
696 return MM_ERROR_NONE;
699 static gpointer __mmplayer_next_play_thread(gpointer data)
701 mm_player_t* player = (mm_player_t*) data;
702 MMPlayerGstElement *mainbin = NULL;
704 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
706 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
707 while (!player->next_play_thread_exit) {
708 LOGD("next play thread started. waiting for signal.\n");
709 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
711 LOGD("reconfigure pipeline for gapless play.\n");
713 if (player->next_play_thread_exit) {
714 if (player->gapless.reconfigure) {
715 player->gapless.reconfigure = false;
716 MMPLAYER_PLAYBACK_UNLOCK(player);
718 LOGD("exiting gapless play thread\n");
722 mainbin = player->pipeline->mainbin;
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
725 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
730 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
732 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
738 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
740 MMHandleType attrs = 0;
741 guint64 data_size = 0;
743 unsigned long pos_msec = 0;
746 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
748 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_msec); // update last_position
750 attrs = MMPLAYER_GET_ATTRS(player);
752 LOGE("fail to get attributes.\n");
756 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
757 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
759 if (stat(path, &sb) == 0)
760 data_size = (guint64)sb.st_size;
761 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
762 data_size = player->http_content_size;
764 __mm_player_streaming_buffering(player->streamer,
767 player->last_position,
770 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
776 __mmplayer_handle_buffering_message(mm_player_t* player)
778 int ret = MM_ERROR_NONE;
779 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
780 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
781 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
782 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
784 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
785 LOGW("do nothing for buffering msg\n");
786 ret = MM_ERROR_PLAYER_INVALID_STATE;
790 prev_state = MMPLAYER_PREV_STATE(player);
791 current_state = MMPLAYER_CURRENT_STATE(player);
792 target_state = MMPLAYER_TARGET_STATE(player);
793 pending_state = MMPLAYER_PENDING_STATE(player);
795 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
796 MMPLAYER_STATE_GET_NAME(prev_state),
797 MMPLAYER_STATE_GET_NAME(current_state),
798 MMPLAYER_STATE_GET_NAME(pending_state),
799 MMPLAYER_STATE_GET_NAME(target_state),
800 player->streamer->is_buffering);
802 if (!player->streamer->is_buffering) {
803 /* NOTE : if buffering has done, player has to go to target state. */
804 switch (target_state) {
805 case MM_PLAYER_STATE_PAUSED:
807 switch (pending_state) {
808 case MM_PLAYER_STATE_PLAYING:
809 __gst_pause(player, TRUE);
812 case MM_PLAYER_STATE_PAUSED:
813 LOGD("player is already going to paused state, there is nothing to do.\n");
816 case MM_PLAYER_STATE_NONE:
817 case MM_PLAYER_STATE_NULL:
818 case MM_PLAYER_STATE_READY:
820 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
826 case MM_PLAYER_STATE_PLAYING:
828 switch (pending_state) {
829 case MM_PLAYER_STATE_NONE:
831 if (current_state != MM_PLAYER_STATE_PLAYING)
832 __gst_resume(player, TRUE);
836 case MM_PLAYER_STATE_PAUSED:
837 /* NOTE: It should be worked as asynchronously.
838 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
840 if (current_state == MM_PLAYER_STATE_PLAYING) {
841 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
842 * The current state should be changed to paused purposely to prevent state conflict.
844 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
846 __gst_resume(player, TRUE);
849 case MM_PLAYER_STATE_PLAYING:
850 LOGD("player is already going to playing state, there is nothing to do.\n");
853 case MM_PLAYER_STATE_NULL:
854 case MM_PLAYER_STATE_READY:
856 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
862 case MM_PLAYER_STATE_NULL:
863 case MM_PLAYER_STATE_READY:
864 case MM_PLAYER_STATE_NONE:
866 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
870 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
871 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
873 switch (pending_state) {
874 case MM_PLAYER_STATE_NONE:
876 if (current_state != MM_PLAYER_STATE_PAUSED) {
877 /* rtsp streaming pause makes rtsp server stop sending data. */
878 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
879 LOGD("set pause state during buffering\n");
880 __gst_pause(player, TRUE);
886 case MM_PLAYER_STATE_PLAYING:
887 /* rtsp streaming pause makes rtsp server stop sending data. */
888 if (!MMPLAYER_IS_RTSP_STREAMING(player))
889 __gst_pause(player, TRUE);
892 case MM_PLAYER_STATE_PAUSED:
895 case MM_PLAYER_STATE_NULL:
896 case MM_PLAYER_STATE_READY:
898 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
908 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
910 MMPlayerGstElement *textbin;
913 MMPLAYER_RETURN_IF_FAIL(player &&
915 player->pipeline->textbin);
917 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
919 textbin = player->pipeline->textbin;
922 LOGD("Drop subtitle text after getting EOS\n");
924 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
925 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
927 player->is_subtitle_force_drop = TRUE;
929 if (player->is_subtitle_force_drop == TRUE) {
930 LOGD("Enable subtitle data path without drop\n");
932 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
933 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
935 LOGD("non-connected with external display");
937 player->is_subtitle_force_drop = FALSE;
943 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
945 VariantData *var_info = NULL;
946 g_return_val_if_fail(self != NULL, NULL);
948 var_info = g_new0(VariantData, 1);
949 if (!var_info) return NULL;
950 var_info->bandwidth = self->bandwidth;
951 var_info->width = self->width;
952 var_info->height = self->height;
956 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
958 mm_player_t* player = (mm_player_t*)hplayer;
961 MMPLAYER_RETURN_IF_FAIL(player);
963 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
965 /* destroy the gst bus msg thread */
966 if (player->bus_msg_thread) {
967 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
968 player->bus_msg_thread_exit = TRUE;
969 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
970 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
972 LOGD("gst bus msg thread exit.");
973 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
974 player->bus_msg_thread = NULL;
976 g_mutex_clear(&player->bus_msg_thread_mutex);
977 g_cond_clear(&player->bus_msg_thread_cond);
983 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
985 mm_player_t *player = (mm_player_t*)(data);
986 GstMessage *msg = NULL;
990 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
992 player->pipeline->mainbin &&
993 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
996 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
998 LOGE("cannot get BUS from the pipeline");
1002 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1004 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1005 while (!player->bus_msg_thread_exit) {
1006 msg = gst_bus_pop(bus);
1008 int timeout = (player->bus_msg_timeout > 0) ? (player->bus_msg_timeout) : (PLAYER_BUS_MSG_DEFAULT_TIMEOUT);
1009 MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + timeout * G_TIME_SPAN_MILLISECOND));
1013 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1014 /* handle the gst msg */
1015 __mmplayer_gst_callback(msg, player);
1016 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1017 gst_message_unref(msg);
1020 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1021 gst_object_unref(GST_OBJECT(bus));
1028 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1030 mm_player_t* player = (mm_player_t*)(data);
1031 static gboolean async_done = FALSE;
1033 MMPLAYER_RETURN_IF_FAIL(player);
1034 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1036 switch (GST_MESSAGE_TYPE(msg)) {
1037 case GST_MESSAGE_UNKNOWN:
1038 LOGD("unknown message received\n");
1041 case GST_MESSAGE_EOS:
1043 MMHandleType attrs = 0;
1046 LOGD("GST_MESSAGE_EOS received\n");
1048 /* NOTE : EOS event is comming multiple time. watch out it */
1049 /* check state. we only process EOS when pipeline state goes to PLAYING */
1050 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1051 LOGD("EOS received on non-playing state. ignoring it\n");
1055 if (player->pipeline) {
1056 if (player->pipeline->textbin)
1057 __mmplayer_drop_subtitle(player, TRUE);
1059 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1062 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1064 LOGD("release audio callback\n");
1066 /* release audio callback */
1067 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1068 player->audio_cb_probe_id = 0;
1069 /* audio callback should be free because it can be called even though probe remove.*/
1070 player->audio_stream_cb = NULL;
1071 player->audio_stream_cb_user_param = NULL;
1075 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1076 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1078 /* rewind if repeat count is greater then zero */
1079 /* get play count */
1080 attrs = MMPLAYER_GET_ATTRS(player);
1083 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1085 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1087 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1088 if (player->playback_rate < 0.0) {
1089 player->resumed_by_rewind = TRUE;
1090 _mmplayer_set_mute((MMHandleType)player, 0);
1091 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1094 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1097 player->sent_bos = FALSE;
1099 /* not posting eos when repeating */
1104 if (player->pipeline)
1105 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1107 /* post eos message to application */
1108 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1110 /* reset last position */
1111 player->last_position = 0;
1115 case GST_MESSAGE_ERROR:
1117 GError *error = NULL;
1118 gchar* debug = NULL;
1120 /* generating debug info before returning error */
1121 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1123 /* get error code */
1124 gst_message_parse_error(msg, &error, &debug);
1126 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1127 /* Note : the streaming error from the streaming source is handled
1128 * using __mmplayer_handle_streaming_error.
1130 __mmplayer_handle_streaming_error(player, msg);
1132 /* dump state of all element */
1133 __mmplayer_dump_pipeline_state(player);
1135 /* traslate gst error code to msl error code. then post it
1136 * to application if needed
1138 __mmplayer_handle_gst_error(player, msg, error);
1141 LOGE("error debug : %s", debug);
1144 if (MMPLAYER_IS_HTTP_PD(player))
1145 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1147 MMPLAYER_FREEIF(debug);
1148 g_error_free(error);
1152 case GST_MESSAGE_WARNING:
1155 GError* error = NULL;
1157 gst_message_parse_warning(msg, &error, &debug);
1159 LOGD("warning : %s\n", error->message);
1160 LOGD("debug : %s\n", debug);
1162 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1164 MMPLAYER_FREEIF(debug);
1165 g_error_free(error);
1169 case GST_MESSAGE_TAG:
1171 LOGD("GST_MESSAGE_TAG\n");
1172 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1173 LOGW("failed to extract tags from gstmessage\n");
1177 case GST_MESSAGE_BUFFERING:
1179 MMMessageParamType msg_param = {0, };
1180 int bRet = MM_ERROR_NONE;
1182 if (!(player->pipeline && player->pipeline->mainbin)) {
1183 LOGE("player pipeline handle is null");
1187 if (!MMPLAYER_IS_STREAMING(player))
1190 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1191 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1192 /* skip the playback control by buffering msg while user request is handled. */
1195 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1197 gst_message_parse_buffering(msg, &per);
1198 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1200 msg_param.connection.buffering = per;
1201 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1205 MMPLAYER_CMD_LOCK(player);
1208 /* ignore the prev buffering message */
1209 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1210 && (player->streamer->is_buffering_done == TRUE)) {
1211 gint buffer_percent = 0;
1213 gst_message_parse_buffering(msg, &buffer_percent);
1215 if (buffer_percent == MAX_BUFFER_PERCENT) {
1216 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1217 player->streamer->is_buffering_done = FALSE;
1219 MMPLAYER_CMD_UNLOCK(player);
1223 __mmplayer_update_buffer_setting(player, msg);
1225 bRet = __mmplayer_handle_buffering_message(player);
1227 if (bRet == MM_ERROR_NONE) {
1228 msg_param.connection.buffering = player->streamer->buffering_percent;
1229 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1231 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1232 player->pending_resume &&
1233 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1235 player->is_external_subtitle_added_now = FALSE;
1236 player->pending_resume = FALSE;
1237 _mmplayer_resume((MMHandleType)player);
1240 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1241 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1243 if (player->doing_seek) {
1244 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1245 player->doing_seek = FALSE;
1246 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1247 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1252 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1253 if (!player->streamer) {
1254 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1255 MMPLAYER_CMD_UNLOCK(player);
1259 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1261 LOGD("player->last_position=%lld , player->streamer->buffering_percent=%d \n",
1262 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1264 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1265 msg_param.connection.buffering = player->streamer->buffering_percent;
1266 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1268 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1271 msg_param.connection.buffering = player->streamer->buffering_percent;
1272 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1275 MMPLAYER_CMD_UNLOCK(player);
1279 case GST_MESSAGE_STATE_CHANGED:
1281 MMPlayerGstElement *mainbin;
1282 const GValue *voldstate, *vnewstate, *vpending;
1283 GstState oldstate = GST_STATE_NULL;
1284 GstState newstate = GST_STATE_NULL;
1285 GstState pending = GST_STATE_NULL;
1287 if (!(player->pipeline && player->pipeline->mainbin)) {
1288 LOGE("player pipeline handle is null");
1292 mainbin = player->pipeline->mainbin;
1294 /* we only handle messages from pipeline */
1295 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1298 /* get state info from msg */
1299 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1300 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1301 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1303 if (!voldstate || !vnewstate) {
1304 LOGE("received msg has wrong format.");
1308 oldstate = (GstState)voldstate->data[0].v_int;
1309 newstate = (GstState)vnewstate->data[0].v_int;
1311 pending = (GstState)vpending->data[0].v_int;
1313 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1314 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1315 gst_element_state_get_name((GstState)oldstate),
1316 gst_element_state_get_name((GstState)newstate),
1317 gst_element_state_get_name((GstState)pending));
1319 if (newstate == GST_STATE_PLAYING) {
1320 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1322 int retVal = MM_ERROR_NONE;
1323 LOGD("trying to play from (%lu) pending position\n", player->pending_seek.pos);
1325 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1327 if (MM_ERROR_NONE != retVal)
1328 LOGE("failed to seek pending postion. just keep staying current position.\n");
1330 player->pending_seek.is_pending = FALSE;
1334 if (oldstate == newstate) {
1335 LOGD("pipeline reports state transition to old state");
1340 case GST_STATE_VOID_PENDING:
1343 case GST_STATE_NULL:
1346 case GST_STATE_READY:
1349 case GST_STATE_PAUSED:
1351 gboolean prepare_async = FALSE;
1352 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1354 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1355 __mmplayer_configure_audio_callback(player);
1357 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1358 // managed prepare async case
1359 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1360 LOGD("checking prepare mode for async transition - %d", prepare_async);
1363 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1364 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1366 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1367 __mm_player_streaming_set_content_bitrate(player->streamer,
1368 player->total_maximum_bitrate, player->total_bitrate);
1370 if (player->pending_seek.is_pending) {
1371 LOGW("trying to do pending seek");
1372 MMPLAYER_CMD_LOCK(player);
1373 __gst_pending_seek(player);
1374 MMPLAYER_CMD_UNLOCK(player);
1380 case GST_STATE_PLAYING:
1382 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1384 if (MMPLAYER_IS_STREAMING(player)) {
1385 // managed prepare async case when buffering is completed
1386 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1387 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1388 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1389 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1391 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1393 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1394 if (player->streamer->buffering_percent < 100) {
1396 MMMessageParamType msg_param = {0, };
1397 LOGW("Posting Buffering Completed Message to Application !!!");
1399 msg_param.connection.buffering = 100;
1400 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1405 if (player->gapless.stream_changed) {
1406 _mmplayer_update_content_attrs(player, ATTR_ALL);
1407 player->gapless.stream_changed = FALSE;
1410 if (player->doing_seek && async_done) {
1411 player->doing_seek = FALSE;
1413 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1424 case GST_MESSAGE_CLOCK_LOST:
1426 GstClock *clock = NULL;
1427 gboolean need_new_clock = FALSE;
1429 gst_message_parse_clock_lost(msg, &clock);
1430 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1432 if (!player->videodec_linked)
1433 need_new_clock = TRUE;
1434 else if (!player->ini.use_system_clock)
1435 need_new_clock = TRUE;
1437 if (need_new_clock) {
1438 LOGD("Provide clock is TRUE, do pause->resume\n");
1439 __gst_pause(player, FALSE);
1440 __gst_resume(player, FALSE);
1445 case GST_MESSAGE_NEW_CLOCK:
1447 GstClock *clock = NULL;
1448 gst_message_parse_new_clock(msg, &clock);
1449 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1453 case GST_MESSAGE_ELEMENT:
1455 const gchar *structure_name;
1456 gint count = 0, idx = 0;
1457 MMHandleType attrs = 0;
1459 attrs = MMPLAYER_GET_ATTRS(player);
1461 LOGE("cannot get content attribute");
1465 if (gst_message_get_structure(msg) == NULL)
1468 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1469 if (!structure_name)
1472 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1474 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1475 const GValue *var_info = NULL;
1477 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1478 if (var_info != NULL) {
1479 if (player->adaptive_info.var_list)
1480 g_list_free_full(player->adaptive_info.var_list, g_free);
1482 /* share addr or copy the list */
1483 player->adaptive_info.var_list =
1484 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1486 count = g_list_length(player->adaptive_info.var_list);
1488 VariantData *temp = NULL;
1490 /* print out for debug */
1491 LOGD("num of variant_info %d", count);
1492 for (idx = 0; idx < count; idx++) {
1493 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1495 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1501 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1502 gint num_buffers = 0;
1503 gint extra_num_buffers = 0;
1505 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1506 player->video_num_buffers = num_buffers;
1507 LOGD("video_num_buffers : %d", player->video_num_buffers);
1510 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1511 player->video_extra_num_buffers = extra_num_buffers;
1512 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1517 if (!strcmp(structure_name, "Language_list")) {
1518 const GValue *lang_list = NULL;
1519 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1520 if (lang_list != NULL) {
1521 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1523 LOGD("Total audio tracks(from parser) = %d \n", count);
1527 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1528 const GValue *lang_list = NULL;
1529 MMPlayerLangStruct *temp = NULL;
1531 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1532 if (lang_list != NULL) {
1533 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1535 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1536 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1537 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1538 if (mmf_attrs_commit(attrs))
1539 LOGE("failed to commit.\n");
1540 LOGD("Total subtitle tracks = %d \n", count);
1543 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1545 LOGD("value of lang_key is %s and lang_code is %s",
1546 temp->language_key, temp->language_code);
1549 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1550 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1555 /* custom message */
1556 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1557 MMMessageParamType msg_param = {0,};
1558 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1559 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1562 /* custom message for RTSP attribute :
1563 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1564 sdp which has contents info is received when rtsp connection is opened.
1565 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1566 if (!strcmp(structure_name, "rtspsrc_properties")) {
1568 gchar *audio_codec = NULL;
1569 gchar *video_codec = NULL;
1570 gchar *video_frame_size = NULL;
1572 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1573 LOGD("rtsp duration : %lld msec", GST_TIME_AS_MSECONDS(player->duration));
1574 player->streaming_type = __mmplayer_get_stream_service_type(player);
1575 mm_attrs_set_int_by_name(attrs, "content_duration", GST_TIME_AS_MSECONDS(player->duration));
1577 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1578 LOGD("rtsp_audio_codec : %s", audio_codec);
1580 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1582 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1583 LOGD("rtsp_video_codec : %s", video_codec);
1585 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1587 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1588 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1589 if (video_frame_size) {
1591 char *seperator = strchr(video_frame_size, '-');
1594 char video_width[10] = {0,};
1595 int frame_size_len = strlen(video_frame_size);
1596 int separtor_len = strlen(seperator);
1598 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1599 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1602 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1606 if (mmf_attrs_commit(attrs))
1607 LOGE("failed to commit.\n");
1612 case GST_MESSAGE_DURATION_CHANGED:
1614 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1615 if (!__mmplayer_gst_handle_duration(player, msg))
1616 LOGW("failed to update duration");
1621 case GST_MESSAGE_ASYNC_START:
1622 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1625 case GST_MESSAGE_ASYNC_DONE:
1627 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1629 /* we only handle messages from pipeline */
1630 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1633 if (player->doing_seek) {
1634 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1635 player->doing_seek = FALSE;
1636 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1637 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1638 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1639 (player->streamer) &&
1640 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1641 (player->streamer->is_buffering == FALSE)) {
1642 GstQuery *query = NULL;
1643 gboolean busy = FALSE;
1646 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1647 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1648 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1649 gst_query_parse_buffering_percent(query, &busy, &percent);
1650 gst_query_unref(query);
1652 LOGD("buffered percent(%s): %d\n",
1653 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1656 if (percent >= 100) {
1657 player->streamer->is_buffering = FALSE;
1658 __mmplayer_handle_buffering_message(player);
1668 #if 0 /* delete unnecessary logs */
1669 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1670 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1671 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1672 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1673 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1674 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1675 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1676 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1677 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1678 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1679 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1680 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1681 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1682 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1683 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1690 /* should not call 'gst_message_unref(msg)' */
1695 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1701 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1702 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1704 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1705 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1706 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1708 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1709 LOGD("data total size of http content: %lld", bytes);
1710 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1713 /* handling audio clip which has vbr. means duration is keep changing */
1714 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1721 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1722 mm_player_spherical_metadata_t *metadata) {
1723 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1724 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1725 gst_tag_list_get_string(tags, "stitching_software",
1726 &metadata->stitching_software);
1727 gst_tag_list_get_string(tags, "projection_type",
1728 &metadata->projection_type_string);
1729 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1730 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1731 gst_tag_list_get_int(tags, "init_view_heading",
1732 &metadata->init_view_heading);
1733 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1734 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1735 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1736 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1737 &metadata->full_pano_width_pixels);
1738 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1739 &metadata->full_pano_height_pixels);
1740 gst_tag_list_get_int(tags, "cropped_area_image_width",
1741 &metadata->cropped_area_image_width);
1742 gst_tag_list_get_int(tags, "cropped_area_image_height",
1743 &metadata->cropped_area_image_height);
1744 gst_tag_list_get_int(tags, "cropped_area_left",
1745 &metadata->cropped_area_left);
1746 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1747 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1748 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1749 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1753 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1756 /* macro for better code readability */
1757 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1758 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1759 if (string != NULL) { \
1760 SECURE_LOGD("update tag string : %s\n", string); \
1761 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1762 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1763 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1764 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1765 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1766 g_free(new_string); \
1767 new_string = NULL; \
1769 mm_attrs_set_string_by_name(attribute, playertag, string); \
1776 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1778 GstSample *sample = NULL;\
1779 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1780 GstMapInfo info = GST_MAP_INFO_INIT;\
1781 buffer = gst_sample_get_buffer(sample);\
1782 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1783 LOGD("failed to get image data from tag");\
1784 gst_sample_unref(sample);\
1787 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1788 MMPLAYER_FREEIF(player->album_art);\
1789 player->album_art = (gchar *)g_malloc(info.size);\
1790 if (player->album_art) {\
1791 memcpy(player->album_art, info.data, info.size);\
1792 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1793 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1794 msg_param.data = (void *)player->album_art;\
1795 msg_param.size = info.size;\
1796 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1797 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1800 gst_buffer_unmap(buffer, &info);\
1801 gst_sample_unref(sample);\
1805 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1807 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1810 gchar *tag_list_str = NULL; \
1811 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1812 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1813 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1814 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1815 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1817 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1818 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1819 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1820 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1821 player->bitrate[track_type] = v_uint; \
1822 player->total_bitrate = 0; \
1823 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1824 player->total_bitrate += player->bitrate[i]; \
1825 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1826 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1827 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1828 player->maximum_bitrate[track_type] = v_uint; \
1829 player->total_maximum_bitrate = 0; \
1830 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1831 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1832 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1833 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1835 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1838 g_free(tag_list_str); \
1843 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1844 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1845 if (date != NULL) {\
1846 string = g_strdup_printf("%d", g_date_get_year(date));\
1847 mm_attrs_set_string_by_name(attribute, playertag, string);\
1848 SECURE_LOGD("metainfo year : %s\n", string);\
1849 MMPLAYER_FREEIF(string);\
1854 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1855 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1856 if (datetime != NULL) {\
1857 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1858 mm_attrs_set_string_by_name(attribute, playertag, string);\
1859 SECURE_LOGD("metainfo year : %s\n", string);\
1860 MMPLAYER_FREEIF(string);\
1861 gst_date_time_unref(datetime);\
1865 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1866 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1868 /* FIXIT : don't know how to store date */\
1874 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1875 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1877 /* FIXIT : don't know how to store date */\
1883 /* function start */
1884 GstTagList* tag_list = NULL;
1886 MMHandleType attrs = 0;
1888 char *string = NULL;
1891 GstDateTime *datetime = NULL;
1893 GstBuffer *buffer = NULL;
1895 MMMessageParamType msg_param = {0, };
1897 /* currently not used. but those are needed for above macro */
1898 //guint64 v_uint64 = 0;
1899 //gdouble v_double = 0;
1901 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1903 attrs = MMPLAYER_GET_ATTRS(player);
1905 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1907 /* get tag list from gst message */
1908 gst_message_parse_tag(msg, &tag_list);
1910 /* store tags to player attributes */
1911 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1912 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1913 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1914 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1915 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1916 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1917 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1918 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1919 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1920 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1921 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1922 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1923 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1924 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1925 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1926 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1927 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1928 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1929 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1930 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1931 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1932 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1933 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1934 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1935 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1936 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1937 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1938 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1939 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1940 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1941 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1942 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1943 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1944 MMPLAYER_UPDATE_TAG_LOCK(player);
1945 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1946 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1947 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1948 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1949 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1950 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1951 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1952 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1953 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1954 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1955 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1956 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1958 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1959 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1961 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1962 if (player->video360_metadata.is_spherical == -1) {
1963 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1964 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
1965 player->video360_metadata.is_spherical);
1966 if (player->video360_metadata.is_spherical == 1) {
1967 LOGD("This is spherical content for 360 playback.");
1968 player->is_content_spherical = TRUE;
1970 LOGD("This is not spherical content");
1971 player->is_content_spherical = FALSE;
1974 if (player->video360_metadata.projection_type_string) {
1975 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
1976 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
1978 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
1979 player->is_content_spherical = player->is_video360_enabled = FALSE;
1983 if (player->video360_metadata.stereo_mode_string) {
1984 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
1985 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
1986 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
1987 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
1988 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
1989 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
1991 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
1992 player->is_content_spherical = player->is_video360_enabled = FALSE;
1998 if (mmf_attrs_commit(attrs))
1999 LOGE("failed to commit.\n");
2001 gst_tag_list_free(tag_list);
2007 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2009 mm_player_t* player = (mm_player_t*) data;
2013 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2014 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2015 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2016 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2018 * [1] audio and video will be dumped with filesink.
2019 * [2] autoplugging is done by just using pad caps.
2020 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2021 * and the video will be dumped via filesink.
2023 if (player->num_dynamic_pad == 0) {
2024 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2026 if (!__mmplayer_gst_remove_fakesink(player,
2027 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2028 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2029 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2030 * source element are not same. To overcome this situation, this function will called
2031 * several places and several times. Therefore, this is not an error case.
2036 /* create dot before error-return. for debugging */
2037 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2039 player->no_more_pad = TRUE;
2045 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2047 GstElement* parent = NULL;
2049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2051 /* if we have no fakesink. this meas we are using decodebin which doesn'
2052 t need to add extra fakesink */
2053 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2056 MMPLAYER_FSINK_LOCK(player);
2061 /* get parent of fakesink */
2062 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2064 LOGD("fakesink already removed\n");
2068 gst_element_set_locked_state(fakesink->gst, TRUE);
2070 /* setting the state to NULL never returns async
2071 * so no need to wait for completion of state transiton
2073 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2074 LOGE("fakesink state change failure!\n");
2075 /* FIXIT : should I return here? or try to proceed to next? */
2078 /* remove fakesink from it's parent */
2079 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2080 LOGE("failed to remove fakesink\n");
2082 gst_object_unref(parent);
2087 gst_object_unref(parent);
2089 LOGD("state-holder removed\n");
2091 gst_element_set_locked_state(fakesink->gst, FALSE);
2093 MMPLAYER_FSINK_UNLOCK(player);
2098 gst_element_set_locked_state(fakesink->gst, FALSE);
2100 MMPLAYER_FSINK_UNLOCK(player);
2106 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2108 GstPad *sinkpad = NULL;
2109 GstCaps* caps = NULL;
2110 GstElement* new_element = NULL;
2111 GstStructure* str = NULL;
2112 const gchar* name = NULL;
2114 mm_player_t* player = (mm_player_t*) data;
2118 MMPLAYER_RETURN_IF_FAIL(element && pad);
2119 MMPLAYER_RETURN_IF_FAIL(player &&
2121 player->pipeline->mainbin);
2124 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2125 * num_dynamic_pad will decreased after creating a sinkbin.
2127 player->num_dynamic_pad++;
2128 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2130 caps = gst_pad_query_caps(pad, NULL);
2132 MMPLAYER_CHECK_NULL(caps);
2134 /* clear previous result*/
2135 player->have_dynamic_pad = FALSE;
2137 str = gst_caps_get_structure(caps, 0);
2140 LOGE("cannot get structure from caps.\n");
2144 name = gst_structure_get_name(str);
2146 LOGE("cannot get mimetype from structure.\n");
2150 if (strstr(name, "video")) {
2152 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2154 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2155 if (player->v_stream_caps) {
2156 gst_caps_unref(player->v_stream_caps);
2157 player->v_stream_caps = NULL;
2160 new_element = gst_element_factory_make("fakesink", NULL);
2161 player->num_dynamic_pad--;
2166 /* clear previous result*/
2167 player->have_dynamic_pad = FALSE;
2169 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2170 LOGE("failed to autoplug for caps");
2174 /* check if there's dynamic pad*/
2175 if (player->have_dynamic_pad) {
2176 LOGE("using pad caps assums there's no dynamic pad !\n");
2180 gst_caps_unref(caps);
2185 /* excute new_element if created*/
2187 LOGD("adding new element to pipeline\n");
2189 /* set state to READY before add to bin */
2190 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2192 /* add new element to the pipeline */
2193 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2194 LOGE("failed to add autoplug element to bin\n");
2198 /* get pad from element */
2199 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2201 LOGE("failed to get sinkpad from autoplug element\n");
2206 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2207 LOGE("failed to link autoplug element\n");
2211 gst_object_unref(sinkpad);
2214 /* run. setting PLAYING here since streamming source is live source */
2215 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2219 gst_caps_unref(caps);
2225 STATE_CHANGE_FAILED:
2227 /* FIXIT : take care if new_element has already added to pipeline */
2229 gst_object_unref(GST_OBJECT(new_element));
2232 gst_object_unref(GST_OBJECT(sinkpad));
2235 gst_caps_unref(caps);
2237 /* FIXIT : how to inform this error to MSL ????? */
2238 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2239 * then post an error to application
2243 static GstPadProbeReturn
2244 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2246 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2247 return GST_PAD_PROBE_OK;
2250 static GstPadProbeReturn
2251 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2253 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2254 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2255 mm_player_t* player = (mm_player_t*)data;
2256 GstCaps* caps = NULL;
2257 GstStructure* str = NULL;
2258 const gchar* name = NULL;
2259 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2262 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2263 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2264 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2265 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2266 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2268 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2269 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2273 caps = gst_pad_query_caps(pad, NULL);
2275 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2279 str = gst_caps_get_structure(caps, 0);
2281 LOGE("failed to get structure from caps");
2285 name = gst_structure_get_name(str);
2287 LOGE("failed to get name from str");
2291 if (strstr(name, "audio")) {
2292 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2293 } else if (strstr(name, "video")) {
2294 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2296 /* text track is not supportable */
2297 LOGE("invalid name %s", name);
2301 switch (GST_EVENT_TYPE(event)) {
2304 /* in case of gapless, drop eos event not to send it to sink */
2305 if (player->gapless.reconfigure && !player->msg_posted) {
2306 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2307 ret = GST_PAD_PROBE_DROP;
2311 case GST_EVENT_STREAM_START:
2313 gint64 stop_running_time = 0;
2314 gint64 position_running_time = 0;
2315 gint64 position = 0;
2318 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2319 if ((player->gapless.update_segment[idx] == TRUE) ||
2320 !(player->selector[idx].event_probe_id)) {
2321 /* LOGW("[%d] skip", idx); */
2325 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2327 gst_segment_to_running_time(&player->gapless.segment[idx],
2328 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2329 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2331 gst_segment_to_running_time(&player->gapless.segment[idx],
2332 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2334 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2336 gst_segment_to_running_time(&player->gapless.segment[idx],
2337 GST_FORMAT_TIME, player->duration);
2340 position_running_time =
2341 gst_segment_to_running_time(&player->gapless.segment[idx],
2342 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2344 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2345 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2347 GST_TIME_ARGS(stop_running_time),
2348 GST_TIME_ARGS(position_running_time),
2349 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2350 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2352 position_running_time = MAX(position_running_time, stop_running_time);
2353 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2354 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2355 position_running_time = MAX(0, position_running_time);
2356 position = MAX(position, position_running_time);
2359 if (position != 0) {
2360 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2361 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2362 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2364 player->gapless.start_time[stream_type] += position;
2368 case GST_EVENT_FLUSH_STOP:
2370 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2371 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2372 player->gapless.start_time[stream_type] = 0;
2375 case GST_EVENT_SEGMENT:
2380 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2381 gst_event_copy_segment(event, &segment);
2383 if (segment.format == GST_FORMAT_TIME) {
2384 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2385 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2386 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2387 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2388 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2389 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2391 /* keep the all the segment ev to cover the seeking */
2392 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2393 player->gapless.update_segment[stream_type] = TRUE;
2395 if (!player->gapless.running)
2398 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2400 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2402 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2403 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2404 gst_event_unref(event);
2405 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2411 gdouble proportion = 0.0;
2412 GstClockTimeDiff diff = 0;
2413 GstClockTime timestamp = 0;
2414 gint64 running_time_diff = -1;
2415 GstQOSType type = 0;
2416 GstEvent *tmpev = NULL;
2418 running_time_diff = player->gapless.segment[stream_type].base;
2420 if (running_time_diff <= 0) /* don't need to adjust */
2423 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2424 gst_event_unref(event);
2426 if (timestamp < running_time_diff) {
2427 LOGW("QOS event from previous group");
2428 ret = GST_PAD_PROBE_DROP;
2432 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2433 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2434 stream_type, GST_TIME_ARGS(timestamp),
2435 GST_TIME_ARGS(running_time_diff),
2436 GST_TIME_ARGS(timestamp - running_time_diff));
2438 timestamp -= running_time_diff;
2440 /* That case is invalid for QoS events */
2441 if (diff < 0 && -diff > timestamp) {
2442 LOGW("QOS event from previous group");
2443 ret = GST_PAD_PROBE_DROP;
2447 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2448 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2458 gst_caps_unref(caps);
2463 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2465 mm_player_t* player = NULL;
2466 GstElement* pipeline = NULL;
2467 GstElement* selector = NULL;
2468 GstElement* fakesink = NULL;
2469 GstCaps* caps = NULL;
2470 GstStructure* str = NULL;
2471 const gchar* name = NULL;
2472 GstPad* sinkpad = NULL;
2473 GstPad* srcpad = NULL;
2474 gboolean first_track = FALSE;
2476 enum MainElementID elemId = MMPLAYER_M_NUM;
2477 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2480 player = (mm_player_t*)data;
2482 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2483 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2485 //LOGD("pad-added signal handling\n");
2487 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2489 /* get mimetype from caps */
2490 caps = gst_pad_query_caps(pad, NULL);
2492 LOGE("cannot get caps from pad.\n");
2496 str = gst_caps_get_structure(caps, 0);
2498 LOGE("cannot get structure from caps.\n");
2502 name = gst_structure_get_name(str);
2504 LOGE("cannot get mimetype from structure.\n");
2508 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2509 //LOGD("detected mimetype : %s\n", name);
2511 if (strstr(name, "video")) {
2514 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2515 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2517 /* don't make video because of not required, and not support multiple track */
2518 if (stype == MM_DISPLAY_SURFACE_NULL) {
2519 LOGD("no video sink by null surface");
2521 gchar *caps_str = gst_caps_to_string(caps);
2522 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2523 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2524 player->set_mode.video_zc = TRUE;
2526 MMPLAYER_FREEIF(caps_str);
2528 if (player->v_stream_caps) {
2529 gst_caps_unref(player->v_stream_caps);
2530 player->v_stream_caps = NULL;
2533 LOGD("create fakesink instead of videobin");
2536 fakesink = gst_element_factory_make("fakesink", NULL);
2537 if (fakesink == NULL) {
2538 LOGE("ERROR : fakesink create error\n");
2542 if (player->ini.set_dump_element_flag)
2543 __mmplayer_add_dump_buffer_probe(player, fakesink);
2545 player->video_fakesink = fakesink;
2547 /* store it as it's sink element */
2548 __mmplayer_add_sink(player, player->video_fakesink);
2550 gst_bin_add(GST_BIN(pipeline), fakesink);
2553 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2555 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2556 LOGW("failed to link fakesink\n");
2557 gst_object_unref(GST_OBJECT(fakesink));
2561 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2562 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2563 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2566 if (player->set_mode.media_packet_video_stream) {
2567 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2569 MMPLAYER_SIGNAL_CONNECT(player,
2571 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2573 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2576 MMPLAYER_SIGNAL_CONNECT(player,
2578 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2580 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2584 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2585 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2589 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2590 __mmplayer_gst_decode_callback(elem, pad, player);
2594 LOGD("video selector \n");
2595 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2596 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2598 if (strstr(name, "audio")) {
2599 gint samplerate = 0;
2602 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2603 __mmplayer_gst_decode_callback(elem, pad, player);
2607 LOGD("audio selector \n");
2608 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2609 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2611 gst_structure_get_int(str, "rate", &samplerate);
2612 gst_structure_get_int(str, "channels", &channels);
2614 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2616 fakesink = gst_element_factory_make("fakesink", NULL);
2617 if (fakesink == NULL) {
2618 LOGE("ERROR : fakesink create error\n");
2622 gst_bin_add(GST_BIN(pipeline), fakesink);
2625 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2627 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2628 LOGW("failed to link fakesink\n");
2629 gst_object_unref(GST_OBJECT(fakesink));
2633 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2634 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2635 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2639 } else if (strstr(name, "text")) {
2640 LOGD("text selector \n");
2641 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2642 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2644 LOGE("wrong elem id \n");
2649 selector = player->pipeline->mainbin[elemId].gst;
2650 if (selector == NULL) {
2651 selector = gst_element_factory_make("input-selector", NULL);
2652 LOGD("Creating input-selector\n");
2653 if (selector == NULL) {
2654 LOGE("ERROR : input-selector create error\n");
2657 g_object_set(selector, "sync-streams", TRUE, NULL);
2659 player->pipeline->mainbin[elemId].id = elemId;
2660 player->pipeline->mainbin[elemId].gst = selector;
2663 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2665 srcpad = gst_element_get_static_pad(selector, "src");
2667 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2668 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2669 __mmplayer_gst_selector_blocked, NULL, NULL);
2670 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2671 __mmplayer_gst_selector_event_probe, player, NULL);
2673 gst_element_set_state(selector, GST_STATE_PAUSED);
2674 gst_bin_add(GST_BIN(pipeline), selector);
2676 LOGD("input-selector is already created.\n");
2679 LOGD("Calling request pad with selector %p \n", selector);
2680 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2682 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2684 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2685 LOGW("failed to link selector\n");
2686 gst_object_unref(GST_OBJECT(selector));
2691 LOGD("this is first track --> active track \n");
2692 g_object_set(selector, "active-pad", sinkpad, NULL);
2695 _mmplayer_track_update_info(player, stream_type, sinkpad);
2702 gst_caps_unref(caps);
2705 gst_object_unref(GST_OBJECT(sinkpad));
2710 gst_object_unref(GST_OBJECT(srcpad));
2717 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2719 GstPad* srcpad = NULL;
2720 MMHandleType attrs = 0;
2721 gint active_index = 0;
2723 // [link] input-selector :: textbin
2724 srcpad = gst_element_get_static_pad(text_selector, "src");
2726 LOGE("failed to get srcpad from selector\n");
2730 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2732 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2733 if ((active_index != DEFAULT_TRACK) &&
2734 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2735 LOGW("failed to change text track\n");
2736 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2739 player->no_more_pad = TRUE;
2740 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2742 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2743 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2744 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2745 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2748 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2750 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2751 player->has_closed_caption = TRUE;
2753 attrs = MMPLAYER_GET_ATTRS(player);
2755 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2756 if (mmf_attrs_commit(attrs))
2757 LOGE("failed to commit.\n");
2759 LOGE("cannot get content attribute");
2762 gst_object_unref(GST_OBJECT(srcpad));
2768 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2770 mm_player_t* player = (mm_player_t*)data;
2771 GstElement* selector = NULL;
2772 GstElement* queue = NULL;
2774 GstPad* srcpad = NULL;
2775 GstPad* sinkpad = NULL;
2776 GstCaps* caps = NULL;
2777 gchar* caps_str = NULL;
2780 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2782 caps = gst_pad_get_current_caps(pad);
2783 caps_str = gst_caps_to_string(caps);
2784 LOGD("deinterleave new caps : %s\n", caps_str);
2785 MMPLAYER_FREEIF(caps_str);
2786 gst_caps_unref(caps);
2788 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2789 LOGE("ERROR : queue create error\n");
2793 g_object_set(G_OBJECT(queue),
2794 "max-size-buffers", 10,
2795 "max-size-bytes", 0,
2796 "max-size-time", (guint64)0,
2799 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2802 LOGE("there is no audio channel selector.\n");
2806 srcpad = gst_element_get_static_pad(queue, "src");
2807 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2809 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2811 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2812 LOGW("failed to link deinterleave - selector\n");
2816 gst_element_set_state(queue, GST_STATE_PAUSED);
2817 player->audio_mode.total_track_num++;
2822 gst_object_unref(GST_OBJECT(srcpad));
2827 gst_object_unref(GST_OBJECT(sinkpad));
2836 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2838 mm_player_t* player = NULL;
2839 GstElement* selector = NULL;
2840 GstPad* sinkpad = NULL;
2841 gint active_index = 0;
2842 gchar* change_pad_name = NULL;
2843 GstCaps* caps = NULL; // no need to unref
2844 gint default_audio_ch = 0;
2847 player = (mm_player_t*) data;
2849 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2852 LOGE("there is no audio channel selector.\n");
2856 active_index = player->audio_mode.active_pad_index;
2858 if (active_index != default_audio_ch) {
2859 gint audio_ch = default_audio_ch;
2861 /*To get the new pad from the selector*/
2862 change_pad_name = g_strdup_printf("sink%d", active_index);
2863 if (change_pad_name != NULL) {
2864 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2865 if (sinkpad != NULL) {
2866 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2867 g_object_set(selector, "active-pad", sinkpad, NULL);
2869 audio_ch = active_index;
2871 caps = gst_pad_get_current_caps(sinkpad);
2872 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2874 __mmplayer_set_audio_attrs(player, caps);
2875 gst_caps_unref(caps);
2877 MMPLAYER_FREEIF(change_pad_name);
2880 player->audio_mode.active_pad_index = audio_ch;
2881 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2887 gst_object_unref(sinkpad);
2894 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2896 mm_player_t* player = NULL;
2897 MMPlayerGstElement *mainbin = NULL;
2899 GstElement* tee = NULL;
2900 GstElement* stereo_queue = NULL;
2901 GstElement* mono_queue = NULL;
2902 GstElement* conv = NULL;
2903 GstElement* filter = NULL;
2904 GstElement* deinterleave = NULL;
2905 GstElement* selector = NULL;
2907 GstPad* srcpad = NULL;
2908 GstPad* selector_srcpad = NULL;
2909 GstPad* sinkpad = NULL;
2910 GstCaps* caps = NULL;
2911 gulong block_id = 0;
2916 player = (mm_player_t*) data;
2918 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2919 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2921 mainbin = player->pipeline->mainbin;
2924 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2925 LOGE("ERROR : tee create error\n");
2929 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2930 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2932 gst_element_set_state(tee, GST_STATE_PAUSED);
2935 srcpad = gst_element_get_request_pad(tee, "src_%u");
2936 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2937 LOGE("ERROR : stereo queue create error\n");
2941 g_object_set(G_OBJECT(stereo_queue),
2942 "max-size-buffers", 10,
2943 "max-size-bytes", 0,
2944 "max-size-time", (guint64)0,
2947 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2948 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2951 gst_object_unref(GST_OBJECT(srcpad));
2955 srcpad = gst_element_get_request_pad(tee, "src_%u");
2957 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2958 LOGE("ERROR : mono queue create error\n");
2962 g_object_set(G_OBJECT(mono_queue),
2963 "max-size-buffers", 10,
2964 "max-size-bytes", 0,
2965 "max-size-time", (guint64)0,
2968 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
2969 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
2971 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
2972 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
2975 srcpad = gst_element_get_static_pad(mono_queue, "src");
2976 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
2977 LOGE("ERROR : audioconvert create error\n");
2981 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
2982 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
2986 gst_object_unref(GST_OBJECT(srcpad));
2989 srcpad = gst_element_get_static_pad(conv, "src");
2991 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
2992 LOGE("ERROR : capsfilter create error\n");
2996 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
2997 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
2999 caps = gst_caps_from_string("audio/x-raw-int, "
3000 "width = (int) 16, "
3001 "depth = (int) 16, "
3002 "channels = (int) 2");
3004 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3005 gst_caps_unref(caps);
3007 gst_element_set_state(conv, GST_STATE_PAUSED);
3008 gst_element_set_state(filter, GST_STATE_PAUSED);
3012 gst_object_unref(GST_OBJECT(srcpad));
3015 srcpad = gst_element_get_static_pad(filter, "src");
3017 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3018 LOGE("ERROR : deinterleave create error\n");
3022 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3024 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3025 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3027 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3028 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3030 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3031 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3034 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3035 if (selector == NULL) {
3036 LOGE("ERROR : audio-selector create error\n");
3040 g_object_set(selector, "sync-streams", TRUE, NULL);
3041 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3043 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3044 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3046 selector_srcpad = gst_element_get_static_pad(selector, "src");
3048 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3050 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3051 __mmplayer_gst_selector_blocked, NULL, NULL);
3054 gst_object_unref(GST_OBJECT(srcpad));
3058 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3059 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3061 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3062 LOGW("failed to link queue_stereo - selector\n");
3066 player->audio_mode.total_track_num++;
3068 g_object_set(selector, "active-pad", sinkpad, NULL);
3069 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3070 gst_element_set_state(selector, GST_STATE_PAUSED);
3072 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3076 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3077 if (block_id != 0) {
3078 gst_pad_remove_probe(selector_srcpad, block_id);
3083 gst_object_unref(GST_OBJECT(sinkpad));
3088 gst_object_unref(GST_OBJECT(srcpad));
3092 if (selector_srcpad) {
3093 gst_object_unref(GST_OBJECT(selector_srcpad));
3094 selector_srcpad = NULL;
3102 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3104 mm_player_t* player = NULL;
3105 GstPad* srcpad = NULL;
3106 GstElement* video_selector = NULL;
3107 GstElement* audio_selector = NULL;
3108 GstElement* text_selector = NULL;
3109 MMHandleType attrs = 0;
3110 gint active_index = 0;
3111 gint64 dur_bytes = 0L;
3113 player = (mm_player_t*) data;
3115 LOGD("no-more-pad signal handling\n");
3117 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3118 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3119 LOGW("no need to go more");
3121 if (player->gapless.reconfigure) {
3122 player->gapless.reconfigure = FALSE;
3123 MMPLAYER_PLAYBACK_UNLOCK(player);
3129 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3130 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3131 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3132 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3133 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3135 if (NULL == player->streamer) {
3136 LOGW("invalid state for buffering");
3140 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3141 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3143 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3144 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3146 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3148 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3149 LOGE("fail to get duration.\n");
3151 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3152 // use file information was already set on Q2 when it was created.
3153 __mm_player_streaming_set_queue2(player->streamer,
3154 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3155 TRUE, // use_buffering
3157 init_buffering_time,
3159 player->ini.http_buffering_limit, // high percent
3160 MUXED_BUFFER_TYPE_MEM_QUEUE,
3162 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3165 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3166 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3167 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3168 if (video_selector) {
3169 // [link] input-selector :: videobin
3170 srcpad = gst_element_get_static_pad(video_selector, "src");
3172 LOGE("failed to get srcpad from video selector\n");
3176 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3177 if (!text_selector && !audio_selector)
3178 player->no_more_pad = TRUE;
3180 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3182 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3183 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3184 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3185 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3189 if (audio_selector) {
3190 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3191 if ((active_index != DEFAULT_TRACK) &&
3192 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3193 LOGW("failed to change audio track\n");
3194 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3197 // [link] input-selector :: audiobin
3198 srcpad = gst_element_get_static_pad(audio_selector, "src");
3200 LOGE("failed to get srcpad from selector\n");
3204 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3206 player->no_more_pad = TRUE;
3208 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3209 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3210 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3211 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3212 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3215 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3217 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3219 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3220 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3221 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3222 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3226 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3228 attrs = MMPLAYER_GET_ATTRS(player);
3230 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3231 if (mmf_attrs_commit(attrs))
3232 LOGE("failed to commit.\n");
3234 LOGE("cannot get content attribute");
3236 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3237 LOGD("There is no audio track : remove audiobin");
3239 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3240 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3242 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3243 MMPLAYER_FREEIF(player->pipeline->audiobin);
3246 if (player->num_dynamic_pad == 0)
3247 __mmplayer_pipeline_complete(NULL, player);
3250 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3252 __mmplayer_handle_text_decode_path(player, text_selector);
3259 gst_object_unref(GST_OBJECT(srcpad));
3263 if (player->gapless.reconfigure) {
3264 player->gapless.reconfigure = FALSE;
3265 MMPLAYER_PLAYBACK_UNLOCK(player);
3270 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3272 mm_player_t* player = NULL;
3273 MMHandleType attrs = 0;
3274 GstElement* pipeline = NULL;
3275 GstCaps* caps = NULL;
3276 gchar* caps_str = NULL;
3277 GstStructure* str = NULL;
3278 const gchar* name = NULL;
3279 GstPad* sinkpad = NULL;
3280 GstElement* sinkbin = NULL;
3281 gboolean reusing = FALSE;
3282 GstElement *text_selector = NULL;
3285 player = (mm_player_t*) data;
3287 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3288 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3290 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3292 attrs = MMPLAYER_GET_ATTRS(player);
3294 LOGE("cannot get content attribute\n");
3298 /* get mimetype from caps */
3299 caps = gst_pad_query_caps(pad, NULL);
3301 LOGE("cannot get caps from pad.\n");
3304 caps_str = gst_caps_to_string(caps);
3306 str = gst_caps_get_structure(caps, 0);
3308 LOGE("cannot get structure from caps.\n");
3312 name = gst_structure_get_name(str);
3314 LOGE("cannot get mimetype from structure.\n");
3318 //LOGD("detected mimetype : %s\n", name);
3320 if (strstr(name, "audio")) {
3321 if (player->pipeline->audiobin == NULL) {
3322 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3323 LOGE("failed to create audiobin. continuing without audio\n");
3327 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3328 LOGD("creating audiosink bin success\n");
3331 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3332 LOGD("reusing audiobin\n");
3333 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3336 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3337 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3339 player->audiosink_linked = 1;
3341 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3343 LOGE("failed to get pad from sinkbin\n");
3346 } else if (strstr(name, "video")) {
3347 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3348 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3349 player->set_mode.video_zc = TRUE;
3351 if (player->pipeline->videobin == NULL) {
3352 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3353 /* get video surface type */
3354 int surface_type = 0;
3355 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3356 LOGD("display_surface_type(%d)\n", surface_type);
3358 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3359 LOGD("not make videobin because it dose not want\n");
3363 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3364 /* mark video overlay for acquire */
3365 if (player->video_overlay_resource == NULL) {
3366 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3367 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3368 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3369 &player->video_overlay_resource)
3370 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3371 LOGE("could not mark video_overlay resource for acquire\n");
3377 player->interrupted_by_resource = FALSE;
3378 /* acquire resources for video overlay */
3379 if (mm_resource_manager_commit(player->resource_manager) !=
3380 MM_RESOURCE_MANAGER_ERROR_NONE) {
3381 LOGE("could not acquire resources for video playing\n");
3385 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3386 LOGE("failed to create videobin. continuing without video\n");
3390 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3391 LOGD("creating videosink bin success\n");
3394 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3395 LOGD("re-using videobin\n");
3396 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3399 player->videosink_linked = 1;
3401 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3403 LOGE("failed to get pad from sinkbin\n");
3406 } else if (strstr(name, "text")) {
3407 if (player->pipeline->textbin == NULL) {
3408 MMPlayerGstElement* mainbin = NULL;
3410 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3411 LOGE("failed to create text sink bin. continuing without text\n");
3415 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3416 LOGD("creating textsink bin success\n");
3418 /* FIXIT : track number shouldn't be hardcoded */
3419 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3421 player->textsink_linked = 1;
3422 LOGI("player->textsink_linked set to 1\n");
3424 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3426 LOGE("failed to get pad from sinkbin\n");
3430 mainbin = player->pipeline->mainbin;
3432 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3433 /* input selector */
3434 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3435 if (!text_selector) {
3436 LOGE("failed to create subtitle input selector element\n");
3439 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3441 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3442 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3445 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3446 LOGE("failed to set state(READY) to sinkbin\n");
3450 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3451 LOGW("failed to add subtitle input selector\n");
3455 LOGD("created element input-selector");
3458 LOGD("already having subtitle input selector");
3459 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3462 if (!player->textsink_linked) {
3463 LOGD("re-using textbin\n");
3466 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3468 player->textsink_linked = 1;
3469 LOGI("player->textsink_linked set to 1\n");
3471 LOGD("ignoring internal subtutle since external subtitle is available");
3474 LOGW("unknown type of elementary stream!ignoring it...\n");
3481 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3482 LOGE("failed to set state(READY) to sinkbin\n");
3486 /* Added for multi audio support to avoid adding audio bin again*/
3488 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3489 LOGE("failed to add sinkbin to pipeline\n");
3495 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3496 LOGE("failed to get pad from sinkbin\n");
3502 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3503 LOGE("failed to set state(PAUSED) to sinkbin\n");
3507 if (text_selector) {
3508 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3509 LOGE("failed to set state(PAUSED) to sinkbin\n");
3515 gst_object_unref(sinkpad);
3519 LOGD("[handle: %p] linking sink bin success", player);
3521 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3522 * streaming task. if the task blocked, then buffer will not flow to the next element
3523 *(autoplugging element). so this is special hack for streaming. please try to remove it
3525 /* dec stream count. we can remove fakesink if it's zero */
3526 if (player->num_dynamic_pad)
3527 player->num_dynamic_pad--;
3529 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3531 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3532 __mmplayer_pipeline_complete(NULL, player);
3536 MMPLAYER_FREEIF(caps_str);
3539 gst_caps_unref(caps);
3542 gst_object_unref(GST_OBJECT(sinkpad));
3544 /* flusing out new attributes */
3545 if (mmf_attrs_commit(attrs))
3546 LOGE("failed to comit attributes\n");
3552 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3554 int pro_value = 0; // in the case of expection, default will be returned.
3555 int dest_angle = rotation_angle;
3556 int rotation_type = -1;
3558 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3559 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3560 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3562 if (rotation_angle >= 360)
3563 dest_angle = rotation_angle - 360;
3565 /* chech if supported or not */
3566 if (dest_angle % 90) {
3567 LOGD("not supported rotation angle = %d", rotation_angle);
3573 * custom_convert - none (B)
3574 * videoflip - none (C)
3576 if (player->set_mode.video_zc) {
3577 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3578 rotation_type = ROTATION_USING_CUSTOM;
3580 rotation_type = ROTATION_USING_SINK;
3582 int surface_type = 0;
3583 rotation_type = ROTATION_USING_FLIP;
3585 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3586 LOGD("check display surface type attribute: %d", surface_type);
3588 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3589 rotation_type = ROTATION_USING_SINK;
3591 rotation_type = ROTATION_USING_FLIP; //C
3593 LOGD("using %d type for rotation", rotation_type);
3596 /* get property value for setting */
3597 switch (rotation_type) {
3598 case ROTATION_USING_SINK: // tizenwlsink
3600 switch (dest_angle) {
3604 pro_value = 3; // clockwise 90
3610 pro_value = 1; // counter-clockwise 90
3615 case ROTATION_USING_CUSTOM:
3617 gchar *ename = NULL;
3618 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3620 if (g_strrstr(ename, "fimcconvert")) {
3621 switch (dest_angle) {
3625 pro_value = 90; // clockwise 90
3631 pro_value = 270; // counter-clockwise 90
3637 case ROTATION_USING_FLIP: // videoflip
3639 switch (dest_angle) {
3643 pro_value = 1; // clockwise 90
3649 pro_value = 3; // counter-clockwise 90
3656 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3664 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3666 /* check video sinkbin is created */
3667 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3669 player->pipeline->videobin &&
3670 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3671 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3672 MM_ERROR_PLAYER_NOT_INITIALIZED);
3674 return MM_ERROR_NONE;
3678 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3680 int rotation_value = 0;
3681 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3685 /* check video sinkbin is created */
3686 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3689 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3691 /* get rotation value to set */
3692 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3693 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3694 LOGD("set video param : rotate %d", rotation_value);
3698 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3700 MMHandleType attrs = 0;
3704 /* check video sinkbin is created */
3705 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3708 attrs = MMPLAYER_GET_ATTRS(player);
3709 MMPLAYER_RETURN_IF_FAIL(attrs);
3711 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3712 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3713 LOGD("set video param : visible %d", visible);
3717 __mmplayer_video_param_set_display_method(mm_player_t* player)
3719 MMHandleType attrs = 0;
3720 int display_method = 0;
3723 /* check video sinkbin is created */
3724 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3727 attrs = MMPLAYER_GET_ATTRS(player);
3728 MMPLAYER_RETURN_IF_FAIL(attrs);
3730 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3731 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3732 LOGD("set video param : method %d", display_method);
3736 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3738 MMHandleType attrs = 0;
3739 void *handle = NULL;
3741 int wl_window_x = 0;
3742 int wl_window_y = 0;
3743 int wl_window_width = 0;
3744 int wl_window_height = 0;
3747 /* check video sinkbin is created */
3748 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3751 attrs = MMPLAYER_GET_ATTRS(player);
3752 MMPLAYER_RETURN_IF_FAIL(attrs);
3754 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3757 /*It should be set after setting window*/
3758 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3759 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3760 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3761 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3763 /* After setting window handle, set render rectangle */
3764 gst_video_overlay_set_render_rectangle(
3765 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3766 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3767 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3768 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3773 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3775 MMHandleType attrs = 0;
3776 void *handle = NULL;
3778 /* check video sinkbin is created */
3779 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3782 attrs = MMPLAYER_GET_ATTRS(player);
3783 MMPLAYER_RETURN_IF_FAIL(attrs);
3785 /* common case if using overlay surface */
3786 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3789 /* default is using wl_surface_id */
3790 unsigned int wl_surface_id = 0;
3791 wl_surface_id = *(int*)handle;
3792 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3793 gst_video_overlay_set_wl_window_wl_surface_id(
3794 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3797 /* FIXIT : is it error case? */
3798 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3803 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3805 bool update_all_param = FALSE;
3808 /* check video sinkbin is created */
3809 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3810 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3812 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3813 LOGE("can not find tizenwlsink");
3814 return MM_ERROR_PLAYER_INTERNAL;
3817 LOGD("param_name : %s", param_name);
3818 if (!g_strcmp0(param_name, "update_all_param"))
3819 update_all_param = TRUE;
3821 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3822 __mmplayer_video_param_set_display_overlay(player);
3823 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3824 __mmplayer_video_param_set_display_method(player);
3825 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3826 __mmplayer_video_param_set_render_rectangle(player);
3827 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3828 __mmplayer_video_param_set_display_visible(player);
3829 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3830 __mmplayer_video_param_set_display_rotation(player);
3832 return MM_ERROR_NONE;
3836 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3838 MMHandleType attrs = 0;
3839 int surface_type = 0;
3840 int ret = MM_ERROR_NONE;
3844 /* check video sinkbin is created */
3845 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3846 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3848 attrs = MMPLAYER_GET_ATTRS(player);
3850 LOGE("cannot get content attribute");
3851 return MM_ERROR_PLAYER_INTERNAL;
3853 LOGD("param_name : %s", param_name);
3855 /* update display surface */
3856 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3857 LOGD("check display surface type attribute: %d", surface_type);
3859 /* configuring display */
3860 switch (surface_type) {
3861 case MM_DISPLAY_SURFACE_OVERLAY:
3863 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3864 if (ret != MM_ERROR_NONE)
3872 return MM_ERROR_NONE;
3876 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3878 gboolean disable_overlay = FALSE;
3879 mm_player_t* player = (mm_player_t*) hplayer;
3880 int ret = MM_ERROR_NONE;
3883 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3885 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3886 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3888 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3889 LOGW("Display control is not supported");
3890 return MM_ERROR_PLAYER_INTERNAL;
3893 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3895 if (audio_only == (bool)disable_overlay) {
3896 LOGE("It's the same with current setting: (%d)", audio_only);
3897 return MM_ERROR_NONE;
3901 LOGE("disable overlay");
3902 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3904 /* release overlay resource */
3905 if (player->video_overlay_resource != NULL) {
3906 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3907 player->video_overlay_resource);
3908 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3909 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3912 player->video_overlay_resource = NULL;
3915 ret = mm_resource_manager_commit(player->resource_manager);
3916 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3917 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3921 /* mark video overlay for acquire */
3922 if (player->video_overlay_resource == NULL) {
3923 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3924 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3925 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3926 &player->video_overlay_resource);
3927 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3928 LOGE("could not prepare for video_overlay resource\n");
3933 player->interrupted_by_resource = FALSE;
3934 /* acquire resources for video overlay */
3935 ret = mm_resource_manager_commit(player->resource_manager);
3936 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3937 LOGE("could not acquire resources for video playing\n");
3941 LOGD("enable overlay");
3942 __mmplayer_video_param_set_display_overlay(player);
3943 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3948 return MM_ERROR_NONE;
3952 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3954 mm_player_t* player = (mm_player_t*) hplayer;
3955 gboolean disable_overlay = FALSE;
3959 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3960 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3961 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3962 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3963 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3965 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3966 LOGW("Display control is not supported");
3967 return MM_ERROR_PLAYER_INTERNAL;
3970 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3972 *paudio_only = (bool)(disable_overlay);
3974 LOGD("audio_only : %d", *paudio_only);
3978 return MM_ERROR_NONE;
3982 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3984 GList* bucket = element_bucket;
3985 MMPlayerGstElement* element = NULL;
3986 MMPlayerGstElement* prv_element = NULL;
3987 gint successful_link_count = 0;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3993 prv_element = (MMPlayerGstElement*)bucket->data;
3994 bucket = bucket->next;
3996 for (; bucket; bucket = bucket->next) {
3997 element = (MMPlayerGstElement*)bucket->data;
3999 if (element && element->gst) {
4000 /* If next element is audio appsrc then make a separate audio pipeline */
4001 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4002 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4003 prv_element = element;
4007 if (prv_element && prv_element->gst) {
4008 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4009 LOGD("linking [%s] to [%s] success\n",
4010 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4011 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4012 successful_link_count++;
4014 LOGD("linking [%s] to [%s] failed\n",
4015 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4016 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4022 prv_element = element;
4027 return successful_link_count;
4031 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4033 GList* bucket = element_bucket;
4034 MMPlayerGstElement* element = NULL;
4035 int successful_add_count = 0;
4039 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4040 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4042 for (; bucket; bucket = bucket->next) {
4043 element = (MMPlayerGstElement*)bucket->data;
4045 if (element && element->gst) {
4046 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4047 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4048 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4049 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4052 successful_add_count++;
4058 return successful_add_count;
4061 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4063 mm_player_t* player = (mm_player_t*) data;
4064 GstCaps *caps = NULL;
4065 GstStructure *str = NULL;
4070 MMPLAYER_RETURN_IF_FAIL(pad)
4071 MMPLAYER_RETURN_IF_FAIL(unused)
4072 MMPLAYER_RETURN_IF_FAIL(data)
4074 caps = gst_pad_get_current_caps(pad);
4078 str = gst_caps_get_structure(caps, 0);
4082 name = gst_structure_get_name(str);
4086 LOGD("name = %s\n", name);
4088 if (strstr(name, "audio")) {
4089 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4091 if (player->audio_stream_changed_cb) {
4092 LOGE("call the audio stream changed cb\n");
4093 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4095 } else if (strstr(name, "video")) {
4096 if ((name = gst_structure_get_string(str, "format")))
4097 player->set_mode.video_zc = name[0] == 'S';
4099 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4101 if (player->video_stream_changed_cb) {
4102 LOGE("call the video stream changed cb\n");
4103 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4110 gst_caps_unref(caps);
4120 * This function is to create audio pipeline for playing.
4122 * @param player [in] handle of player
4124 * @return This function returns zero on success.
4126 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4128 /* macro for code readability. just for sinkbin-creation functions */
4129 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4131 x_bin[x_id].id = x_id;\
4132 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4133 if (!x_bin[x_id].gst) {\
4134 LOGE("failed to create %s \n", x_factory);\
4137 if (x_player->ini.set_dump_element_flag)\
4138 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4141 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4145 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4150 MMPLAYER_RETURN_IF_FAIL(player);
4152 if (player->audio_stream_buff_list) {
4153 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4154 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4157 LOGD("[%lld] send remained data.", tmp->channel_mask);
4158 __mmplayer_audio_stream_send_data(player, tmp);
4161 g_free(tmp->pcm_data);
4165 g_list_free(player->audio_stream_buff_list);
4166 player->audio_stream_buff_list = NULL;
4173 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4175 MMPlayerAudioStreamDataType audio_stream = { 0, };
4178 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4180 audio_stream.bitrate = a_buffer->bitrate;
4181 audio_stream.channel = a_buffer->channel;
4182 audio_stream.depth = a_buffer->depth;
4183 audio_stream.is_little_endian = a_buffer->is_little_endian;
4184 audio_stream.channel_mask = a_buffer->channel_mask;
4185 audio_stream.data_size = a_buffer->data_size;
4186 audio_stream.data = a_buffer->pcm_data;
4188 /* LOGD("[%lld] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4189 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4195 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4197 mm_player_t* player = (mm_player_t*) data;
4202 gint endianness = 0;
4203 guint64 channel_mask = 0;
4204 void *a_data = NULL;
4206 mm_player_audio_stream_buff_t *a_buffer = NULL;
4207 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4211 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4213 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4214 a_data = mapinfo.data;
4215 a_size = mapinfo.size;
4217 GstCaps *caps = gst_pad_get_current_caps(pad);
4218 GstStructure *structure = gst_caps_get_structure(caps, 0);
4220 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4221 gst_structure_get_int(structure, "rate", &rate);
4222 gst_structure_get_int(structure, "channels", &channel);
4223 gst_structure_get_int(structure, "depth", &depth);
4224 gst_structure_get_int(structure, "endianness", &endianness);
4225 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4226 gst_caps_unref(GST_CAPS(caps));
4228 /* In case of the sync is false, use buffer list. *
4229 * The num of buffer list depends on the num of audio channels */
4230 if (player->audio_stream_buff_list) {
4231 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4232 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4234 if (channel_mask == tmp->channel_mask) {
4235 /* LOGD("[%lld] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4236 if (tmp->data_size + a_size < tmp->buff_size) {
4237 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4238 tmp->data_size += a_size;
4240 /* send data to client */
4241 __mmplayer_audio_stream_send_data(player, tmp);
4243 if (a_size > tmp->buff_size) {
4244 LOGD("[%lld] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4245 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4246 if (tmp->pcm_data == NULL) {
4247 LOGE("failed to realloc data.");
4250 tmp->buff_size = a_size;
4252 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4253 memcpy(tmp->pcm_data, a_data, a_size);
4254 tmp->data_size = a_size;
4259 LOGE("data is empty in list.");
4265 /* create new audio stream data */
4266 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4267 if (a_buffer == NULL) {
4268 LOGE("failed to alloc data.");
4271 a_buffer->bitrate = rate;
4272 a_buffer->channel = channel;
4273 a_buffer->depth = depth;
4274 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4275 a_buffer->channel_mask = channel_mask;
4276 a_buffer->data_size = a_size;
4278 if (!player->audio_stream_sink_sync) {
4279 /* If sync is FALSE, use buffer list to reduce the IPC. */
4280 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4281 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4282 if (a_buffer->pcm_data == NULL) {
4283 LOGE("failed to alloc data.");
4287 memcpy(a_buffer->pcm_data, a_data, a_size);
4288 /* LOGD("new [%lld] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4289 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4291 /* If sync is TRUE, send data directly. */
4292 a_buffer->pcm_data = a_data;
4293 __mmplayer_audio_stream_send_data(player, a_buffer);
4298 gst_buffer_unmap(buffer, &mapinfo);
4303 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4305 mm_player_t* player = (mm_player_t*)data;
4306 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4307 GstPad* sinkpad = NULL;
4308 GstElement *queue = NULL, *sink = NULL;
4311 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4313 queue = gst_element_factory_make("queue", NULL);
4314 if (queue == NULL) {
4315 LOGD("fail make queue\n");
4319 sink = gst_element_factory_make("fakesink", NULL);
4321 LOGD("fail make fakesink\n");
4325 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4327 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4328 LOGW("failed to link queue & sink\n");
4332 sinkpad = gst_element_get_static_pad(queue, "sink");
4334 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4335 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4339 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4341 gst_object_unref(sinkpad);
4342 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4343 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4345 gst_element_set_state(sink, GST_STATE_PAUSED);
4346 gst_element_set_state(queue, GST_STATE_PAUSED);
4348 MMPLAYER_SIGNAL_CONNECT(player,
4350 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4352 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4359 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4361 gst_object_unref(GST_OBJECT(queue));
4365 gst_object_unref(GST_OBJECT(sink));
4369 gst_object_unref(GST_OBJECT(sinkpad));
4376 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4378 #define MAX_PROPS_LEN 128
4379 gint latency_mode = 0;
4380 gchar *stream_type = NULL;
4381 gchar *latency = NULL;
4383 gchar stream_props[MAX_PROPS_LEN] = {0,};
4384 GstStructure *props = NULL;
4387 * It should be set after player creation through attribute.
4388 * But, it can not be changed during playing.
4391 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4392 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4395 LOGE("stream_type is null.\n");
4397 if (player->sound.focus_id)
4398 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4399 stream_type, stream_id, player->sound.focus_id);
4401 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4402 stream_type, stream_id);
4403 props = gst_structure_from_string(stream_props, NULL);
4404 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4405 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4406 stream_type, stream_id, player->sound.focus_id, stream_props);
4407 gst_structure_free(props);
4410 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4412 switch (latency_mode) {
4413 case AUDIO_LATENCY_MODE_LOW:
4414 latency = g_strndup("low", 3);
4416 case AUDIO_LATENCY_MODE_MID:
4417 latency = g_strndup("mid", 3);
4419 case AUDIO_LATENCY_MODE_HIGH:
4420 latency = g_strndup("high", 4);
4424 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4428 LOGD("audiosink property - latency=%s \n", latency);
4436 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4438 MMPlayerGstElement* first_element = NULL;
4439 MMPlayerGstElement* audiobin = NULL;
4440 MMHandleType attrs = 0;
4442 GstPad *ghostpad = NULL;
4443 GList* element_bucket = NULL;
4444 gboolean link_audio_sink_now = TRUE;
4450 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4453 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4455 LOGE("failed to allocate memory for audiobin\n");
4456 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4459 attrs = MMPLAYER_GET_ATTRS(player);
4462 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4463 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4464 if (!audiobin[MMPLAYER_A_BIN].gst) {
4465 LOGE("failed to create audiobin\n");
4470 player->pipeline->audiobin = audiobin;
4472 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4474 /* Adding audiotp plugin for reverse trickplay feature */
4475 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4478 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4480 /* replaygain volume */
4481 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4482 if (player->sound.rg_enable)
4483 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4485 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4488 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4490 if (player->set_mode.pcm_extraction) {
4491 // pcm extraction only and no sound output
4492 if (player->audio_stream_render_cb_ex) {
4493 char *caps_str = NULL;
4494 GstCaps* caps = NULL;
4495 gchar *format = NULL;
4498 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4500 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4502 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4504 caps = gst_caps_new_simple("audio/x-raw",
4505 "format", G_TYPE_STRING, format,
4506 "rate", G_TYPE_INT, player->pcm_samplerate,
4507 "channels", G_TYPE_INT, player->pcm_channel,
4509 caps_str = gst_caps_to_string(caps);
4510 LOGD("new caps : %s\n", caps_str);
4512 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4515 gst_caps_unref(caps);
4516 MMPLAYER_FREEIF(caps_str);
4518 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4520 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4521 /* raw pad handling signal */
4522 MMPLAYER_SIGNAL_CONNECT(player,
4523 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4524 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4525 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4527 int dst_samplerate = 0;
4528 int dst_channels = 0;
4530 char *caps_str = NULL;
4531 GstCaps* caps = NULL;
4533 /* get conf. values */
4534 mm_attrs_multiple_get(player->attrs,
4536 "pcm_extraction_samplerate", &dst_samplerate,
4537 "pcm_extraction_channels", &dst_channels,
4538 "pcm_extraction_depth", &dst_depth,
4542 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4543 caps = gst_caps_new_simple("audio/x-raw",
4544 "rate", G_TYPE_INT, dst_samplerate,
4545 "channels", G_TYPE_INT, dst_channels,
4546 "depth", G_TYPE_INT, dst_depth,
4548 caps_str = gst_caps_to_string(caps);
4549 LOGD("new caps : %s\n", caps_str);
4551 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4554 gst_caps_unref(caps);
4555 MMPLAYER_FREEIF(caps_str);
4558 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4561 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4565 //GstCaps* caps = NULL;
4568 /* for logical volume control */
4569 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4570 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4572 if (player->sound.mute) {
4573 LOGD("mute enabled\n");
4574 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4579 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4580 caps = gst_caps_from_string("audio/x-raw-int, "
4581 "endianness = (int) LITTLE_ENDIAN, "
4582 "signed = (boolean) true, "
4583 "width = (int) 16, "
4584 "depth = (int) 16");
4585 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4586 gst_caps_unref(caps);
4589 /* check if multi-channels */
4590 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4591 GstPad *srcpad = NULL;
4592 GstCaps *caps = NULL;
4594 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4595 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4596 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4597 GstStructure *str = gst_caps_get_structure(caps, 0);
4599 gst_structure_get_int(str, "channels", &channels);
4600 gst_caps_unref(caps);
4602 gst_object_unref(srcpad);
4606 /* audio effect element. if audio effect is enabled */
4607 if ((strcmp(player->ini.audioeffect_element, ""))
4609 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4610 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4612 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4614 if ((!player->bypass_audio_effect)
4615 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4616 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4617 if (!_mmplayer_audio_effect_custom_apply(player))
4618 LOGI("apply audio effect(custom) setting success\n");
4622 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4623 && (player->set_mode.rich_audio))
4624 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4627 /* create audio sink */
4628 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4629 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4630 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4632 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4633 if (player->is_360_feature_enabled &&
4634 player->is_content_spherical &&
4636 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4637 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4638 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4640 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4644 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4645 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4647 gst_caps_unref(acaps);
4649 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4650 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4651 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4652 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4654 player->is_openal_plugin_used = TRUE;
4656 if (player->video360_yaw_radians <= M_PI &&
4657 player->video360_yaw_radians >= -M_PI &&
4658 player->video360_pitch_radians <= M_PI_2 &&
4659 player->video360_pitch_radians >= -M_PI_2) {
4660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4661 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4662 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4663 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4664 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4665 "source-orientation-y", player->video360_metadata.init_view_heading,
4666 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4669 if (player->is_360_feature_enabled && player->is_content_spherical)
4670 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4676 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4679 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4680 (player->videodec_linked && player->ini.use_system_clock)) {
4681 LOGD("system clock will be used.\n");
4682 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4685 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4686 __mmplayer_gst_set_audiosink_property(player, attrs);
4689 if (audiobin[MMPLAYER_A_SINK].gst) {
4690 GstPad *sink_pad = NULL;
4691 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4692 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4693 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4694 gst_object_unref(GST_OBJECT(sink_pad));
4697 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4699 /* adding created elements to bin */
4700 LOGD("adding created elements to bin\n");
4701 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4702 LOGE("failed to add elements\n");
4706 /* linking elements in the bucket by added order. */
4707 LOGD("Linking elements in the bucket by added order.\n");
4708 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4709 LOGE("failed to link elements\n");
4713 /* get first element's sinkpad for creating ghostpad */
4714 first_element = (MMPlayerGstElement *)element_bucket->data;
4715 if (!first_element) {
4716 LOGE("failed to get first elem\n");
4720 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4722 LOGE("failed to get pad from first element of audiobin\n");
4726 ghostpad = gst_ghost_pad_new("sink", pad);
4728 LOGE("failed to create ghostpad\n");
4732 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4733 LOGE("failed to add ghostpad to audiobin\n");
4737 gst_object_unref(pad);
4739 g_list_free(element_bucket);
4742 return MM_ERROR_NONE;
4746 LOGD("ERROR : releasing audiobin\n");
4749 gst_object_unref(GST_OBJECT(pad));
4752 gst_object_unref(GST_OBJECT(ghostpad));
4755 g_list_free(element_bucket);
4757 /* release element which are not added to bin */
4758 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4759 /* NOTE : skip bin */
4760 if (audiobin[i].gst) {
4761 GstObject* parent = NULL;
4762 parent = gst_element_get_parent(audiobin[i].gst);
4765 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4766 audiobin[i].gst = NULL;
4768 gst_object_unref(GST_OBJECT(parent));
4772 /* release audiobin with it's childs */
4773 if (audiobin[MMPLAYER_A_BIN].gst)
4774 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4776 MMPLAYER_FREEIF(audiobin);
4778 player->pipeline->audiobin = NULL;
4780 return MM_ERROR_PLAYER_INTERNAL;
4783 static GstPadProbeReturn
4784 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4786 mm_player_t* player = (mm_player_t*) u_data;
4787 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4788 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4790 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4792 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4793 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4795 return GST_PAD_PROBE_OK;
4798 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4800 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4803 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4805 int ret = MM_ERROR_NONE;
4807 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4808 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4810 MMPLAYER_VIDEO_BO_LOCK(player);
4812 if (player->video_bo_list) {
4813 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4814 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4815 if (tmp && tmp->bo == bo) {
4817 LOGD("release bo %p", bo);
4818 tbm_bo_unref(tmp->bo);
4819 MMPLAYER_VIDEO_BO_UNLOCK(player);
4820 MMPLAYER_VIDEO_BO_SIGNAL(player);
4825 /* hw codec is running or the list was reset for DRC. */
4826 LOGW("there is no bo list.");
4828 MMPLAYER_VIDEO_BO_UNLOCK(player);
4830 LOGW("failed to find bo %p", bo);
4835 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4840 MMPLAYER_RETURN_IF_FAIL(player);
4842 MMPLAYER_VIDEO_BO_LOCK(player);
4843 if (player->video_bo_list) {
4844 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4845 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4846 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4849 tbm_bo_unref(tmp->bo);
4853 g_list_free(player->video_bo_list);
4854 player->video_bo_list = NULL;
4856 player->video_bo_size = 0;
4857 MMPLAYER_VIDEO_BO_UNLOCK(player);
4864 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4867 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4868 gboolean ret = TRUE;
4870 /* check DRC, if it is, destroy the prev bo list to create again */
4871 if (player->video_bo_size != size) {
4872 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4873 __mmplayer_video_stream_destroy_bo_list(player);
4874 player->video_bo_size = size;
4877 MMPLAYER_VIDEO_BO_LOCK(player);
4879 if ((!player->video_bo_list) ||
4880 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4882 /* create bo list */
4884 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4886 if (player->video_bo_list) {
4887 /* if bo list did not created all, try it again. */
4888 idx = g_list_length(player->video_bo_list);
4889 LOGD("bo list exist(len: %d)", idx);
4892 for (; idx < player->ini.num_of_video_bo; idx++) {
4893 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4895 LOGE("Fail to alloc bo_info.");
4898 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4900 LOGE("Fail to tbm_bo_alloc.");
4904 bo_info->using = FALSE;
4905 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4908 /* update video num buffers */
4909 player->video_num_buffers = idx;
4910 if (idx == player->ini.num_of_video_bo)
4911 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4914 MMPLAYER_VIDEO_BO_UNLOCK(player);
4918 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4922 /* get bo from list*/
4923 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4924 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4925 if (tmp && (tmp->using == FALSE)) {
4926 LOGD("found bo %p to use", tmp->bo);
4928 MMPLAYER_VIDEO_BO_UNLOCK(player);
4929 return tbm_bo_ref(tmp->bo);
4933 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4934 MMPLAYER_VIDEO_BO_UNLOCK(player);
4938 if (player->ini.video_bo_timeout <= 0) {
4939 MMPLAYER_VIDEO_BO_WAIT(player);
4941 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4942 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4949 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4951 mm_player_t* player = (mm_player_t*)data;
4953 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4955 /* send prerolled pkt */
4956 player->video_stream_prerolled = FALSE;
4958 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4960 /* not to send prerolled pkt again */
4961 player->video_stream_prerolled = TRUE;
4965 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4967 mm_player_t* player = (mm_player_t*)data;
4968 GstCaps *caps = NULL;
4969 MMPlayerVideoStreamDataType *stream = NULL;
4970 MMVideoBuffer *video_buffer = NULL;
4971 GstMemory *dataBlock = NULL;
4972 GstMemory *metaBlock = NULL;
4973 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4974 GstStructure *structure = NULL;
4975 const gchar *string_format = NULL;
4976 unsigned int fourcc = 0;
4979 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4981 if (player->video_stream_prerolled) {
4982 player->video_stream_prerolled = FALSE;
4983 LOGD("skip the prerolled pkt not to send it again");
4987 caps = gst_pad_get_current_caps(pad);
4989 LOGE("Caps is NULL.");
4993 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4995 /* clear stream data structure */
4996 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4998 LOGE("failed to alloc mem for video data");
5002 structure = gst_caps_get_structure(caps, 0);
5003 gst_structure_get_int(structure, "width", &(stream->width));
5004 gst_structure_get_int(structure, "height", &(stream->height));
5005 string_format = gst_structure_get_string(structure, "format");
5007 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5008 stream->format = util_get_pixtype(fourcc);
5009 gst_caps_unref(caps);
5013 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5014 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5017 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5018 LOGE("Wrong condition!!");
5022 /* set size and timestamp */
5023 dataBlock = gst_buffer_peek_memory(buffer, 0);
5024 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5025 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano sec -> mili sec */
5027 /* check zero-copy */
5028 if (player->set_mode.video_zc &&
5029 player->set_mode.media_packet_video_stream &&
5030 gst_buffer_n_memory(buffer) > 1) {
5031 metaBlock = gst_buffer_peek_memory(buffer, 1);
5032 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5033 video_buffer = (MMVideoBuffer *)mapinfo.data;
5036 if (video_buffer) { /* hw codec */
5038 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5041 /* copy pointer of tbm bo, stride, elevation */
5042 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5043 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5047 LOGE("Not support video buffer format");
5050 memcpy(stream->stride, video_buffer->stride_width,
5051 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5052 memcpy(stream->elevation, video_buffer->stride_height,
5053 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5055 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5056 stream->internal_buffer = gst_buffer_ref(buffer);
5057 } else { /* sw codec */
5061 int ret = TBM_SURFACE_ERROR_NONE;
5062 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5063 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5065 unsigned char *src = NULL;
5066 unsigned char *dest = NULL;
5067 tbm_bo_handle thandle;
5068 tbm_surface_h surface;
5069 tbm_surface_info_s info;
5072 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5074 LOGE("fail to gst_memory_map");
5079 if (stream->format == MM_PIXEL_FORMAT_I420) {
5080 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5082 ret = tbm_surface_get_info(surface, &info);
5084 if (ret != TBM_SURFACE_ERROR_NONE) {
5085 tbm_surface_destroy(surface);
5088 tbm_surface_destroy(surface);
5090 src_stride[0] = GST_ROUND_UP_4(stream->width);
5091 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5092 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5093 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5094 stream->stride[0] = info.planes[0].stride;
5095 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5096 stream->stride[1] = info.planes[1].stride;
5097 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5098 stream->stride[2] = info.planes[2].stride;
5099 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5100 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5101 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5102 stream->stride[0] = stream->width * 4;
5103 stream->elevation[0] = stream->height;
5104 size = stream->stride[0] * stream->height;
5106 LOGE("Not support format %d", stream->format);
5110 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5111 if (!stream->bo[0]) {
5112 LOGE("Fail to tbm_bo_alloc!!");
5116 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5117 if (thandle.ptr && mapinfo.data) {
5118 if (stream->format == MM_PIXEL_FORMAT_I420) {
5119 for (i = 0; i < 3; i++) {
5120 src = mapinfo.data + src_offset[i];
5121 dest = thandle.ptr + info.planes[i].offset;
5124 for (j = 0; j < stream->height>>k; j++) {
5125 memcpy(dest, src, stream->width>>k);
5126 src += src_stride[i];
5127 dest += stream->stride[i];
5130 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5131 memcpy(thandle.ptr, mapinfo.data, size);
5133 LOGE("Not support format %d", stream->format);
5137 LOGE("data pointer is wrong. dest : %p, src : %p",
5138 thandle.ptr, mapinfo.data);
5141 tbm_bo_unmap(stream->bo[0]);
5144 if (player->video_stream_cb) { /* This has been already checked at the entry */
5145 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5146 LOGE("failed to send video stream data.");
5152 gst_memory_unmap(metaBlock, &mapinfo);
5154 gst_memory_unmap(dataBlock, &mapinfo);
5159 LOGE("release video stream resource.");
5162 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5164 tbm_bo_unref(stream->bo[i]);
5166 gst_memory_unmap(metaBlock, &mapinfo);
5168 /* unref gst buffer */
5169 if (stream->internal_buffer)
5170 gst_buffer_unref(stream->internal_buffer);
5171 } else if (dataBlock) {
5173 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5174 gst_memory_unmap(dataBlock, &mapinfo);
5182 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5184 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5185 GList* element_bucket = NULL;
5187 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5191 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5192 LOGD("do not need to add video filters.");
5193 return MM_ERROR_NONE;
5196 /* in case of sw codec except 360 playback,
5197 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5198 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5199 LOGD("using video converter: %s", video_csc);
5201 /* set video rotator */
5202 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5204 *bucket = element_bucket;
5206 return MM_ERROR_NONE;
5208 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5209 g_list_free(element_bucket);
5213 return MM_ERROR_PLAYER_INTERNAL;
5217 * This function is to create video pipeline.
5219 * @param player [in] handle of player
5220 * caps [in] src caps of decoder
5221 * surface_type [in] surface type for video rendering
5223 * @return This function returns zero on success.
5225 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5229 * - video overlay surface(arm/x86) : tizenwlsink
5232 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5236 GList*element_bucket = NULL;
5237 MMPlayerGstElement* first_element = NULL;
5238 MMPlayerGstElement* videobin = NULL;
5239 gchar *videosink_element = NULL;
5243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5246 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5248 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5250 player->pipeline->videobin = videobin;
5252 attrs = MMPLAYER_GET_ATTRS(player);
5254 LOGE("cannot get content attribute");
5255 return MM_ERROR_PLAYER_INTERNAL;
5259 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5260 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5261 if (!videobin[MMPLAYER_V_BIN].gst) {
5262 LOGE("failed to create videobin");
5266 int enable_video_decoded_cb = 0;
5267 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5269 if (player->is_360_feature_enabled && player->is_content_spherical) {
5270 LOGD("video360 elem will be added.");
5272 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5273 "video-360", TRUE, player);
5275 /* Set spatial media metadata and/or user settings to the element.
5277 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5278 "projection-type", player->video360_metadata.projection_type, NULL);
5280 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5281 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5283 if (player->video360_metadata.full_pano_width_pixels &&
5284 player->video360_metadata.full_pano_height_pixels &&
5285 player->video360_metadata.cropped_area_image_width &&
5286 player->video360_metadata.cropped_area_image_height) {
5287 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5288 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5289 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5290 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5291 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5292 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5293 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5297 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5298 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5299 "horizontal-fov", player->video360_horizontal_fov,
5300 "vertical-fov", player->video360_vertical_fov, NULL);
5303 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5304 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5305 "zoom", 1.0f / player->video360_zoom, NULL);
5308 if (player->video360_yaw_radians <= M_PI &&
5309 player->video360_yaw_radians >= -M_PI &&
5310 player->video360_pitch_radians <= M_PI_2 &&
5311 player->video360_pitch_radians >= -M_PI_2) {
5312 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5313 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5314 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5315 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5316 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5317 "pose-yaw", player->video360_metadata.init_view_heading,
5318 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5322 "passthrough", !player->is_video360_enabled, NULL);
5325 /* set video sink */
5326 switch (surface_type) {
5327 case MM_DISPLAY_SURFACE_OVERLAY:
5328 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5330 if (strlen(player->ini.videosink_element_overlay) > 0)
5331 videosink_element = player->ini.videosink_element_overlay;
5335 case MM_DISPLAY_SURFACE_NULL:
5336 if (strlen(player->ini.videosink_element_fake) > 0)
5337 videosink_element = player->ini.videosink_element_fake;
5341 case MM_DISPLAY_SURFACE_REMOTE:
5342 if (strlen(player->ini.videosink_element_fake) > 0)
5343 videosink_element = player->ini.videosink_element_fake;
5348 LOGE("unidentified surface type");
5351 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5353 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5355 /* additional setting for sink plug-in */
5356 switch (surface_type) {
5357 case MM_DISPLAY_SURFACE_OVERLAY:
5359 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5361 LOGD("selected videosink name: %s", videosink_element);
5363 /* support shard memory with S/W codec on HawkP */
5364 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5365 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5366 "use-tbm", use_tbm, NULL);
5372 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5375 LOGD("disable last-sample");
5376 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5380 if (player->set_mode.media_packet_video_stream) {
5382 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5384 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5386 MMPLAYER_SIGNAL_CONNECT(player,
5387 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5388 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5390 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5393 MMPLAYER_SIGNAL_CONNECT(player,
5394 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5395 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5397 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5402 case MM_DISPLAY_SURFACE_REMOTE:
5404 if (player->set_mode.media_packet_video_stream) {
5405 LOGE("add data probe at videosink");
5406 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5407 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5409 MMPLAYER_SIGNAL_CONNECT(player,
5410 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5411 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5413 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5416 MMPLAYER_SIGNAL_CONNECT(player,
5417 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5418 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5420 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5425 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5428 LOGD("disable last-sample");
5429 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5439 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5442 if (videobin[MMPLAYER_V_SINK].gst) {
5443 GstPad *sink_pad = NULL;
5444 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5446 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5447 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5448 gst_object_unref(GST_OBJECT(sink_pad));
5450 LOGW("failed to get sink pad from videosink\n");
5453 /* store it as it's sink element */
5454 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5456 /* adding created elements to bin */
5457 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5458 LOGE("failed to add elements\n");
5462 /* Linking elements in the bucket by added order */
5463 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5464 LOGE("failed to link elements\n");
5468 /* get first element's sinkpad for creating ghostpad */
5470 first_element = (MMPlayerGstElement *)element_bucket->data;
5471 if (!first_element) {
5472 LOGE("failed to get first element from bucket\n");
5476 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5478 LOGE("failed to get pad from first element\n");
5482 /* create ghostpad */
5483 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5484 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5485 LOGE("failed to add ghostpad to videobin\n");
5488 gst_object_unref(pad);
5490 /* done. free allocated variables */
5492 g_list_free(element_bucket);
5496 return MM_ERROR_NONE;
5499 LOGE("ERROR : releasing videobin\n");
5501 g_list_free(element_bucket);
5504 gst_object_unref(GST_OBJECT(pad));
5506 /* release videobin with it's childs */
5507 if (videobin[MMPLAYER_V_BIN].gst)
5508 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5511 MMPLAYER_FREEIF(videobin);
5513 player->pipeline->videobin = NULL;
5515 return MM_ERROR_PLAYER_INTERNAL;
5518 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5520 GList *element_bucket = NULL;
5521 MMPlayerGstElement *textbin = player->pipeline->textbin;
5523 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5524 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5525 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5526 "signal-handoffs", FALSE,
5529 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5530 MMPLAYER_SIGNAL_CONNECT(player,
5531 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5532 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5534 G_CALLBACK(__mmplayer_update_subtitle),
5537 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5538 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5539 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5541 if (!player->play_subtitle) {
5542 LOGD("add textbin sink as sink element of whole pipeline.\n");
5543 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5546 /* adding created elements to bin */
5547 LOGD("adding created elements to bin\n");
5548 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5549 LOGE("failed to add elements\n");
5553 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5554 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5555 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5557 /* linking elements in the bucket by added order. */
5558 LOGD("Linking elements in the bucket by added order.\n");
5559 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5560 LOGE("failed to link elements\n");
5564 /* done. free allocated variables */
5565 g_list_free(element_bucket);
5567 if (textbin[MMPLAYER_T_QUEUE].gst) {
5569 GstPad *ghostpad = NULL;
5571 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5573 LOGE("failed to get sink pad of text queue");
5577 ghostpad = gst_ghost_pad_new("text_sink", pad);
5578 gst_object_unref(pad);
5581 LOGE("failed to create ghostpad of textbin\n");
5585 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5586 LOGE("failed to add ghostpad to textbin\n");
5587 gst_object_unref(ghostpad);
5592 return MM_ERROR_NONE;
5595 g_list_free(element_bucket);
5597 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5598 LOGE("remove textbin sink from sink list");
5599 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5602 /* release element at __mmplayer_gst_create_text_sink_bin */
5603 return MM_ERROR_PLAYER_INTERNAL;
5606 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5608 MMPlayerGstElement *textbin = NULL;
5609 GList *element_bucket = NULL;
5610 int surface_type = 0;
5615 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5618 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5620 LOGE("failed to allocate memory for textbin\n");
5621 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5625 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5626 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5627 if (!textbin[MMPLAYER_T_BIN].gst) {
5628 LOGE("failed to create textbin\n");
5633 player->pipeline->textbin = textbin;
5636 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5637 LOGD("surface type for subtitle : %d", surface_type);
5638 switch (surface_type) {
5639 case MM_DISPLAY_SURFACE_OVERLAY:
5640 case MM_DISPLAY_SURFACE_NULL:
5641 case MM_DISPLAY_SURFACE_REMOTE:
5642 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5643 LOGE("failed to make plain text elements\n");
5654 return MM_ERROR_NONE;
5658 LOGD("ERROR : releasing textbin\n");
5660 g_list_free(element_bucket);
5662 /* release signal */
5663 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5665 /* release element which are not added to bin */
5666 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5667 /* NOTE : skip bin */
5668 if (textbin[i].gst) {
5669 GstObject* parent = NULL;
5670 parent = gst_element_get_parent(textbin[i].gst);
5673 gst_object_unref(GST_OBJECT(textbin[i].gst));
5674 textbin[i].gst = NULL;
5676 gst_object_unref(GST_OBJECT(parent));
5681 /* release textbin with it's childs */
5682 if (textbin[MMPLAYER_T_BIN].gst)
5683 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5685 MMPLAYER_FREEIF(player->pipeline->textbin);
5686 player->pipeline->textbin = NULL;
5689 return MM_ERROR_PLAYER_INTERNAL;
5694 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5696 MMPlayerGstElement* mainbin = NULL;
5697 MMPlayerGstElement* textbin = NULL;
5698 MMHandleType attrs = 0;
5699 GstElement *subsrc = NULL;
5700 GstElement *subparse = NULL;
5701 gchar *subtitle_uri = NULL;
5702 const gchar *charset = NULL;
5708 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5710 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712 mainbin = player->pipeline->mainbin;
5714 attrs = MMPLAYER_GET_ATTRS(player);
5716 LOGE("cannot get content attribute\n");
5717 return MM_ERROR_PLAYER_INTERNAL;
5720 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5721 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5722 LOGE("subtitle uri is not proper filepath.\n");
5723 return MM_ERROR_PLAYER_INVALID_URI;
5726 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5727 LOGE("failed to get storage info of subtitle path");
5728 return MM_ERROR_PLAYER_INVALID_URI;
5731 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5733 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5734 player->subtitle_language_list = NULL;
5735 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5737 /* create the subtitle source */
5738 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5740 LOGE("failed to create filesrc element\n");
5743 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5745 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5746 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5748 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5749 LOGW("failed to add queue\n");
5750 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5751 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5752 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5757 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5759 LOGE("failed to create subparse element\n");
5763 charset = util_get_charset(subtitle_uri);
5765 LOGD("detected charset is %s\n", charset);
5766 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5769 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5770 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5772 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5773 LOGW("failed to add subparse\n");
5774 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5775 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5776 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5780 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5781 LOGW("failed to link subsrc and subparse\n");
5785 player->play_subtitle = TRUE;
5786 player->adjust_subtitle_pos = 0;
5788 LOGD("play subtitle using subtitle file\n");
5790 if (player->pipeline->textbin == NULL) {
5791 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5792 LOGE("failed to create text sink bin. continuing without text\n");
5796 textbin = player->pipeline->textbin;
5798 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5799 LOGW("failed to add textbin\n");
5801 /* release signal */
5802 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5804 /* release textbin with it's childs */
5805 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5806 MMPLAYER_FREEIF(player->pipeline->textbin);
5807 player->pipeline->textbin = textbin = NULL;
5811 LOGD("link text input selector and textbin ghost pad");
5813 player->textsink_linked = 1;
5814 player->external_text_idx = 0;
5815 LOGI("player->textsink_linked set to 1\n");
5817 textbin = player->pipeline->textbin;
5818 LOGD("text bin has been created. reuse it.");
5819 player->external_text_idx = 1;
5822 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5823 LOGW("failed to link subparse and textbin\n");
5827 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5829 LOGE("failed to get sink pad from textsink to probe data");
5833 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5834 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5836 gst_object_unref(pad);
5839 /* create dot. for debugging */
5840 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5843 return MM_ERROR_NONE;
5846 /* release text pipeline resource */
5847 player->textsink_linked = 0;
5849 /* release signal */
5850 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5852 if (player->pipeline->textbin) {
5853 LOGE("remove textbin");
5855 /* release textbin with it's childs */
5856 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5857 MMPLAYER_FREEIF(player->pipeline->textbin);
5858 player->pipeline->textbin = NULL;
5862 /* release subtitle elem */
5863 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5864 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5866 return MM_ERROR_PLAYER_INTERNAL;
5870 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5872 mm_player_t* player = (mm_player_t*) data;
5873 MMMessageParamType msg = {0, };
5874 GstClockTime duration = 0;
5875 gpointer text = NULL;
5876 guint text_size = 0;
5877 gboolean ret = TRUE;
5878 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5882 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5883 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5885 if (player->is_subtitle_force_drop) {
5886 LOGW("subtitle is dropped forcedly.");
5890 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5891 text = mapinfo.data;
5892 text_size = mapinfo.size;
5893 duration = GST_BUFFER_DURATION(buffer);
5895 if (player->set_mode.subtitle_off) {
5896 LOGD("subtitle is OFF.\n");
5900 if (!text || (text_size == 0)) {
5901 LOGD("There is no subtitle to be displayed.\n");
5905 msg.data = (void *) text;
5906 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5908 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5910 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5911 gst_buffer_unmap(buffer, &mapinfo);
5918 static GstPadProbeReturn
5919 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5921 mm_player_t *player = (mm_player_t *) u_data;
5922 GstClockTime cur_timestamp = 0;
5923 gint64 adjusted_timestamp = 0;
5924 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5926 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5928 if (player->set_mode.subtitle_off) {
5929 LOGD("subtitle is OFF.\n");
5933 if (player->adjust_subtitle_pos == 0) {
5934 LOGD("nothing to do");
5938 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5939 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5941 if (adjusted_timestamp < 0) {
5942 LOGD("adjusted_timestamp under zero");
5947 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5948 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5949 GST_TIME_ARGS(cur_timestamp),
5950 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5952 return GST_PAD_PROBE_OK;
5954 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5958 /* check player and subtitlebin are created */
5959 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5960 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5962 if (position == 0) {
5963 LOGD("nothing to do\n");
5965 return MM_ERROR_NONE;
5969 case MM_PLAYER_POS_FORMAT_TIME:
5971 /* check current postion */
5972 player->adjust_subtitle_pos = position;
5974 LOGD("save adjust_subtitle_pos in player") ;
5980 LOGW("invalid format.\n");
5982 return MM_ERROR_INVALID_ARGUMENT;
5988 return MM_ERROR_NONE;
5990 static int __gst_adjust_video_position(mm_player_t* player, int offset)
5993 LOGD("adjusting video_pos in player") ;
5994 int current_pos = 0;
5995 /* check player and videobin are created */
5996 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5997 if (!player->pipeline->videobin ||
5998 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
5999 LOGD("no video pipeline or sink is there");
6000 return MM_ERROR_PLAYER_INVALID_STATE ;
6003 LOGD("nothing to do\n");
6005 return MM_ERROR_NONE;
6007 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, (unsigned long*)¤t_pos) != MM_ERROR_NONE) {
6008 LOGD("failed to get current position");
6009 return MM_ERROR_PLAYER_INTERNAL;
6011 if ((current_pos - offset) < GST_TIME_AS_MSECONDS(player->duration)) {
6012 LOGD("enter video delay is valid");
6014 LOGD("enter video delay is crossing content boundary");
6015 return MM_ERROR_INVALID_ARGUMENT ;
6017 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "ts-offset", ((gint64) offset * G_GINT64_CONSTANT(1000000)), NULL);
6018 LOGD("video delay has been done");
6021 return MM_ERROR_NONE;
6025 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6027 GstElement *appsrc = element;
6028 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6029 GstBuffer *buffer = NULL;
6030 GstFlowReturn ret = GST_FLOW_OK;
6033 MMPLAYER_RETURN_IF_FAIL(element);
6034 MMPLAYER_RETURN_IF_FAIL(buf);
6036 buffer = gst_buffer_new();
6038 if (buf->offset >= buf->len) {
6039 LOGD("call eos appsrc\n");
6040 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6044 if (buf->len - buf->offset < size)
6045 len = buf->len - buf->offset;
6047 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6048 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6049 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6051 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6052 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6058 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6060 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6062 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6064 buf->offset = (int)size;
6069 static GstBusSyncReply
6070 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6072 mm_player_t *player = (mm_player_t *)data;
6073 GstBusSyncReply reply = GST_BUS_DROP;
6075 if (!(player->pipeline && player->pipeline->mainbin)) {
6076 LOGE("player pipeline handle is null");
6077 return GST_BUS_PASS;
6080 if (!__mmplayer_check_useful_message(player, message)) {
6081 gst_message_unref(message);
6082 return GST_BUS_DROP;
6085 switch (GST_MESSAGE_TYPE(message)) {
6086 case GST_MESSAGE_STATE_CHANGED:
6087 /* post directly for fast launch */
6088 if (player->sync_handler) {
6089 __mmplayer_gst_callback(message, player);
6090 reply = GST_BUS_DROP;
6092 reply = GST_BUS_PASS;
6094 case GST_MESSAGE_TAG:
6095 __mmplayer_gst_extract_tag_from_msg(player, message);
6099 GstTagList *tags = NULL;
6101 gst_message_parse_tag(message, &tags);
6103 LOGE("TAGS received from element \"%s\".\n",
6104 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6106 gst_tag_list_foreach(tags, print_tag, NULL);
6107 gst_tag_list_free(tags);
6115 case GST_MESSAGE_DURATION_CHANGED:
6116 __mmplayer_gst_handle_duration(player, message);
6118 case GST_MESSAGE_ASYNC_DONE:
6119 /* NOTE:Don't call gst_callback directly
6120 * because previous frame can be showed even though this message is received for seek.
6123 reply = GST_BUS_PASS;
6127 if (reply == GST_BUS_DROP)
6128 gst_message_unref(message);
6134 __mmplayer_gst_create_decoder(mm_player_t *player,
6135 MMPlayerTrackType track,
6137 enum MainElementID elemId,
6140 gboolean ret = TRUE;
6141 GstPad *sinkpad = NULL;
6145 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6147 player->pipeline->mainbin, FALSE);
6148 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6149 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6150 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6152 GstElement *decodebin = NULL;
6153 GstCaps *dec_caps = NULL;
6155 /* create decodebin */
6156 decodebin = gst_element_factory_make("decodebin", name);
6159 LOGE("error : fail to create decodebin for %d decoder\n", track);
6164 /* raw pad handling signal */
6165 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6166 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6168 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6169 before looking for any elements that can handle that stream.*/
6170 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6171 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6173 /* This signal is emitted when a element is added to the bin.*/
6174 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6175 G_CALLBACK(__mmplayer_gst_element_added), player);
6177 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6178 LOGE("failed to add new decodebin\n");
6183 dec_caps = gst_pad_query_caps(srcpad, NULL);
6185 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6186 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6187 gst_caps_unref(dec_caps);
6190 player->pipeline->mainbin[elemId].id = elemId;
6191 player->pipeline->mainbin[elemId].gst = decodebin;
6193 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6195 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6196 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6197 gst_object_unref(GST_OBJECT(decodebin));
6200 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6201 LOGE("failed to sync second level decodebin state with parent\n");
6203 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6207 gst_object_unref(GST_OBJECT(sinkpad));
6216 * This function is to create audio or video pipeline for playing.
6218 * @param player [in] handle of player
6220 * @return This function returns zero on success.
6225 __mmplayer_gst_create_pipeline(mm_player_t* player)
6228 MMPlayerGstElement *mainbin = NULL;
6229 MMHandleType attrs = 0;
6230 GstElement* element = NULL;
6231 GstElement* elem_src_audio = NULL;
6232 GstElement* elem_src_subtitle = NULL;
6233 GstElement* es_video_queue = NULL;
6234 GstElement* es_audio_queue = NULL;
6235 GstElement* es_subtitle_queue = NULL;
6236 GList* element_bucket = NULL;
6237 gboolean need_state_holder = TRUE;
6239 #ifdef SW_CODEC_ONLY
6240 int surface_type = 0;
6244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6246 /* get profile attribute */
6247 attrs = MMPLAYER_GET_ATTRS(player);
6249 LOGE("cannot get content attribute\n");
6253 /* create pipeline handles */
6254 if (player->pipeline) {
6255 LOGW("pipeline should be released before create new one\n");
6259 player->video360_metadata.is_spherical = -1;
6260 player->is_openal_plugin_used = FALSE;
6262 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6263 if (player->pipeline == NULL)
6266 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6268 /* create mainbin */
6269 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6270 if (mainbin == NULL)
6273 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6275 /* create pipeline */
6276 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6277 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6278 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6279 LOGE("failed to create pipeline\n");
6282 player->demux_pad_index = 0;
6283 player->subtitle_language_list = NULL;
6285 player->is_subtitle_force_drop = FALSE;
6286 player->last_multiwin_status = FALSE;
6288 _mmplayer_track_initialize(player);
6289 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6291 /* create source element */
6292 switch (player->profile.uri_type) {
6293 /* rtsp streamming */
6294 case MM_PLAYER_URI_TYPE_URL_RTSP:
6298 element = gst_element_factory_make("rtspsrc", "rtsp source");
6301 LOGE("failed to create streaming source element\n");
6309 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6311 SECURE_LOGD("user_agent : %s\n", user_agent);
6313 /* setting property to streaming source */
6314 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6316 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6318 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6319 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6320 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6321 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6326 case MM_PLAYER_URI_TYPE_URL_HTTP:
6328 gchar *user_agent, *cookies, **cookie_list;
6329 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6330 user_agent = cookies = NULL;
6332 gint mode = MM_PLAYER_PD_MODE_NONE;
6334 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6336 player->pd_mode = mode;
6338 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6340 if (!MMPLAYER_IS_HTTP_PD(player)) {
6341 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6343 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6346 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6349 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6350 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6352 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6353 LOGD("get timeout from ini\n");
6354 http_timeout = player->ini.http_timeout;
6358 SECURE_LOGD("location : %s\n", player->profile.uri);
6359 SECURE_LOGD("cookies : %s\n", cookies);
6360 SECURE_LOGD("user_agent : %s\n", user_agent);
6361 LOGD("timeout : %d\n", http_timeout);
6363 /* setting property to streaming source */
6364 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6365 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6366 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6368 /* parsing cookies */
6369 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6370 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6371 g_strfreev(cookie_list);
6374 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6376 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6377 LOGW("it's dash. and it's still experimental feature.");
6379 // progressive download
6380 gchar* location = NULL;
6382 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6385 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6387 MMPLAYER_FREEIF(player->pd_file_save_path);
6389 LOGD("PD Location : %s\n", path);
6392 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6393 LOGE("failed to get storage info");
6396 player->pd_file_save_path = g_strdup(path);
6398 LOGE("can't find pd location so, it should be set \n");
6403 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6405 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6409 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6410 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6412 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6413 g_object_get(element, "location", &location, NULL);
6414 LOGD("PD_LOCATION [%s].\n", location);
6422 case MM_PLAYER_URI_TYPE_FILE:
6424 LOGD("using filesrc for 'file://' handler.\n");
6425 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6426 LOGE("failed to get storage info");
6430 element = gst_element_factory_make("filesrc", "source");
6432 LOGE("failed to create filesrc\n");
6436 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6440 case MM_PLAYER_URI_TYPE_SS:
6442 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6443 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6445 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6449 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6450 LOGD("get timeout from ini\n");
6451 http_timeout = player->ini.http_timeout;
6454 /* setting property to streaming source */
6455 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6456 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6459 case MM_PLAYER_URI_TYPE_MS_BUFF:
6461 LOGD("MS buff src is selected\n");
6463 if (player->v_stream_caps) {
6464 element = gst_element_factory_make("appsrc", "video_appsrc");
6466 LOGF("failed to create video app source element[appsrc].\n");
6470 if (player->a_stream_caps) {
6471 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6472 if (!elem_src_audio) {
6473 LOGF("failed to create audio app source element[appsrc].\n");
6477 } else if (player->a_stream_caps) {
6478 /* no video, only audio pipeline*/
6479 element = gst_element_factory_make("appsrc", "audio_appsrc");
6481 LOGF("failed to create audio app source element[appsrc].\n");
6486 if (player->s_stream_caps) {
6487 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6488 if (!elem_src_subtitle) {
6489 LOGF("failed to create subtitle app source element[appsrc].\n");
6494 LOGD("setting app sources properties.\n");
6495 LOGD("location : %s\n", player->profile.uri);
6497 if (player->v_stream_caps && element) {
6498 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6499 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6500 "caps", player->v_stream_caps, NULL);
6502 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6503 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6504 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6505 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6507 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6508 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6509 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6510 G_CALLBACK(__gst_seek_video_data), player);
6512 if (player->a_stream_caps && elem_src_audio) {
6513 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6514 "caps", player->a_stream_caps, NULL);
6516 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6517 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6518 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6519 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6521 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6522 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6523 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6524 G_CALLBACK(__gst_seek_audio_data), player);
6526 } else if (player->a_stream_caps && element) {
6527 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6528 "caps", player->a_stream_caps, NULL);
6530 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6531 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6532 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6533 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6535 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6536 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6537 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6538 G_CALLBACK(__gst_seek_audio_data), player);
6541 if (player->s_stream_caps && elem_src_subtitle) {
6542 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6543 "caps", player->s_stream_caps, NULL);
6545 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6546 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6547 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6548 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6550 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6552 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6553 G_CALLBACK(__gst_seek_subtitle_data), player);
6556 if (player->v_stream_caps && element) {
6557 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6558 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6559 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6560 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6562 if (player->a_stream_caps && elem_src_audio) {
6563 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6564 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6565 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6566 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6568 } else if (player->a_stream_caps && element) {
6569 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6570 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6571 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6572 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6575 if (player->s_stream_caps && elem_src_subtitle)
6576 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6577 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6579 need_state_holder = FALSE;
6581 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6582 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6583 LOGE("failed to commit\n");
6587 case MM_PLAYER_URI_TYPE_MEM:
6589 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6591 LOGD("mem src is selected\n");
6593 element = gst_element_factory_make("appsrc", "mem-source");
6595 LOGE("failed to create appsrc element\n");
6599 g_object_set(element, "stream-type", stream_type, NULL);
6600 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6601 g_object_set(element, "blocksize", (guint64)20480, NULL);
6603 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6604 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6605 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6606 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6609 case MM_PLAYER_URI_TYPE_URL:
6612 case MM_PLAYER_URI_TYPE_TEMP:
6615 case MM_PLAYER_URI_TYPE_NONE:
6620 /* check source element is OK */
6622 LOGE("no source element was created.\n");
6626 /* take source element */
6627 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6628 mainbin[MMPLAYER_M_SRC].gst = element;
6629 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6631 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6632 player->streamer = __mm_player_streaming_create();
6633 __mm_player_streaming_initialize(player->streamer);
6636 if (MMPLAYER_IS_HTTP_PD(player)) {
6637 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6639 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6640 element = gst_element_factory_make("queue2", "queue2");
6642 LOGE("failed to create http streaming buffer element\n");
6647 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6648 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6649 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6651 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6653 __mm_player_streaming_set_queue2(player->streamer,
6656 player->ini.http_max_size_bytes + 52428800, // http_max_size_types + 5Mb
6659 player->ini.http_buffering_limit,
6660 MUXED_BUFFER_TYPE_MEM_QUEUE,
6664 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6665 if (player->v_stream_caps) {
6666 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6667 if (!es_video_queue) {
6668 LOGE("create es_video_queue for es player failed\n");
6671 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6672 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6673 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6674 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6676 /* Adding audio appsrc to bucket */
6677 if (player->a_stream_caps && elem_src_audio) {
6678 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6679 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6680 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6682 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6683 if (!es_audio_queue) {
6684 LOGE("create es_audio_queue for es player failed\n");
6687 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6689 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6690 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6691 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6693 } else if (player->a_stream_caps) {
6694 /* Only audio stream, no video */
6695 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6696 if (!es_audio_queue) {
6697 LOGE("create es_audio_queue for es player failed\n");
6700 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6701 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6702 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6705 if (player->s_stream_caps && elem_src_subtitle) {
6706 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6707 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6708 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6710 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6711 if (!es_subtitle_queue) {
6712 LOGE("create es_subtitle_queue for es player failed\n");
6715 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6716 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6717 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6721 /* create autoplugging element if src element is not a rtsp src */
6722 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6723 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6725 enum MainElementID elemId = MMPLAYER_M_NUM;
6727 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6728 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6729 elemId = MMPLAYER_M_AUTOPLUG;
6730 element = __mmplayer_create_decodebin(player);
6732 /* default size of mq in decodebin is 2M
6733 * but it can cause blocking issue during seeking depends on content. */
6734 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6736 need_state_holder = FALSE;
6738 elemId = MMPLAYER_M_TYPEFIND;
6739 element = gst_element_factory_make("typefind", "typefinder");
6740 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6741 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6745 /* check autoplug element is OK */
6747 LOGE("can not create element(%d)\n", elemId);
6751 mainbin[elemId].id = elemId;
6752 mainbin[elemId].gst = element;
6754 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6757 /* add elements to pipeline */
6758 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6759 LOGE("Failed to add elements to pipeline\n");
6764 /* linking elements in the bucket by added order. */
6765 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6766 LOGE("Failed to link some elements\n");
6771 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6772 if (need_state_holder) {
6774 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6775 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6777 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6778 LOGE("fakesink element could not be created\n");
6781 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6783 /* take ownership of fakesink. we are reusing it */
6784 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6787 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6788 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6789 LOGE("failed to add fakesink to bin\n");
6794 /* now we have completed mainbin. take it */
6795 player->pipeline->mainbin = mainbin;
6797 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6798 GstPad *srcpad = NULL;
6800 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6801 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6803 __mmplayer_gst_create_decoder(player,
6804 MM_PLAYER_TRACK_TYPE_VIDEO,
6806 MMPLAYER_M_AUTOPLUG_V_DEC,
6809 gst_object_unref(GST_OBJECT(srcpad));
6814 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6815 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6817 __mmplayer_gst_create_decoder(player,
6818 MM_PLAYER_TRACK_TYPE_AUDIO,
6820 MMPLAYER_M_AUTOPLUG_A_DEC,
6823 gst_object_unref(GST_OBJECT(srcpad));
6828 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6829 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6832 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6833 if (__mmplayer_check_subtitle(player)) {
6834 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6835 LOGE("fail to create text pipeline");
6838 /* connect bus callback */
6839 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6841 LOGE("cannot get bus from pipeline.\n");
6845 /* set sync handler to get tag synchronously */
6846 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6849 gst_object_unref(GST_OBJECT(bus));
6850 g_list_free(element_bucket);
6852 /* create gst bus_msb_cb thread */
6853 g_mutex_init(&player->bus_msg_thread_mutex);
6854 g_cond_init(&player->bus_msg_thread_cond);
6855 player->bus_msg_thread_exit = FALSE;
6856 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6857 player->bus_msg_thread =
6858 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6859 if (!player->bus_msg_thread) {
6860 LOGE("failed to create gst BUS msg thread");
6861 g_mutex_clear(&player->bus_msg_thread_mutex);
6862 g_cond_clear(&player->bus_msg_thread_cond);
6868 return MM_ERROR_NONE;
6871 __mmplayer_gst_destroy_pipeline(player);
6872 g_list_free(element_bucket);
6875 /* release element which are not added to bin */
6876 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6877 /* NOTE : skip pipeline */
6878 if (mainbin[i].gst) {
6879 GstObject* parent = NULL;
6880 parent = gst_element_get_parent(mainbin[i].gst);
6883 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6884 mainbin[i].gst = NULL;
6886 gst_object_unref(GST_OBJECT(parent));
6890 /* release pipeline with it's childs */
6891 if (mainbin[MMPLAYER_M_PIPE].gst)
6892 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6894 MMPLAYER_FREEIF(mainbin);
6897 MMPLAYER_FREEIF(player->pipeline);
6898 return MM_ERROR_PLAYER_INTERNAL;
6902 __mmplayer_reset_gapless_state(mm_player_t* player)
6905 MMPLAYER_RETURN_IF_FAIL(player
6907 && player->pipeline->audiobin
6908 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6910 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6917 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6920 int ret = MM_ERROR_NONE;
6924 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6926 /* cleanup stuffs */
6927 MMPLAYER_FREEIF(player->type);
6928 player->have_dynamic_pad = FALSE;
6929 player->no_more_pad = FALSE;
6930 player->num_dynamic_pad = 0;
6931 player->demux_pad_index = 0;
6932 player->use_deinterleave = FALSE;
6933 player->max_audio_channels = 0;
6934 player->video_share_api_delta = 0;
6935 player->video_share_clock_delta = 0;
6936 player->video_hub_download_mode = 0;
6938 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6939 player->subtitle_language_list = NULL;
6940 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6942 __mmplayer_reset_gapless_state(player);
6944 if (player->streamer) {
6945 __mm_player_streaming_deinitialize(player->streamer);
6946 __mm_player_streaming_destroy(player->streamer);
6947 player->streamer = NULL;
6950 /* cleanup unlinked mime type */
6951 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6952 MMPLAYER_FREEIF(player->unlinked_video_mime);
6953 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6955 /* cleanup running stuffs */
6956 __mmplayer_cancel_eos_timer(player);
6958 /* cleanup gst stuffs */
6959 if (player->pipeline) {
6960 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6961 GstTagList* tag_list = player->pipeline->tag_list;
6963 /* first we need to disconnect all signal hander */
6964 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6967 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6968 MMPlayerGstElement* videobin = player->pipeline->videobin;
6969 MMPlayerGstElement* textbin = player->pipeline->textbin;
6970 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6971 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6972 gst_object_unref(bus);
6974 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6975 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6976 if (ret != MM_ERROR_NONE) {
6977 LOGE("fail to change state to NULL\n");
6978 return MM_ERROR_PLAYER_INTERNAL;
6981 LOGW("succeeded in chaning state to NULL\n");
6983 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6986 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
6987 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
6989 /* free avsysaudiosink
6990 avsysaudiosink should be unref when destory pipeline just after start play with BT.
6991 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
6993 MMPLAYER_FREEIF(audiobin);
6994 MMPLAYER_FREEIF(videobin);
6995 MMPLAYER_FREEIF(textbin);
6996 MMPLAYER_FREEIF(mainbin);
7000 gst_tag_list_free(tag_list);
7002 MMPLAYER_FREEIF(player->pipeline);
7004 MMPLAYER_FREEIF(player->album_art);
7006 if (player->v_stream_caps) {
7007 gst_caps_unref(player->v_stream_caps);
7008 player->v_stream_caps = NULL;
7010 if (player->a_stream_caps) {
7011 gst_caps_unref(player->a_stream_caps);
7012 player->a_stream_caps = NULL;
7015 if (player->s_stream_caps) {
7016 gst_caps_unref(player->s_stream_caps);
7017 player->s_stream_caps = NULL;
7019 _mmplayer_track_destroy(player);
7021 if (player->sink_elements)
7022 g_list_free(player->sink_elements);
7023 player->sink_elements = NULL;
7025 if (player->bufmgr) {
7026 tbm_bufmgr_deinit(player->bufmgr);
7027 player->bufmgr = NULL;
7030 LOGW("finished destroy pipeline\n");
7037 static int __gst_realize(mm_player_t* player)
7040 int ret = MM_ERROR_NONE;
7044 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7046 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7048 ret = __mmplayer_gst_create_pipeline(player);
7050 LOGE("failed to create pipeline\n");
7054 /* set pipeline state to READY */
7055 /* NOTE : state change to READY must be performed sync. */
7056 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7057 ret = __mmplayer_gst_set_state(player,
7058 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7060 if (ret != MM_ERROR_NONE) {
7061 /* return error if failed to set state */
7062 LOGE("failed to set READY state");
7066 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7068 /* create dot before error-return. for debugging */
7069 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7076 static int __gst_unrealize(mm_player_t* player)
7078 int ret = MM_ERROR_NONE;
7082 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7084 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7085 MMPLAYER_PRINT_STATE(player);
7087 /* release miscellaneous information */
7088 __mmplayer_release_misc(player);
7090 /* destroy pipeline */
7091 ret = __mmplayer_gst_destroy_pipeline(player);
7092 if (ret != MM_ERROR_NONE) {
7093 LOGE("failed to destory pipeline\n");
7097 /* release miscellaneous information.
7098 these info needs to be released after pipeline is destroyed. */
7099 __mmplayer_release_misc_post(player);
7101 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7108 static int __gst_pending_seek(mm_player_t* player)
7110 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7111 int ret = MM_ERROR_NONE;
7115 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7117 if (!player->pending_seek.is_pending) {
7118 LOGD("pending seek is not reserved. nothing to do.\n");
7122 /* check player state if player could pending seek or not. */
7123 current_state = MMPLAYER_CURRENT_STATE(player);
7125 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7126 LOGW("try to pending seek in %s state, try next time. \n",
7127 MMPLAYER_STATE_GET_NAME(current_state));
7131 LOGD("trying to play from(%lu) pending position\n", player->pending_seek.pos);
7133 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7135 if (MM_ERROR_NONE != ret)
7136 LOGE("failed to seek pending postion. just keep staying current position.\n");
7138 player->pending_seek.is_pending = FALSE;
7145 static int __gst_start(mm_player_t* player)
7147 gboolean sound_extraction = 0;
7148 int ret = MM_ERROR_NONE;
7149 gboolean async = FALSE;
7153 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7155 /* get sound_extraction property */
7156 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7158 /* NOTE : if SetPosition was called before Start. do it now */
7159 /* streaming doesn't support it. so it should be always sync */
7160 /* !!create one more api to check if there is pending seek rather than checking variables */
7161 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7162 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7163 ret = __gst_pause(player, FALSE);
7164 if (ret != MM_ERROR_NONE) {
7165 LOGE("failed to set state to PAUSED for pending seek\n");
7169 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7171 if (sound_extraction) {
7172 LOGD("setting pcm extraction\n");
7174 ret = __mmplayer_set_pcm_extraction(player);
7175 if (MM_ERROR_NONE != ret) {
7176 LOGW("failed to set pcm extraction\n");
7180 if (MM_ERROR_NONE != __gst_pending_seek(player))
7181 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7185 LOGD("current state before doing transition");
7186 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7187 MMPLAYER_PRINT_STATE(player);
7189 /* set pipeline state to PLAYING */
7190 if (player->es_player_push_mode)
7192 /* set pipeline state to PLAYING */
7193 ret = __mmplayer_gst_set_state(player,
7194 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7196 if (ret == MM_ERROR_NONE) {
7197 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7199 LOGE("failed to set state to PLAYING");
7203 /* generating debug info before returning error */
7204 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7211 static int __gst_stop(mm_player_t* player)
7213 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7214 MMHandleType attrs = 0;
7215 gboolean rewind = FALSE;
7217 int ret = MM_ERROR_NONE;
7218 gboolean async = FALSE;
7222 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7223 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7225 LOGD("current state before doing transition");
7226 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7227 MMPLAYER_PRINT_STATE(player);
7229 attrs = MMPLAYER_GET_ATTRS(player);
7231 LOGE("cannot get content attribute\n");
7232 return MM_ERROR_PLAYER_INTERNAL;
7235 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7236 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7238 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7239 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7242 if (player->es_player_push_mode)
7245 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7247 /* return if set_state has failed */
7248 if (ret != MM_ERROR_NONE) {
7249 LOGE("failed to set state.\n");
7255 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7256 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7257 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7258 LOGW("failed to rewind\n");
7259 ret = MM_ERROR_PLAYER_SEEK;
7264 player->sent_bos = FALSE;
7266 if (player->es_player_push_mode) //for cloudgame
7269 /* wait for seek to complete */
7270 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7271 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7272 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7274 LOGE("fail to stop player.\n");
7275 ret = MM_ERROR_PLAYER_INTERNAL;
7276 __mmplayer_dump_pipeline_state(player);
7279 /* generate dot file if enabled */
7280 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7287 int __gst_pause(mm_player_t* player, gboolean async)
7289 int ret = MM_ERROR_NONE;
7293 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7294 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7296 LOGD("current state before doing transition");
7297 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7298 MMPLAYER_PRINT_STATE(player);
7300 /* set pipeline status to PAUSED */
7301 ret = __mmplayer_gst_set_state(player,
7302 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7304 if (FALSE == async) {
7305 if (ret != MM_ERROR_NONE) {
7306 GstMessage *msg = NULL;
7307 GTimer *timer = NULL;
7308 gdouble MAX_TIMEOUT_SEC = 3;
7310 LOGE("failed to set state to PAUSED");
7312 if (player->msg_posted) {
7313 LOGE("error msg is already posted.");
7317 timer = g_timer_new();
7318 g_timer_start(timer);
7320 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7323 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7325 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7326 GError *error = NULL;
7328 /* parse error code */
7329 gst_message_parse_error(msg, &error, NULL);
7331 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7332 /* Note : the streaming error from the streaming source is handled
7333 * using __mmplayer_handle_streaming_error.
7335 __mmplayer_handle_streaming_error(player, msg);
7338 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7340 if (error->domain == GST_STREAM_ERROR)
7341 ret = __gst_handle_stream_error(player, error, msg);
7342 else if (error->domain == GST_RESOURCE_ERROR)
7343 ret = __gst_handle_resource_error(player, error->code, NULL);
7344 else if (error->domain == GST_LIBRARY_ERROR)
7345 ret = __gst_handle_library_error(player, error->code);
7346 else if (error->domain == GST_CORE_ERROR)
7347 ret = __gst_handle_core_error(player, error->code);
7349 g_error_free(error);
7351 player->msg_posted = TRUE;
7353 gst_message_unref(msg);
7355 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7357 gst_object_unref(bus);
7358 g_timer_stop(timer);
7359 g_timer_destroy(timer);
7363 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7364 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7366 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7368 } else if (ret == MM_ERROR_NONE) {
7370 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7374 /* generate dot file before returning error */
7375 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7382 int __gst_resume(mm_player_t* player, gboolean async)
7384 int ret = MM_ERROR_NONE;
7389 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7390 MM_ERROR_PLAYER_NOT_INITIALIZED);
7392 LOGD("current state before doing transition");
7393 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7394 MMPLAYER_PRINT_STATE(player);
7396 /* generate dot file before returning error */
7397 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7400 LOGD("do async state transition to PLAYING.\n");
7402 /* set pipeline state to PLAYING */
7403 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7405 ret = __mmplayer_gst_set_state(player,
7406 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7407 if (ret != MM_ERROR_NONE) {
7408 LOGE("failed to set state to PLAYING\n");
7411 if (async == FALSE) {
7412 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7413 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7414 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7418 /* generate dot file before returning error */
7419 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7427 __gst_set_position(mm_player_t* player, int format, unsigned long position, gboolean internal_called)
7429 unsigned long dur_msec = 0;
7430 gint64 dur_nsec = 0;
7431 gint64 pos_nsec = 0;
7432 gboolean ret = TRUE;
7433 gboolean accurated = FALSE;
7434 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7437 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7438 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7440 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7441 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7444 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7445 /* check duration */
7446 /* NOTE : duration cannot be zero except live streaming.
7447 * Since some element could have some timing problemn with quering duration, try again.
7449 if (!player->duration) {
7450 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7451 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7452 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7453 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7454 player->pending_seek.is_pending = TRUE;
7455 player->pending_seek.format = format;
7456 player->pending_seek.pos = position;
7457 player->doing_seek = FALSE;
7458 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7459 return MM_ERROR_NONE;
7464 player->duration = dur_nsec;
7467 if (player->duration) {
7468 dur_msec = GST_TIME_AS_MSECONDS(player->duration);
7470 LOGE("could not get the duration. fail to seek.\n");
7474 LOGD("playback rate: %f\n", player->playback_rate);
7476 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7478 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7480 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7484 case MM_PLAYER_POS_FORMAT_TIME:
7486 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7487 GstQuery *query = NULL;
7488 gboolean seekable = FALSE;
7490 /* check position is valid or not */
7491 if (position > dur_msec)
7494 query = gst_query_new_seeking(GST_FORMAT_TIME);
7495 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7496 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7497 gst_query_unref(query);
7500 LOGW("non-seekable content");
7501 player->doing_seek = FALSE;
7502 return MM_ERROR_PLAYER_NO_OP;
7505 LOGW("failed to get seeking query");
7506 gst_query_unref(query); /* keep seeking operation */
7509 LOGD("seeking to(%lu) msec, duration is %d msec\n", position, dur_msec);
7511 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7512 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7513 This causes problem is position calculation during normal pause resume scenarios also.
7514 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7515 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7516 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7517 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7518 LOGW("getting current position failed in seek\n");
7520 player->last_position = pos_nsec;
7521 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7524 if (player->doing_seek) {
7525 LOGD("not completed seek");
7526 return MM_ERROR_PLAYER_DOING_SEEK;
7530 if (!internal_called)
7531 player->doing_seek = TRUE;
7533 pos_nsec = position * G_GINT64_CONSTANT(1000000);
7535 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7536 gint64 cur_time = 0;
7538 /* get current position */
7539 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7542 GstEvent *event = gst_event_new_seek(1.0,
7544 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7545 GST_SEEK_TYPE_SET, cur_time,
7546 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7548 __gst_send_event_to_sink(player, event);
7550 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7551 __gst_pause(player, FALSE);
7554 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7555 that's why set position through property. */
7556 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7557 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7558 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7559 (!player->videodec_linked) && (!player->audiodec_linked)) {
7561 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7562 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7563 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7564 player->doing_seek = FALSE;
7565 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7567 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7568 GST_FORMAT_TIME, seek_flags,
7569 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7573 LOGE("failed to set position. dur[%lu] pos[%lu] pos_msec[%llu]\n", dur_msec, position, pos_nsec);
7579 case MM_PLAYER_POS_FORMAT_PERCENT:
7581 LOGD("seeking to(%lu)%% \n", position);
7583 if (player->doing_seek) {
7584 LOGD("not completed seek");
7585 return MM_ERROR_PLAYER_DOING_SEEK;
7588 if (!internal_called)
7589 player->doing_seek = TRUE;
7591 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7592 pos_nsec = (gint64)((position * player->duration) / 100);
7593 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7594 GST_FORMAT_TIME, seek_flags,
7595 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7597 LOGE("failed to set position. dur[%lud] pos[%lud] pos_msec[%"G_GUINT64_FORMAT"]\n", dur_msec, position, pos_nsec);
7607 /* NOTE : store last seeking point to overcome some bad operation
7608 * (returning zero when getting current position) of some elements
7610 player->last_position = pos_nsec;
7612 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7613 if (player->playback_rate > 1.0)
7614 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7617 return MM_ERROR_NONE;
7620 player->pending_seek.is_pending = TRUE;
7621 player->pending_seek.format = format;
7622 player->pending_seek.pos = position;
7624 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%lu).\n",
7625 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)), MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)), player->pending_seek.pos);
7627 return MM_ERROR_NONE;
7630 LOGE("invalid arguments, position : %ld dur : %ld format : %d \n", position, dur_msec, format);
7631 return MM_ERROR_INVALID_ARGUMENT;
7634 player->doing_seek = FALSE;
7635 return MM_ERROR_PLAYER_SEEK;
7638 #define TRICKPLAY_OFFSET GST_MSECOND
7641 __gst_get_position(mm_player_t* player, int format, unsigned long* position)
7643 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7644 gint64 pos_msec = 0;
7645 gboolean ret = TRUE;
7647 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7648 MM_ERROR_PLAYER_NOT_INITIALIZED);
7650 current_state = MMPLAYER_CURRENT_STATE(player);
7652 /* NOTE : query position except paused state to overcome some bad operation
7653 * please refer to below comments in details
7655 if (current_state != MM_PLAYER_STATE_PAUSED)
7656 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
7658 /* NOTE : get last point to overcome some bad operation of some elements
7659 *(returning zero when getting current position in paused state
7660 * and when failed to get postion during seeking
7662 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7663 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
7665 if (player->playback_rate < 0.0)
7666 pos_msec = player->last_position - TRICKPLAY_OFFSET;
7668 pos_msec = player->last_position;
7671 pos_msec = player->last_position;
7673 player->last_position = pos_msec;
7675 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_msec));
7678 if (player->duration > 0 && pos_msec > player->duration)
7679 pos_msec = player->duration;
7681 player->last_position = pos_msec;
7685 case MM_PLAYER_POS_FORMAT_TIME:
7686 *position = GST_TIME_AS_MSECONDS(pos_msec);
7689 case MM_PLAYER_POS_FORMAT_PERCENT:
7691 if (player->duration <= 0) {
7692 LOGD("duration is [%lld], so returning position 0\n", player->duration);
7695 LOGD("postion is [%lld] msec , duration is [%lld] msec", pos_msec, player->duration);
7696 *position = pos_msec * 100 / player->duration;
7701 return MM_ERROR_PLAYER_INTERNAL;
7704 return MM_ERROR_NONE;
7708 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7710 #define STREAMING_IS_FINISHED 0
7711 #define BUFFERING_MAX_PER 100
7712 #define DEFAULT_PER_VALUE -1
7713 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7715 MMPlayerGstElement *mainbin = NULL;
7716 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7717 gint64 buffered_total = 0;
7718 unsigned long position = 0;
7719 gint buffered_sec = -1;
7720 GstBufferingMode mode = GST_BUFFERING_STREAM;
7721 gint64 content_size_time = player->duration;
7722 guint64 content_size_bytes = player->http_content_size;
7724 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7726 player->pipeline->mainbin,
7727 MM_ERROR_PLAYER_NOT_INITIALIZED);
7729 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7734 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7735 /* and rtsp is not ready yet. */
7736 LOGW("it's only used for http streaming case.\n");
7737 return MM_ERROR_PLAYER_NO_OP;
7740 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7741 LOGW("Time format is not supported yet.\n");
7742 return MM_ERROR_INVALID_ARGUMENT;
7745 if (content_size_time <= 0 || content_size_bytes <= 0) {
7746 LOGW("there is no content size.");
7747 return MM_ERROR_NONE;
7750 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7751 LOGW("fail to get current position.");
7752 return MM_ERROR_NONE;
7755 LOGD("pos %d ms, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7756 position, (guint)(content_size_time/GST_SECOND), content_size_bytes);
7758 mainbin = player->pipeline->mainbin;
7759 start_per = (gint)(floor(100 *(gdouble)(position*GST_MSECOND) / (gdouble)content_size_time));
7761 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7762 GstQuery *query = NULL;
7763 gint byte_in_rate = 0, byte_out_rate = 0;
7764 gint64 estimated_total = 0;
7766 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7767 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7768 LOGW("fail to get buffering query from queue2");
7770 gst_query_unref(query);
7771 return MM_ERROR_NONE;
7774 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7775 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7777 if (mode == GST_BUFFERING_STREAM) {
7778 /* using only queue in case of push mode(ts / mp3) */
7779 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7780 GST_FORMAT_BYTES, &buffered_total)) {
7781 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7782 stop_per = 100 * buffered_total / content_size_bytes;
7785 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7787 guint num_of_ranges = 0;
7788 gint64 start_byte = 0, stop_byte = 0;
7790 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7791 if (estimated_total != STREAMING_IS_FINISHED) {
7792 /* buffered size info from queue2 */
7793 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7794 for (idx = 0; idx < num_of_ranges; idx++) {
7795 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7796 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7798 buffered_total += (stop_byte - start_byte);
7801 stop_per = BUFFERING_MAX_PER;
7803 gst_query_unref(query);
7806 if (stop_per == DEFAULT_PER_VALUE) {
7807 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7809 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7811 /* buffered size info from multiqueue */
7812 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7813 guint curr_size_bytes = 0;
7814 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7815 "curr-size-bytes", &curr_size_bytes, NULL);
7816 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7817 buffered_total += curr_size_bytes;
7820 if (avg_byterate > 0)
7821 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7822 else if (player->total_maximum_bitrate > 0)
7823 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7824 else if (player->total_bitrate > 0)
7825 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7827 if (buffered_sec >= 0)
7828 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7832 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7833 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7835 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7836 buffered_total, buffered_sec, *start_pos, *stop_pos);
7838 return MM_ERROR_NONE;
7842 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7847 LOGW("set_message_callback is called with invalid player handle\n");
7848 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7851 player->msg_cb = callback;
7852 player->msg_cb_param = user_param;
7854 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7858 return MM_ERROR_NONE;
7861 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7863 int ret = MM_ERROR_PLAYER_INVALID_URI;
7868 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7869 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7870 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7872 memset(data, 0, sizeof(MMPlayerParseProfile));
7874 if ((path = strstr(uri, "es_buff://"))) {
7876 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7877 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7878 ret = MM_ERROR_NONE;
7880 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7882 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7883 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7884 ret = MM_ERROR_NONE;
7886 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7889 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7890 tmp = g_ascii_strdown(uri, strlen(uri));
7892 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7893 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7895 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7897 ret = MM_ERROR_NONE;
7900 } else if ((path = strstr(uri, "rtspu://"))) {
7902 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7903 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7904 ret = MM_ERROR_NONE;
7906 } else if ((path = strstr(uri, "rtspr://"))) {
7907 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7908 char *separater = strstr(path, "*");
7912 char *urgent = separater + strlen("*");
7914 if ((urgent_len = strlen(urgent))) {
7915 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7916 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7917 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7918 ret = MM_ERROR_NONE;
7921 } else if ((path = strstr(uri, "mms://"))) {
7923 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7924 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7925 ret = MM_ERROR_NONE;
7927 } else if ((path = strstr(uri, "mem://"))) {
7930 char *buffer = NULL;
7931 char *seperator = strchr(path, ',');
7932 char ext[100] = {0,}, size[100] = {0,};
7935 if ((buffer = strstr(path, "ext="))) {
7936 buffer += strlen("ext=");
7938 if (strlen(buffer)) {
7939 strncpy(ext, buffer, 99);
7941 if ((seperator = strchr(ext, ','))
7942 || (seperator = strchr(ext, ' '))
7943 || (seperator = strchr(ext, '\0'))) {
7944 seperator[0] = '\0';
7949 if ((buffer = strstr(path, "size="))) {
7950 buffer += strlen("size=");
7952 if (strlen(buffer) > 0) {
7953 strncpy(size, buffer, 99);
7955 if ((seperator = strchr(size, ','))
7956 || (seperator = strchr(size, ' '))
7957 || (seperator = strchr(size, '\0'))) {
7958 seperator[0] = '\0';
7961 mem_size = atoi(size);
7966 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7967 if (mem_size && param) {
7968 if (data->input_mem.buf)
7969 free(data->input_mem.buf);
7970 data->input_mem.buf = malloc(mem_size);
7972 if (data->input_mem.buf) {
7973 memcpy(data->input_mem.buf, param, mem_size);
7974 data->input_mem.len = mem_size;
7975 ret = MM_ERROR_NONE;
7977 LOGE("failed to alloc mem %d", mem_size);
7978 ret = MM_ERROR_PLAYER_INTERNAL;
7981 data->input_mem.offset = 0;
7982 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
7986 gchar *location = NULL;
7989 if ((path = strstr(uri, "file://"))) {
7991 location = g_filename_from_uri(uri, NULL, &err);
7993 if (!location || (err != NULL)) {
7994 LOGE("Invalid URI '%s' for filesrc: %s", path,
7995 (err != NULL) ? err->message : "unknown error");
7997 if (err) g_error_free(err);
7998 if (location) g_free(location);
8000 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8004 LOGD("path from uri: %s", location);
8007 path = (location != NULL) ? (location) : ((char*)uri);
8008 int file_stat = MM_ERROR_NONE;
8010 file_stat = util_exist_file_path(path);
8012 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8013 if (file_stat == MM_ERROR_NONE) {
8014 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8016 if (util_is_sdp_file(path)) {
8017 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8018 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8020 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8022 ret = MM_ERROR_NONE;
8023 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8024 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8026 LOGE("invalid uri, could not play..\n");
8027 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8030 if (location) g_free(location);
8034 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8035 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8036 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8037 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8039 /* dump parse result */
8040 SECURE_LOGW("incomming uri : %s\n", uri);
8041 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8042 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8050 __mmplayer_can_do_interrupt(mm_player_t *player)
8052 if (!player || !player->pipeline || !player->attrs) {
8053 LOGW("not initialized");
8057 if (player->set_mode.pcm_extraction) {
8058 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8062 /* check if seeking */
8063 if (player->doing_seek) {
8064 MMMessageParamType msg_param;
8065 memset(&msg_param, 0, sizeof(MMMessageParamType));
8066 msg_param.code = MM_ERROR_PLAYER_SEEK;
8067 player->doing_seek = FALSE;
8068 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8072 /* check other thread */
8073 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8074 LOGW("locked already, cmd state : %d", player->cmd);
8076 /* check application command */
8077 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8078 LOGW("playing.. should wait cmd lock then, will be interrupted");
8080 /* lock will be released at mrp_resource_release_cb() */
8081 MMPLAYER_CMD_LOCK(player);
8084 LOGW("nothing to do");
8087 LOGW("can interrupt immediately");
8091 FAILED: /* with CMD UNLOCKED */
8094 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8099 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8102 mm_player_t *player = NULL;
8106 if (user_data == NULL) {
8107 LOGE("- user_data is null\n");
8110 player = (mm_player_t *)user_data;
8112 /* do something to release resource here.
8113 * player stop and interrupt forwarding */
8114 if (!__mmplayer_can_do_interrupt(player)) {
8115 LOGW("no need to interrupt, so leave");
8117 MMMessageParamType msg = {0, };
8118 unsigned long pos = 0;
8120 player->interrupted_by_resource = TRUE;
8122 /* get last play position */
8123 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8124 LOGW("failed to get play position.");
8126 msg.union_type = MM_MSG_UNION_TIME;
8127 msg.time.elapsed = (unsigned int)pos;
8128 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8130 LOGD("video resource conflict so, resource will be freed by unrealizing");
8131 if (_mmplayer_unrealize((MMHandleType)player))
8132 LOGW("failed to unrealize");
8134 /* lock is called in __mmplayer_can_do_interrupt() */
8135 MMPLAYER_CMD_UNLOCK(player);
8138 if (res == player->video_overlay_resource)
8139 player->video_overlay_resource = FALSE;
8141 player->video_decoder_resource = FALSE;
8149 _mmplayer_create_player(MMHandleType handle)
8151 int ret = MM_ERROR_PLAYER_INTERNAL;
8152 bool enabled = false;
8154 mm_player_t* player = MM_PLAYER_CAST(handle);
8158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8160 /* initialize player state */
8161 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8162 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8163 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8164 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8166 /* check current state */
8167 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8169 /* construct attributes */
8170 player->attrs = _mmplayer_construct_attribute(handle);
8172 if (!player->attrs) {
8173 LOGE("Failed to construct attributes\n");
8177 /* initialize gstreamer with configured parameter */
8178 if (!__mmplayer_init_gstreamer(player)) {
8179 LOGE("Initializing gstreamer failed\n");
8180 _mmplayer_deconstruct_attribute(handle);
8184 /* create lock. note that g_tread_init() has already called in gst_init() */
8185 g_mutex_init(&player->fsink_lock);
8187 /* create update tag lock */
8188 g_mutex_init(&player->update_tag_lock);
8190 /* create next play mutex */
8191 g_mutex_init(&player->next_play_thread_mutex);
8193 /* create next play cond */
8194 g_cond_init(&player->next_play_thread_cond);
8196 /* create next play thread */
8197 player->next_play_thread =
8198 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8199 if (!player->next_play_thread) {
8200 LOGE("failed to create next play thread");
8201 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8202 g_mutex_clear(&player->next_play_thread_mutex);
8203 g_cond_clear(&player->next_play_thread_cond);
8207 ret = _mmplayer_initialize_video_capture(player);
8208 if (ret != MM_ERROR_NONE) {
8209 LOGE("failed to initialize video capture\n");
8213 /* initialize resource manager */
8214 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8215 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8216 &player->resource_manager)) {
8217 LOGE("failed to initialize resource manager\n");
8221 if (MMPLAYER_IS_HTTP_PD(player)) {
8222 player->pd_downloader = NULL;
8223 player->pd_file_save_path = NULL;
8226 /* create video bo lock and cond */
8227 g_mutex_init(&player->video_bo_mutex);
8228 g_cond_init(&player->video_bo_cond);
8230 /* create media stream callback mutex */
8231 g_mutex_init(&player->media_stream_cb_lock);
8233 /* create subtitle info lock and cond */
8234 g_mutex_init(&player->subtitle_info_mutex);
8235 g_cond_init(&player->subtitle_info_cond);
8237 player->streaming_type = STREAMING_SERVICE_NONE;
8239 /* give default value of audio effect setting */
8240 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8241 player->sound.rg_enable = false;
8242 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8244 player->play_subtitle = FALSE;
8245 player->use_deinterleave = FALSE;
8246 player->max_audio_channels = 0;
8247 player->video_share_api_delta = 0;
8248 player->video_share_clock_delta = 0;
8249 player->has_closed_caption = FALSE;
8250 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8251 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8252 player->pending_resume = FALSE;
8253 if (player->ini.dump_element_keyword[0][0] == '\0')
8254 player->ini.set_dump_element_flag = FALSE;
8256 player->ini.set_dump_element_flag = TRUE;
8258 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8259 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8260 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8262 /* Set video360 settings to their defaults for just-created player.
8265 player->is_360_feature_enabled = FALSE;
8266 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8267 LOGI("spherical feature info: %d", enabled);
8269 player->is_360_feature_enabled = TRUE;
8271 LOGE("failed to get spherical feature info");
8274 player->is_content_spherical = FALSE;
8275 player->is_video360_enabled = TRUE;
8276 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8277 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8278 player->video360_yaw_radians = 4;
8279 player->video360_pitch_radians = 4;
8280 player->video360_zoom = 1.0f;
8281 player->video360_horizontal_fov = 0;
8282 player->video360_vertical_fov = 0;
8284 /* set player state to null */
8285 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8286 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8288 return MM_ERROR_NONE;
8292 g_mutex_clear(&player->fsink_lock);
8294 /* free update tag lock */
8295 g_mutex_clear(&player->update_tag_lock);
8297 /* free next play thread */
8298 if (player->next_play_thread) {
8299 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8300 player->next_play_thread_exit = TRUE;
8301 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8302 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8304 g_thread_join(player->next_play_thread);
8305 player->next_play_thread = NULL;
8307 g_mutex_clear(&player->next_play_thread_mutex);
8308 g_cond_clear(&player->next_play_thread_cond);
8311 /* release attributes */
8312 _mmplayer_deconstruct_attribute(handle);
8320 __mmplayer_init_gstreamer(mm_player_t* player)
8322 static gboolean initialized = FALSE;
8323 static const int max_argc = 50;
8325 gchar** argv = NULL;
8326 gchar** argv2 = NULL;
8332 LOGD("gstreamer already initialized.\n");
8337 argc = malloc(sizeof(int));
8338 argv = malloc(sizeof(gchar*) * max_argc);
8339 argv2 = malloc(sizeof(gchar*) * max_argc);
8341 if (!argc || !argv || !argv2)
8344 memset(argv, 0, sizeof(gchar*) * max_argc);
8345 memset(argv2, 0, sizeof(gchar*) * max_argc);
8349 argv[0] = g_strdup("mmplayer");
8352 for (i = 0; i < 5; i++) {
8353 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8354 if (strlen(player->ini.gst_param[i]) > 0) {
8355 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8360 /* we would not do fork for scanning plugins */
8361 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8364 /* check disable registry scan */
8365 if (player->ini.skip_rescan) {
8366 argv[*argc] = g_strdup("--gst-disable-registry-update");
8370 /* check disable segtrap */
8371 if (player->ini.disable_segtrap) {
8372 argv[*argc] = g_strdup("--gst-disable-segtrap");
8376 LOGD("initializing gstreamer with following parameter\n");
8377 LOGD("argc : %d\n", *argc);
8380 for (i = 0; i < arg_count; i++) {
8382 LOGD("argv[%d] : %s\n", i, argv2[i]);
8385 /* initializing gstreamer */
8386 if (!gst_init_check(argc, &argv, &err)) {
8387 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8394 for (i = 0; i < arg_count; i++) {
8395 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8396 MMPLAYER_FREEIF(argv2[i]);
8399 MMPLAYER_FREEIF(argv);
8400 MMPLAYER_FREEIF(argv2);
8401 MMPLAYER_FREEIF(argc);
8411 for (i = 0; i < arg_count; i++) {
8412 LOGD("free[%d] : %s\n", i, argv2[i]);
8413 MMPLAYER_FREEIF(argv2[i]);
8416 MMPLAYER_FREEIF(argv);
8417 MMPLAYER_FREEIF(argv2);
8418 MMPLAYER_FREEIF(argc);
8424 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8426 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8428 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8429 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8430 MMPLAYER_FREEIF(player->pd_file_save_path);
8433 return MM_ERROR_NONE;
8437 __mmplayer_check_async_state_transition(mm_player_t* player)
8439 GstState element_state = GST_STATE_VOID_PENDING;
8440 GstState element_pending_state = GST_STATE_VOID_PENDING;
8441 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8442 GstElement * element = NULL;
8443 gboolean async = FALSE;
8445 /* check player handle */
8446 MMPLAYER_RETURN_IF_FAIL(player &&
8448 player->pipeline->mainbin &&
8449 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8452 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8454 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8455 LOGD("don't need to check the pipeline state");
8459 MMPLAYER_PRINT_STATE(player);
8461 /* wait for state transition */
8462 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8463 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8465 if (ret == GST_STATE_CHANGE_FAILURE) {
8466 LOGE(" [%s] state : %s pending : %s \n",
8467 GST_ELEMENT_NAME(element),
8468 gst_element_state_get_name(element_state),
8469 gst_element_state_get_name(element_pending_state));
8471 /* dump state of all element */
8472 __mmplayer_dump_pipeline_state(player);
8477 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8482 _mmplayer_destroy(MMHandleType handle)
8484 mm_player_t* player = MM_PLAYER_CAST(handle);
8488 /* check player handle */
8489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8491 /* destroy can called at anytime */
8492 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8494 /* check async state transition */
8495 __mmplayer_check_async_state_transition(player);
8497 __mmplayer_destroy_streaming_ext(player);
8499 /* release next play thread */
8500 if (player->next_play_thread) {
8501 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8502 player->next_play_thread_exit = TRUE;
8503 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8504 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8506 LOGD("waitting for next play thread exit\n");
8507 g_thread_join(player->next_play_thread);
8508 g_mutex_clear(&player->next_play_thread_mutex);
8509 g_cond_clear(&player->next_play_thread_cond);
8510 LOGD("next play thread released\n");
8513 _mmplayer_release_video_capture(player);
8515 /* de-initialize resource manager */
8516 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8517 player->resource_manager))
8518 LOGE("failed to deinitialize resource manager\n");
8520 /* release pipeline */
8521 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8522 LOGE("failed to destory pipeline\n");
8523 return MM_ERROR_PLAYER_INTERNAL;
8526 /* release subtitle info lock and cond */
8527 g_mutex_clear(&player->subtitle_info_mutex);
8528 g_cond_clear(&player->subtitle_info_cond);
8530 __mmplayer_release_dump_list(player->dump_list);
8532 /* release miscellaneous information */
8533 __mmplayer_release_misc(player);
8535 /* release miscellaneous information.
8536 these info needs to be released after pipeline is destroyed. */
8537 __mmplayer_release_misc_post(player);
8539 /* release attributes */
8540 _mmplayer_deconstruct_attribute(handle);
8543 g_mutex_clear(&player->fsink_lock);
8546 g_mutex_clear(&player->update_tag_lock);
8548 /* release video bo lock and cond */
8549 g_mutex_clear(&player->video_bo_mutex);
8550 g_cond_clear(&player->video_bo_cond);
8552 /* release media stream callback lock */
8553 g_mutex_clear(&player->media_stream_cb_lock);
8557 return MM_ERROR_NONE;
8561 __mmplayer_realize_streaming_ext(mm_player_t* player)
8563 int ret = MM_ERROR_NONE;
8566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8568 if (MMPLAYER_IS_HTTP_PD(player)) {
8569 gboolean bret = FALSE;
8571 player->pd_downloader = _mmplayer_create_pd_downloader();
8572 if (!player->pd_downloader) {
8573 LOGE("Unable to create PD Downloader...");
8574 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8577 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8579 if (FALSE == bret) {
8580 LOGE("Unable to create PD Downloader...");
8581 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8590 _mmplayer_realize(MMHandleType hplayer)
8592 mm_player_t* player = (mm_player_t*)hplayer;
8595 MMHandleType attrs = 0;
8596 int ret = MM_ERROR_NONE;
8600 /* check player handle */
8601 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8603 /* check current state */
8604 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8606 attrs = MMPLAYER_GET_ATTRS(player);
8608 LOGE("fail to get attributes.\n");
8609 return MM_ERROR_PLAYER_INTERNAL;
8611 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8612 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8614 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8615 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8617 if (ret != MM_ERROR_NONE) {
8618 LOGE("failed to parse profile\n");
8623 if (uri && (strstr(uri, "es_buff://"))) {
8624 if (strstr(uri, "es_buff://push_mode"))
8625 player->es_player_push_mode = TRUE;
8627 player->es_player_push_mode = FALSE;
8630 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8631 LOGW("mms protocol is not supported format.\n");
8632 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8635 if (MMPLAYER_IS_STREAMING(player))
8636 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8638 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8640 player->smooth_streaming = FALSE;
8641 player->videodec_linked = 0;
8642 player->videosink_linked = 0;
8643 player->audiodec_linked = 0;
8644 player->audiosink_linked = 0;
8645 player->textsink_linked = 0;
8646 player->is_external_subtitle_present = FALSE;
8647 player->is_external_subtitle_added_now = FALSE;
8648 /* set the subtitle ON default */
8649 player->is_subtitle_off = FALSE;
8651 /* realize pipeline */
8652 ret = __gst_realize(player);
8653 if (ret != MM_ERROR_NONE)
8654 LOGE("fail to realize the player.\n");
8656 ret = __mmplayer_realize_streaming_ext(player);
8658 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8659 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8667 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8672 /* destroy can called at anytime */
8673 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8674 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8677 return MM_ERROR_NONE;
8681 _mmplayer_unrealize(MMHandleType hplayer)
8683 mm_player_t* player = (mm_player_t*)hplayer;
8684 int ret = MM_ERROR_NONE;
8688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8690 MMPLAYER_CMD_UNLOCK(player);
8691 /* destroy the gst bus msg thread which is created during realize.
8692 this funct have to be called before getting cmd lock. */
8693 _mmplayer_bus_msg_thread_destroy(player);
8694 MMPLAYER_CMD_LOCK(player);
8696 /* check current state */
8697 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8699 /* check async state transition */
8700 __mmplayer_check_async_state_transition(player);
8702 __mmplayer_unrealize_streaming_ext(player);
8704 /* unrealize pipeline */
8705 ret = __gst_unrealize(player);
8707 /* set asm stop if success */
8708 if (MM_ERROR_NONE == ret) {
8709 if (!player->interrupted_by_resource) {
8710 if (player->video_decoder_resource != NULL) {
8711 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8712 player->video_decoder_resource);
8713 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8714 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8716 player->video_decoder_resource = NULL;
8719 if (player->video_overlay_resource != NULL) {
8720 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8721 player->video_overlay_resource);
8722 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8723 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8725 player->video_overlay_resource = NULL;
8728 ret = mm_resource_manager_commit(player->resource_manager);
8729 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8730 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8733 LOGE("failed and don't change asm state to stop");
8741 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8743 mm_player_t* player = (mm_player_t*)hplayer;
8745 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8747 return __gst_set_message_callback(player, callback, user_param);
8751 _mmplayer_get_state(MMHandleType hplayer, int* state)
8753 mm_player_t *player = (mm_player_t*)hplayer;
8755 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8757 *state = MMPLAYER_CURRENT_STATE(player);
8759 return MM_ERROR_NONE;
8764 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8766 mm_player_t* player = (mm_player_t*) hplayer;
8767 GstElement* vol_element = NULL;
8772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8774 LOGD("volume [L]=%f:[R]=%f\n",
8775 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8777 /* invalid factor range or not */
8778 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8779 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8780 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8781 return MM_ERROR_INVALID_ARGUMENT;
8785 /* not support to set other value into each channel */
8786 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8787 return MM_ERROR_INVALID_ARGUMENT;
8789 /* Save volume to handle. Currently the first array element will be saved. */
8790 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8792 /* check pipeline handle */
8793 if (!player->pipeline || !player->pipeline->audiobin) {
8794 LOGD("audiobin is not created yet\n");
8795 LOGD("but, current stored volume will be set when it's created.\n");
8797 /* NOTE : stored volume will be used in create_audiobin
8798 * returning MM_ERROR_NONE here makes application to able to
8799 * set volume at anytime.
8801 return MM_ERROR_NONE;
8804 /* setting volume to volume element */
8805 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8808 LOGD("volume is set [%f]\n", player->sound.volume);
8809 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8814 return MM_ERROR_NONE;
8819 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8821 mm_player_t* player = (mm_player_t*) hplayer;
8826 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8827 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8829 /* returning stored volume */
8830 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8831 volume->level[i] = player->sound.volume;
8835 return MM_ERROR_NONE;
8839 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8841 mm_player_t* player = (mm_player_t*) hplayer;
8842 GstElement* vol_element = NULL;
8846 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8848 /* mute value shoud 0 or 1 */
8849 if (mute != 0 && mute != 1) {
8850 LOGE("bad mute value\n");
8852 /* FIXIT : definitly, we need _BAD_PARAM error code */
8853 return MM_ERROR_INVALID_ARGUMENT;
8856 player->sound.mute = mute;
8858 /* just hold mute value if pipeline is not ready */
8859 if (!player->pipeline || !player->pipeline->audiobin) {
8860 LOGD("pipeline is not ready. holding mute value\n");
8861 return MM_ERROR_NONE;
8864 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8866 /* NOTE : volume will only created when the bt is enabled */
8868 LOGD("mute : %d\n", mute);
8869 g_object_set(vol_element, "mute", mute, NULL);
8871 LOGD("volume elemnet is not created. using volume in audiosink\n");
8875 return MM_ERROR_NONE;
8879 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8881 mm_player_t* player = (mm_player_t*) hplayer;
8885 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8886 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8888 /* just hold mute value if pipeline is not ready */
8889 if (!player->pipeline || !player->pipeline->audiobin) {
8890 LOGD("pipeline is not ready. returning stored value\n");
8891 *pmute = player->sound.mute;
8892 return MM_ERROR_NONE;
8895 *pmute = player->sound.mute;
8899 return MM_ERROR_NONE;
8903 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8905 mm_player_t* player = (mm_player_t*) hplayer;
8909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8911 player->video_stream_changed_cb = callback;
8912 player->video_stream_changed_cb_user_param = user_param;
8913 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8917 return MM_ERROR_NONE;
8921 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8923 mm_player_t* player = (mm_player_t*) hplayer;
8927 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8929 player->audio_stream_changed_cb = callback;
8930 player->audio_stream_changed_cb_user_param = user_param;
8931 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8935 return MM_ERROR_NONE;
8939 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8941 mm_player_t* player = (mm_player_t*) hplayer;
8945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8947 player->audio_stream_render_cb_ex = callback;
8948 player->audio_stream_cb_user_param = user_param;
8949 player->audio_stream_sink_sync = sync;
8950 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);
8954 return MM_ERROR_NONE;
8958 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8960 mm_player_t* player = (mm_player_t*) hplayer;
8964 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8966 if (callback && !player->bufmgr)
8967 player->bufmgr = tbm_bufmgr_init(-1);
8969 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8970 player->video_stream_cb = callback;
8971 player->video_stream_cb_user_param = user_param;
8973 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
8977 return MM_ERROR_NONE;
8981 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
8983 mm_player_t* player = (mm_player_t*) hplayer;
8987 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8989 player->audio_stream_cb = callback;
8990 player->audio_stream_cb_user_param = user_param;
8991 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
8995 return MM_ERROR_NONE;
8999 __mmplayer_start_streaming_ext(mm_player_t *player)
9001 gint ret = MM_ERROR_NONE;
9004 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9006 if (MMPLAYER_IS_HTTP_PD(player)) {
9007 if (!player->pd_downloader) {
9008 ret = __mmplayer_realize_streaming_ext(player);
9010 if (ret != MM_ERROR_NONE) {
9011 LOGE("failed to realize streaming ext\n");
9016 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9017 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9019 LOGE("ERROR while starting PD...\n");
9020 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9022 ret = MM_ERROR_NONE;
9031 _mmplayer_start(MMHandleType hplayer)
9033 mm_player_t* player = (mm_player_t*) hplayer;
9034 gint ret = MM_ERROR_NONE;
9038 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9040 /* check current state */
9041 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9043 /* NOTE : we should check and create pipeline again if not created as we destroy
9044 * whole pipeline when stopping in streamming playback
9046 if (!player->pipeline) {
9047 ret = __gst_realize(player);
9048 if (MM_ERROR_NONE != ret) {
9049 LOGE("failed to realize before starting. only in streamming\n");
9055 ret = __mmplayer_start_streaming_ext(player);
9056 if (ret != MM_ERROR_NONE) {
9057 LOGE("failed to start streaming ext 0x%X", ret);
9061 /* start pipeline */
9062 ret = __gst_start(player);
9063 if (ret != MM_ERROR_NONE)
9064 LOGE("failed to start player.\n");
9071 /* NOTE: post "not supported codec message" to application
9072 * when one codec is not found during AUTOPLUGGING in MSL.
9073 * So, it's separated with error of __mmplayer_gst_callback().
9074 * And, if any codec is not found, don't send message here.
9075 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9078 __mmplayer_handle_missed_plugin(mm_player_t* player)
9080 MMMessageParamType msg_param;
9081 memset(&msg_param, 0, sizeof(MMMessageParamType));
9082 gboolean post_msg_direct = FALSE;
9086 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9088 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9089 player->not_supported_codec, player->can_support_codec);
9091 if (player->not_found_demuxer) {
9092 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9093 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9095 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9096 MMPLAYER_FREEIF(msg_param.data);
9098 return MM_ERROR_NONE;
9101 if (player->not_supported_codec) {
9102 if (player->can_support_codec) {
9103 // There is one codec to play
9104 post_msg_direct = TRUE;
9106 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9107 post_msg_direct = TRUE;
9110 if (post_msg_direct) {
9111 MMMessageParamType msg_param;
9112 memset(&msg_param, 0, sizeof(MMMessageParamType));
9114 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9115 LOGW("not found AUDIO codec, posting error code to application.\n");
9117 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9118 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9119 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9120 LOGW("not found VIDEO codec, posting error code to application.\n");
9122 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9123 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9126 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9128 MMPLAYER_FREEIF(msg_param.data);
9130 return MM_ERROR_NONE;
9132 // no any supported codec case
9133 LOGW("not found any codec, posting error code to application.\n");
9135 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9136 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9137 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9139 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9140 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9143 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9145 MMPLAYER_FREEIF(msg_param.data);
9151 return MM_ERROR_NONE;
9154 static void __mmplayer_check_pipeline(mm_player_t* player)
9156 GstState element_state = GST_STATE_VOID_PENDING;
9157 GstState element_pending_state = GST_STATE_VOID_PENDING;
9159 int ret = MM_ERROR_NONE;
9161 if (player->gapless.reconfigure) {
9162 LOGW("pipeline is under construction.\n");
9164 MMPLAYER_PLAYBACK_LOCK(player);
9165 MMPLAYER_PLAYBACK_UNLOCK(player);
9167 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9169 /* wait for state transition */
9170 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9172 if (ret == GST_STATE_CHANGE_FAILURE)
9173 LOGE("failed to change pipeline state within %d sec\n", timeout);
9177 /* NOTE : it should be able to call 'stop' anytime*/
9179 _mmplayer_stop(MMHandleType hplayer)
9181 mm_player_t* player = (mm_player_t*)hplayer;
9182 int ret = MM_ERROR_NONE;
9186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9188 /* check current state */
9189 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9191 /* check pipline building state */
9192 __mmplayer_check_pipeline(player);
9193 __mmplayer_reset_gapless_state(player);
9195 /* NOTE : application should not wait for EOS after calling STOP */
9196 __mmplayer_cancel_eos_timer(player);
9198 __mmplayer_unrealize_streaming_ext(player);
9201 player->doing_seek = FALSE;
9204 ret = __gst_stop(player);
9206 if (ret != MM_ERROR_NONE)
9207 LOGE("failed to stop player.\n");
9215 _mmplayer_pause(MMHandleType hplayer)
9217 mm_player_t* player = (mm_player_t*)hplayer;
9218 gint64 pos_msec = 0;
9219 gboolean async = FALSE;
9220 gint ret = MM_ERROR_NONE;
9224 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9226 /* check current state */
9227 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9229 /* check pipline building state */
9230 __mmplayer_check_pipeline(player);
9232 switch (MMPLAYER_CURRENT_STATE(player)) {
9233 case MM_PLAYER_STATE_READY:
9235 /* check prepare async or not.
9236 * In the case of streaming playback, it's recommned to avoid blocking wait.
9238 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9239 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9241 /* Changing back sync of rtspsrc to async */
9242 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9243 LOGD("async prepare working mode for rtsp");
9249 case MM_PLAYER_STATE_PLAYING:
9251 /* NOTE : store current point to overcome some bad operation
9252 *(returning zero when getting current position in paused state) of some
9255 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec))
9256 LOGW("getting current position failed in paused\n");
9258 player->last_position = pos_msec;
9260 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9261 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9262 This causes problem is position calculation during normal pause resume scenarios also.
9263 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9264 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9265 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9266 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9272 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9273 LOGD("doing async pause in case of ms buff src");
9277 /* pause pipeline */
9278 ret = __gst_pause(player, async);
9280 if (ret != MM_ERROR_NONE)
9281 LOGE("failed to pause player. ret : 0x%x\n", ret);
9283 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9284 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9285 LOGE("failed to update display_rotation");
9294 _mmplayer_resume(MMHandleType hplayer)
9296 mm_player_t* player = (mm_player_t*)hplayer;
9297 int ret = MM_ERROR_NONE;
9298 gboolean async = FALSE;
9302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9304 /* Changing back sync mode rtspsrc to async */
9305 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9306 LOGD("async resume for rtsp case");
9310 /* check current state */
9311 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9313 ret = __gst_resume(player, async);
9315 if (ret != MM_ERROR_NONE)
9316 LOGE("failed to resume player.\n");
9324 __mmplayer_set_pcm_extraction(mm_player_t* player)
9326 gint64 start_nsec = 0;
9327 gint64 end_nsec = 0;
9328 gint64 dur_nsec = 0;
9329 gint64 dur_msec = 0;
9330 int required_start = 0;
9331 int required_end = 0;
9336 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9338 mm_attrs_multiple_get(player->attrs,
9340 "pcm_extraction_start_msec", &required_start,
9341 "pcm_extraction_end_msec", &required_end,
9344 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9346 if (required_start == 0 && required_end == 0) {
9347 LOGD("extracting entire stream");
9348 return MM_ERROR_NONE;
9349 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9350 LOGD("invalid range for pcm extraction");
9351 return MM_ERROR_INVALID_ARGUMENT;
9355 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9357 LOGE("failed to get duration");
9358 return MM_ERROR_PLAYER_INTERNAL;
9360 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9362 if (dur_msec < required_end) {
9364 LOGD("invalid end pos for pcm extraction");
9365 return MM_ERROR_INVALID_ARGUMENT;
9368 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9369 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9371 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9374 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9375 GST_SEEK_TYPE_SET, start_nsec,
9376 GST_SEEK_TYPE_SET, end_nsec))) {
9377 LOGE("failed to seek for pcm extraction\n");
9379 return MM_ERROR_PLAYER_SEEK;
9382 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9386 return MM_ERROR_NONE;
9390 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9392 mm_player_t* player = (mm_player_t*)hplayer;
9393 gint64 pos_msec = 0;
9394 int ret = MM_ERROR_NONE;
9396 signed long long start = 0, stop = 0;
9397 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9400 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9401 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9403 /* The sound of video is not supported under 0.0 and over 2.0. */
9404 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9405 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9408 _mmplayer_set_mute(hplayer, mute);
9410 if (player->playback_rate == rate)
9411 return MM_ERROR_NONE;
9413 /* If the position is reached at start potion during fast backward, EOS is posted.
9414 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9416 player->playback_rate = rate;
9418 current_state = MMPLAYER_CURRENT_STATE(player);
9420 if (current_state != MM_PLAYER_STATE_PAUSED)
9421 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_msec);
9423 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_msec), ret, current_state);
9425 if ((current_state == MM_PLAYER_STATE_PAUSED)
9426 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9427 LOGW("returning last point : %lld\n", player->last_position);
9428 pos_msec = player->last_position;
9433 stop = GST_CLOCK_TIME_NONE;
9435 start = GST_CLOCK_TIME_NONE;
9439 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9440 player->playback_rate,
9442 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9443 GST_SEEK_TYPE_SET, start,
9444 GST_SEEK_TYPE_SET, stop)) {
9445 LOGE("failed to set speed playback\n");
9446 return MM_ERROR_PLAYER_SEEK;
9449 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9453 return MM_ERROR_NONE;;
9457 _mmplayer_set_position(MMHandleType hplayer, int format, int position)
9459 mm_player_t* player = (mm_player_t*)hplayer;
9460 int ret = MM_ERROR_NONE;
9464 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9466 /* check pipline building state */
9467 __mmplayer_check_pipeline(player);
9469 ret = __gst_set_position(player, format, (unsigned long)position, FALSE);
9477 _mmplayer_get_position(MMHandleType hplayer, int format, unsigned long *position)
9479 mm_player_t* player = (mm_player_t*)hplayer;
9480 int ret = MM_ERROR_NONE;
9482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9484 ret = __gst_get_position(player, format, position);
9490 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9492 mm_player_t* player = (mm_player_t*)hplayer;
9493 int ret = MM_ERROR_NONE;
9495 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9497 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9503 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9505 mm_player_t* player = (mm_player_t*)hplayer;
9506 int ret = MM_ERROR_NONE;
9510 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9512 ret = __gst_adjust_subtitle_position(player, format, position);
9519 _mmplayer_adjust_video_postion(MMHandleType hplayer, int offset)
9521 mm_player_t* player = (mm_player_t*)hplayer;
9522 int ret = MM_ERROR_NONE;
9526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9528 ret = __gst_adjust_video_position(player, offset);
9536 __mmplayer_is_midi_type(gchar* str_caps)
9538 if ((g_strrstr(str_caps, "audio/midi")) ||
9539 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9540 (g_strrstr(str_caps, "application/x-smaf")) ||
9541 (g_strrstr(str_caps, "audio/x-imelody")) ||
9542 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9543 (g_strrstr(str_caps, "audio/xmf")) ||
9544 (g_strrstr(str_caps, "audio/mxmf"))) {
9553 __mmplayer_is_only_mp3_type(gchar *str_caps)
9555 if (g_strrstr(str_caps, "application/x-id3") ||
9556 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9562 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9564 GstStructure* caps_structure = NULL;
9565 gint samplerate = 0;
9569 MMPLAYER_RETURN_IF_FAIL(player && caps);
9571 caps_structure = gst_caps_get_structure(caps, 0);
9573 /* set stream information */
9574 gst_structure_get_int(caps_structure, "rate", &samplerate);
9575 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9577 gst_structure_get_int(caps_structure, "channels", &channels);
9578 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9580 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9584 __mmplayer_update_content_type_info(mm_player_t* player)
9587 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9589 if (__mmplayer_is_midi_type(player->type)) {
9590 player->bypass_audio_effect = TRUE;
9591 } else if (g_strrstr(player->type, "application/x-hls")) {
9592 /* If it can't know exact type when it parses uri because of redirection case,
9593 * it will be fixed by typefinder or when doing autoplugging.
9595 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9596 if (player->streamer) {
9597 player->streamer->is_adaptive_streaming = TRUE;
9598 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9599 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9601 } else if (g_strrstr(player->type, "application/dash+xml")) {
9602 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9609 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9610 GstCaps *caps, gpointer data)
9612 mm_player_t* player = (mm_player_t*)data;
9617 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9619 /* store type string */
9620 MMPLAYER_FREEIF(player->type);
9621 player->type = gst_caps_to_string(caps);
9623 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9624 player, player->type, probability, gst_caps_get_size(caps));
9627 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9628 (g_strrstr(player->type, "audio/x-raw-int"))) {
9629 LOGE("not support media format\n");
9631 if (player->msg_posted == FALSE) {
9632 MMMessageParamType msg_param;
9633 memset(&msg_param, 0, sizeof(MMMessageParamType));
9635 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9636 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9638 /* don't post more if one was sent already */
9639 player->msg_posted = TRUE;
9644 __mmplayer_update_content_type_info(player);
9646 pad = gst_element_get_static_pad(tf, "src");
9648 LOGE("fail to get typefind src pad.\n");
9652 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9653 gboolean async = FALSE;
9654 LOGE("failed to autoplug %s\n", player->type);
9656 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9658 if (async && player->msg_posted == FALSE)
9659 __mmplayer_handle_missed_plugin(player);
9665 gst_object_unref(GST_OBJECT(pad));
9673 __mmplayer_create_decodebin(mm_player_t* player)
9675 GstElement *decodebin = NULL;
9679 /* create decodebin */
9680 decodebin = gst_element_factory_make("decodebin", NULL);
9683 LOGE("fail to create decodebin\n");
9687 /* raw pad handling signal */
9688 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9689 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9691 /* no-more-pad pad handling signal */
9692 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9693 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9695 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9696 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9698 /* This signal is emitted when a pad for which there is no further possible
9699 decoding is added to the decodebin.*/
9700 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9701 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9703 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9704 before looking for any elements that can handle that stream.*/
9705 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9706 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9708 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9709 before looking for any elements that can handle that stream.*/
9710 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9711 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9713 /* This signal is emitted once decodebin has finished decoding all the data.*/
9714 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9715 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9717 /* This signal is emitted when a element is added to the bin.*/
9718 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9719 G_CALLBACK(__mmplayer_gst_element_added), player);
9726 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9728 MMPlayerGstElement* mainbin = NULL;
9729 GstElement* decodebin = NULL;
9730 GstElement* queue2 = NULL;
9731 GstPad* sinkpad = NULL;
9732 GstPad* qsrcpad = NULL;
9733 gint64 dur_bytes = 0L;
9735 guint max_buffer_size_bytes = 0;
9736 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9739 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9741 mainbin = player->pipeline->mainbin;
9743 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9744 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9745 LOGD("creating http streaming buffering queue(queue2)\n");
9747 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9748 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9750 queue2 = gst_element_factory_make("queue2", "queue2");
9752 LOGE("failed to create buffering queue element\n");
9756 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9757 LOGE("failed to add buffering queue\n");
9761 sinkpad = gst_element_get_static_pad(queue2, "sink");
9762 qsrcpad = gst_element_get_static_pad(queue2, "src");
9764 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9765 LOGE("failed to link buffering queue\n");
9769 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9770 LOGE("fail to get duration.\n");
9772 LOGD("dur_bytes = %lld\n", dur_bytes);
9774 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9776 if (dur_bytes > 0) {
9777 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9778 type = MUXED_BUFFER_TYPE_FILE;
9780 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9781 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9787 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9788 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9789 if (!g_strrstr(player->type, "video/mpegts")) {
9790 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9791 LOGD("max_buffer_size_bytes = %d\n", max_buffer_size_bytes);
9793 // FIXME : pass ini setting directly. is this ok?
9794 __mm_player_streaming_set_queue2(player->streamer,
9797 max_buffer_size_bytes,
9798 player->ini.http_buffering_time,
9800 player->ini.http_buffering_limit, // no meaning
9802 player->http_file_buffering_path,
9803 (guint64)dur_bytes);
9806 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9807 LOGE("failed to sync queue2 state with parent\n");
9813 gst_object_unref(GST_OBJECT(sinkpad));
9815 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9816 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9820 /* create decodebin */
9821 decodebin = __mmplayer_create_decodebin(player);
9824 LOGE("can not create autoplug element\n");
9828 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9829 LOGE("failed to add decodebin\n");
9833 /* to force caps on the decodebin element and avoid reparsing stuff by
9834 * typefind. It also avoids a deadlock in the way typefind activates pads in
9835 * the state change */
9836 g_object_set(decodebin, "sink-caps", caps, NULL);
9838 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9840 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9841 LOGE("failed to link decodebin\n");
9845 gst_object_unref(GST_OBJECT(sinkpad));
9847 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9848 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9850 /* set decodebin property about buffer in streaming playback. *
9851 * in case of HLS/DASH, it does not need to have big buffer *
9852 * because it is kind of adaptive streaming. */
9853 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9854 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9855 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9856 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9858 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9859 || MMPLAYER_IS_DASH_STREAMING(player)) {
9860 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9861 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9864 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9865 "high-percent", (gint)player->ini.http_buffering_limit,
9866 "low-percent", 1, // 1%
9867 "max-size-bytes", max_size_bytes,
9868 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9869 "max-size-buffers", 0, NULL); // disable or automatic
9872 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9873 LOGE("failed to sync decodebin state with parent\n");
9884 gst_object_unref(GST_OBJECT(sinkpad));
9887 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9888 * You need to explicitly set elements to the NULL state before
9889 * dropping the final reference, to allow them to clean up.
9891 gst_element_set_state(queue2, GST_STATE_NULL);
9893 /* And, it still has a parent "player".
9894 * You need to let the parent manage the object instead of unreffing the object directly.
9896 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9897 gst_object_unref(queue2);
9902 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9903 * You need to explicitly set elements to the NULL state before
9904 * dropping the final reference, to allow them to clean up.
9906 gst_element_set_state(decodebin, GST_STATE_NULL);
9908 /* And, it still has a parent "player".
9909 * You need to let the parent manage the object instead of unreffing the object directly.
9912 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9913 gst_object_unref(decodebin);
9921 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9925 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9926 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9928 LOGD("class : %s, mime : %s \n", factory_class, mime);
9930 /* add missing plugin */
9931 /* NOTE : msl should check missing plugin for image mime type.
9932 * Some motion jpeg clips can have playable audio track.
9933 * So, msl have to play audio after displaying popup written video format not supported.
9935 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9936 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9937 LOGD("not found demuxer\n");
9938 player->not_found_demuxer = TRUE;
9939 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9945 if (!g_strrstr(factory_class, "Demuxer")) {
9946 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9947 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9948 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9950 /* check that clip have multi tracks or not */
9951 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9952 LOGD("video plugin is already linked\n");
9954 LOGW("add VIDEO to missing plugin\n");
9955 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9956 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9958 } else if (g_str_has_prefix(mime, "audio")) {
9959 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9960 LOGD("audio plugin is already linked\n");
9962 LOGW("add AUDIO to missing plugin\n");
9963 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9964 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9972 return MM_ERROR_NONE;
9977 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
9979 mm_player_t* player = (mm_player_t*)data;
9983 MMPLAYER_RETURN_IF_FAIL(player);
9985 /* remove fakesink. */
9986 if (!__mmplayer_gst_remove_fakesink(player,
9987 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
9988 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
9989 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
9990 * source element are not same. To overcome this situation, this function will called
9991 * several places and several times. Therefore, this is not an error case.
9996 LOGD("[handle: %p] pipeline has completely constructed", player);
9998 if ((player->ini.async_start) &&
9999 (player->msg_posted == FALSE) &&
10000 (player->cmd >= MMPLAYER_COMMAND_START))
10001 __mmplayer_handle_missed_plugin(player);
10003 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10007 __mmplayer_verify_next_play_path(mm_player_t *player)
10009 MMHandleType attrs = 0;
10010 MMPlayerParseProfile profile;
10011 gint uri_idx = 0, check_cnt = 0;
10013 gint mode = MM_PLAYER_PD_MODE_NONE;
10017 guint num_of_list = 0;
10018 static int profile_tv = -1;
10022 LOGD("checking for gapless play");
10024 if (player->pipeline->textbin) {
10025 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10029 attrs = MMPLAYER_GET_ATTRS(player);
10031 LOGE("fail to get attributes.\n");
10035 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10037 if (__builtin_expect(profile_tv == -1, 0)) {
10039 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10040 switch (*profileName) {
10050 /* gapless playback is not supported in case of video at TV profile. */
10051 if (profile_tv && video) {
10052 LOGW("not support video gapless playback");
10056 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10057 if (mode == TRUE) {
10063 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10064 LOGE("can not get play count\n");
10066 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10067 LOGE("can not get gapless mode\n");
10069 if (video && !gapless) {
10070 LOGW("not enabled video gapless playback");
10074 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10078 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10082 num_of_list = g_list_length(player->uri_info.uri_list);
10084 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10086 if (num_of_list == 0) {
10087 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10088 LOGE("can not get profile_uri\n");
10093 LOGE("uri list is empty.\n");
10097 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10098 LOGD("add original path : %s ", uri);
10104 uri_idx = player->uri_info.uri_idx;
10109 if (check_cnt > num_of_list) {
10110 LOGE("there is no valid uri.");
10114 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10116 if (uri_idx < num_of_list-1) {
10119 if ((count <= 1) && (count != -1)) {
10120 LOGD("no repeat.");
10122 } else if (count > 1) {
10123 /* decrease play count */
10124 /* we succeeded to rewind. update play count and then wait for next EOS */
10127 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10129 /* commit attribute */
10130 if (mmf_attrs_commit(attrs))
10131 LOGE("failed to commit attribute\n");
10134 /* count < 0 : repeat continually */
10138 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10139 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10142 LOGW("next uri does not exist\n");
10146 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10147 LOGE("failed to parse profile\n");
10151 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10152 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10153 LOGW("uri type is not supported(%d).", profile.uri_type);
10160 player->uri_info.uri_idx = uri_idx;
10161 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10163 if (mmf_attrs_commit(player->attrs)) {
10164 LOGE("failed to commit.\n");
10168 LOGD("next uri %s(%d)\n", uri, uri_idx);
10174 LOGE("unable to play next path. EOS will be posted soon.\n");
10179 __mmplayer_initialize_next_play(mm_player_t *player)
10185 player->smooth_streaming = FALSE;
10186 player->videodec_linked = 0;
10187 player->audiodec_linked = 0;
10188 player->videosink_linked = 0;
10189 player->audiosink_linked = 0;
10190 player->textsink_linked = 0;
10191 player->is_external_subtitle_present = FALSE;
10192 player->is_external_subtitle_added_now = FALSE;
10193 player->not_supported_codec = MISSING_PLUGIN_NONE;
10194 player->can_support_codec = FOUND_PLUGIN_NONE;
10195 player->pending_seek.is_pending = FALSE;
10196 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10197 player->pending_seek.pos = 0;
10198 player->msg_posted = FALSE;
10199 player->has_many_types = FALSE;
10200 player->no_more_pad = FALSE;
10201 player->not_found_demuxer = 0;
10202 player->doing_seek = FALSE;
10203 player->max_audio_channels = 0;
10204 player->is_subtitle_force_drop = FALSE;
10205 player->play_subtitle = FALSE;
10206 player->adjust_subtitle_pos = 0;
10208 player->total_bitrate = 0;
10209 player->total_maximum_bitrate = 0;
10211 _mmplayer_track_initialize(player);
10212 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10214 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10215 player->bitrate[i] = 0;
10216 player->maximum_bitrate[i] = 0;
10219 if (player->v_stream_caps) {
10220 gst_caps_unref(player->v_stream_caps);
10221 player->v_stream_caps = NULL;
10224 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10226 /* clean found parsers */
10227 if (player->parsers) {
10228 GList *parsers = player->parsers;
10229 for (; parsers; parsers = g_list_next(parsers)) {
10230 gchar *name = parsers->data;
10231 MMPLAYER_FREEIF(name);
10233 g_list_free(player->parsers);
10234 player->parsers = NULL;
10237 /* clean found audio decoders */
10238 if (player->audio_decoders) {
10239 GList *a_dec = player->audio_decoders;
10240 for (; a_dec; a_dec = g_list_next(a_dec)) {
10241 gchar *name = a_dec->data;
10242 MMPLAYER_FREEIF(name);
10244 g_list_free(player->audio_decoders);
10245 player->audio_decoders = NULL;
10252 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10254 MMPlayerGstElement *mainbin = NULL;
10255 MMMessageParamType msg_param = {0,};
10256 GstElement *element = NULL;
10257 MMHandleType attrs = 0;
10259 enum MainElementID elemId = MMPLAYER_M_NUM;
10263 if ((player == NULL) ||
10264 (player->pipeline == NULL) ||
10265 (player->pipeline->mainbin == NULL)) {
10266 LOGE("player is null.\n");
10270 mainbin = player->pipeline->mainbin;
10271 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10273 attrs = MMPLAYER_GET_ATTRS(player);
10275 LOGE("fail to get attributes.\n");
10279 /* Initialize Player values */
10280 __mmplayer_initialize_next_play(player);
10282 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10284 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10285 LOGE("failed to parse profile\n");
10286 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10290 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10291 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10292 LOGE("it's dash or hls. not support.");
10293 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10298 switch (player->profile.uri_type) {
10300 case MM_PLAYER_URI_TYPE_FILE:
10302 LOGD("using filesrc for 'file://' handler.\n");
10303 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10304 LOGE("failed to get storage info");
10308 element = gst_element_factory_make("filesrc", "source");
10311 LOGE("failed to create filesrc\n");
10315 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10318 case MM_PLAYER_URI_TYPE_URL_HTTP:
10320 gchar *user_agent, *cookies, **cookie_list;
10321 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10322 user_agent = cookies = NULL;
10323 cookie_list = NULL;
10325 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10327 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10330 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10332 /* get attribute */
10333 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10334 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10336 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10337 LOGD("get timeout from ini\n");
10338 http_timeout = player->ini.http_timeout;
10341 /* get attribute */
10342 SECURE_LOGD("location : %s\n", player->profile.uri);
10343 SECURE_LOGD("cookies : %s\n", cookies);
10344 SECURE_LOGD("user_agent : %s\n", user_agent);
10345 LOGD("timeout : %d\n", http_timeout);
10347 /* setting property to streaming source */
10348 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10349 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10350 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10352 /* parsing cookies */
10353 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10354 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10356 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10360 LOGE("not support uri type %d\n", player->profile.uri_type);
10365 LOGE("no source element was created.\n");
10369 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10370 LOGE("failed to add source element to pipeline\n");
10371 gst_object_unref(GST_OBJECT(element));
10376 /* take source element */
10377 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10378 mainbin[MMPLAYER_M_SRC].gst = element;
10382 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10383 if (player->streamer == NULL) {
10384 player->streamer = __mm_player_streaming_create();
10385 __mm_player_streaming_initialize(player->streamer);
10388 elemId = MMPLAYER_M_TYPEFIND;
10389 element = gst_element_factory_make("typefind", "typefinder");
10390 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10391 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10393 elemId = MMPLAYER_M_AUTOPLUG;
10394 element = __mmplayer_create_decodebin(player);
10397 /* check autoplug element is OK */
10399 LOGE("can not create element(%d)\n", elemId);
10403 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10404 LOGE("failed to add sinkbin to pipeline\n");
10405 gst_object_unref(GST_OBJECT(element));
10410 mainbin[elemId].id = elemId;
10411 mainbin[elemId].gst = element;
10413 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10414 LOGE("Failed to link src - autoplug(or typefind)\n");
10418 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10419 LOGE("Failed to change state of src element\n");
10423 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10424 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10425 LOGE("Failed to change state of decodebin\n");
10429 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10430 LOGE("Failed to change state of src element\n");
10435 player->gapless.stream_changed = TRUE;
10436 player->gapless.running = TRUE;
10442 MMPLAYER_PLAYBACK_UNLOCK(player);
10444 if (!player->msg_posted) {
10445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10446 player->msg_posted = TRUE;
10453 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10455 mm_player_selector_t *selector = &player->selector[type];
10456 MMPlayerGstElement *sinkbin = NULL;
10457 enum MainElementID selectorId = MMPLAYER_M_NUM;
10458 enum MainElementID sinkId = MMPLAYER_M_NUM;
10459 GstPad *srcpad = NULL;
10460 GstPad *sinkpad = NULL;
10461 gboolean send_notice = FALSE;
10464 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10466 LOGD("type %d", type);
10469 case MM_PLAYER_TRACK_TYPE_AUDIO:
10470 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10471 sinkId = MMPLAYER_A_BIN;
10472 sinkbin = player->pipeline->audiobin;
10474 case MM_PLAYER_TRACK_TYPE_VIDEO:
10475 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10476 sinkId = MMPLAYER_V_BIN;
10477 sinkbin = player->pipeline->videobin;
10478 send_notice = TRUE;
10480 case MM_PLAYER_TRACK_TYPE_TEXT:
10481 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10482 sinkId = MMPLAYER_T_BIN;
10483 sinkbin = player->pipeline->textbin;
10486 LOGE("requested type is not supportable");
10491 if (player->pipeline->mainbin[selectorId].gst) {
10494 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10496 if (selector->event_probe_id != 0)
10497 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10498 selector->event_probe_id = 0;
10500 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10501 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10503 if (srcpad && sinkpad) {
10504 /* after getting drained signal there is no data flows, so no need to do pad_block */
10505 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10506 gst_pad_unlink(srcpad, sinkpad);
10508 /* send custom event to sink pad to handle it at video sink */
10510 LOGD("send custom event to sinkpad");
10511 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10512 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10513 gst_pad_send_event(sinkpad, event);
10517 gst_object_unref(sinkpad);
10520 gst_object_unref(srcpad);
10523 LOGD("selector release");
10525 /* release and unref requests pad from the selector */
10526 for (n = 0; n < selector->channels->len; n++) {
10527 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10528 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10530 g_ptr_array_set_size(selector->channels, 0);
10532 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10533 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10535 player->pipeline->mainbin[selectorId].gst = NULL;
10543 __mmplayer_deactivate_old_path(mm_player_t *player)
10546 MMPLAYER_RETURN_IF_FAIL(player);
10548 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10549 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10550 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10551 LOGE("deactivate selector error");
10555 _mmplayer_track_destroy(player);
10556 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10558 if (player->streamer) {
10559 __mm_player_streaming_deinitialize(player->streamer);
10560 __mm_player_streaming_destroy(player->streamer);
10561 player->streamer = NULL;
10564 MMPLAYER_PLAYBACK_LOCK(player);
10565 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10572 if (!player->msg_posted) {
10573 MMMessageParamType msg = {0,};
10576 msg.code = MM_ERROR_PLAYER_INTERNAL;
10577 LOGE("next_uri_play> deactivate error");
10579 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10580 player->msg_posted = TRUE;
10585 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10587 int result = MM_ERROR_NONE;
10588 mm_player_t* player = (mm_player_t*) hplayer;
10591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10594 player->http_file_buffering_path = (gchar*)file_path;
10595 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10601 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10603 int result = MM_ERROR_NONE;
10604 mm_player_t* player = (mm_player_t*) hplayer;
10607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10609 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10610 if (mmf_attrs_commit(player->attrs)) {
10611 LOGE("failed to commit the original uri.\n");
10612 result = MM_ERROR_PLAYER_INTERNAL;
10614 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10615 LOGE("failed to add the original uri in the uri list.\n");
10622 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10624 mm_player_t* player = (mm_player_t*) hplayer;
10625 guint num_of_list = 0;
10629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10630 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10632 if (player->pipeline && player->pipeline->textbin) {
10633 LOGE("subtitle path is enabled.\n");
10634 return MM_ERROR_PLAYER_INVALID_STATE;
10637 num_of_list = g_list_length(player->uri_info.uri_list);
10639 if (is_first_path == TRUE) {
10640 if (num_of_list == 0) {
10641 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10642 LOGD("add original path : %s", uri);
10644 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10645 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10647 LOGD("change original path : %s", uri);
10650 MMHandleType attrs = 0;
10651 attrs = MMPLAYER_GET_ATTRS(player);
10653 if (num_of_list == 0) {
10654 char *original_uri = NULL;
10657 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10659 if (!original_uri) {
10660 LOGE("there is no original uri.");
10661 return MM_ERROR_PLAYER_INVALID_STATE;
10664 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10665 player->uri_info.uri_idx = 0;
10667 LOGD("add original path at first : %s(%d)", original_uri);
10671 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10672 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10676 return MM_ERROR_NONE;
10679 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10681 mm_player_t* player = (mm_player_t*) hplayer;
10682 char *next_uri = NULL;
10683 guint num_of_list = 0;
10686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10688 num_of_list = g_list_length(player->uri_info.uri_list);
10690 if (num_of_list > 0) {
10691 gint uri_idx = player->uri_info.uri_idx;
10693 if (uri_idx < num_of_list-1)
10698 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10699 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10701 *uri = g_strdup(next_uri);
10705 return MM_ERROR_NONE;
10709 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10710 GstCaps *caps, gpointer data)
10712 mm_player_t* player = (mm_player_t*)data;
10713 const gchar* klass = NULL;
10714 const gchar* mime = NULL;
10715 gchar* caps_str = NULL;
10717 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10718 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10719 caps_str = gst_caps_to_string(caps);
10721 LOGW("unknown type of caps : %s from %s",
10722 caps_str, GST_ELEMENT_NAME(elem));
10724 MMPLAYER_FREEIF(caps_str);
10726 /* There is no available codec. */
10727 __mmplayer_check_not_supported_codec(player, klass, mime);
10731 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10732 GstCaps * caps, gpointer data)
10734 mm_player_t* player = (mm_player_t*)data;
10735 const char* mime = NULL;
10736 gboolean ret = TRUE;
10738 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10739 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10741 if (g_str_has_prefix(mime, "audio")) {
10742 GstStructure* caps_structure = NULL;
10743 gint samplerate = 0;
10745 gchar *caps_str = NULL;
10747 caps_structure = gst_caps_get_structure(caps, 0);
10748 gst_structure_get_int(caps_structure, "rate", &samplerate);
10749 gst_structure_get_int(caps_structure, "channels", &channels);
10751 if ((channels > 0 && samplerate == 0)) {
10752 LOGD("exclude audio...");
10756 caps_str = gst_caps_to_string(caps);
10757 /* set it directly because not sent by TAG */
10758 if (g_strrstr(caps_str, "mobile-xmf"))
10759 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10760 MMPLAYER_FREEIF(caps_str);
10761 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10762 MMMessageParamType msg_param;
10763 memset(&msg_param, 0, sizeof(MMMessageParamType));
10764 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10765 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10766 LOGD("video file is not supported on this device");
10768 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10769 LOGD("already video linked");
10772 LOGD("found new stream");
10779 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10781 int ret = MM_ERROR_NONE;
10783 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10785 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10786 GstStructure* str = NULL;
10788 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10790 LOGD("audio codec type: %d", codec_type);
10791 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10792 /* sw codec will be skipped */
10793 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10794 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10795 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10796 ret = MM_ERROR_PLAYER_INTERNAL;
10800 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10801 /* hw codec will be skipped */
10802 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10803 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10804 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10805 ret = MM_ERROR_PLAYER_INTERNAL;
10810 str = gst_caps_get_structure(caps, 0);
10812 gst_structure_get_int(str, "channels", &channels);
10814 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10815 if (player->max_audio_channels < channels)
10816 player->max_audio_channels = channels;
10818 /* set stream information */
10819 if (!player->audiodec_linked)
10820 __mmplayer_set_audio_attrs(player, caps);
10822 /* update codec info */
10823 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10824 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10825 player->audiodec_linked = 1;
10827 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10829 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10831 LOGD("video codec type: %d", codec_type);
10832 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10833 /* sw codec is skipped */
10834 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10835 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10836 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10837 ret = MM_ERROR_PLAYER_INTERNAL;
10841 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10842 /* hw codec is skipped */
10843 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10844 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10845 ret = MM_ERROR_PLAYER_INTERNAL;
10850 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10851 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10853 /* mark video decoder for acquire */
10854 if (player->video_decoder_resource == NULL) {
10855 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10856 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10857 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10858 &player->video_decoder_resource)
10859 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10860 LOGE("could not mark video_decoder resource for acquire");
10861 ret = MM_ERROR_PLAYER_INTERNAL;
10865 LOGW("video decoder resource is already acquired, skip it.");
10866 ret = MM_ERROR_PLAYER_INTERNAL;
10870 player->interrupted_by_resource = FALSE;
10871 /* acquire resources for video playing */
10872 if (mm_resource_manager_commit(player->resource_manager)
10873 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10874 LOGE("could not acquire resources for video decoding\n");
10875 ret = MM_ERROR_PLAYER_INTERNAL;
10880 /* update codec info */
10881 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10882 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10883 player->videodec_linked = 1;
10891 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10892 GstCaps* caps, GstElementFactory* factory, gpointer data)
10894 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10895 We are defining our own and will be removed when it actually exposed */
10897 GST_AUTOPLUG_SELECT_TRY,
10898 GST_AUTOPLUG_SELECT_EXPOSE,
10899 GST_AUTOPLUG_SELECT_SKIP
10900 } GstAutoplugSelectResult;
10902 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10903 mm_player_t* player = (mm_player_t*)data;
10905 gchar* factory_name = NULL;
10906 gchar* caps_str = NULL;
10907 const gchar* klass = NULL;
10910 factory_name = GST_OBJECT_NAME(factory);
10911 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10912 caps_str = gst_caps_to_string(caps);
10914 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10916 /* store type string */
10917 if (player->type == NULL) {
10918 player->type = gst_caps_to_string(caps);
10919 __mmplayer_update_content_type_info(player);
10922 /* filtering exclude keyword */
10923 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10924 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10925 LOGW("skipping [%s] by exculde keyword [%s]\n",
10926 factory_name, player->ini.exclude_element_keyword[idx]);
10928 result = GST_AUTOPLUG_SELECT_SKIP;
10933 /* exclude webm format */
10934 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10935 * because webm format is not supportable.
10936 * If webm is disabled in "autoplug-continue", there is no state change
10937 * failure or error because the decodebin will expose the pad directly.
10938 * It make MSL invoke _prepare_async_callback.
10939 * So, we need to disable webm format in "autoplug-select" */
10940 if (caps_str && strstr(caps_str, "webm")) {
10941 LOGW("webm is not supported");
10942 result = GST_AUTOPLUG_SELECT_SKIP;
10946 /* check factory class for filtering */
10947 /* NOTE : msl don't need to use image plugins.
10948 * So, those plugins should be skipped for error handling.
10950 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10951 LOGD("skipping [%s] by not required\n", factory_name);
10952 result = GST_AUTOPLUG_SELECT_SKIP;
10956 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10957 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10958 // TO CHECK : subtitle if needed, add subparse exception.
10959 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10960 result = GST_AUTOPLUG_SELECT_SKIP;
10964 if (g_strrstr(factory_name, "mpegpsdemux")) {
10965 LOGD("skipping PS container - not support\n");
10966 result = GST_AUTOPLUG_SELECT_SKIP;
10970 if (g_strrstr(factory_name, "mssdemux"))
10971 player->smooth_streaming = TRUE;
10973 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10974 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10977 GstStructure *str = NULL;
10978 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
10980 /* don't make video because of not required */
10981 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
10982 (player->set_mode.media_packet_video_stream == FALSE)) {
10983 LOGD("no video because it's not required. -> return expose");
10984 result = GST_AUTOPLUG_SELECT_EXPOSE;
10988 /* get w/h for omx state-tune */
10989 /* FIXME: deprecated? */
10990 str = gst_caps_get_structure(caps, 0);
10991 gst_structure_get_int(str, "width", &width);
10994 if (player->v_stream_caps) {
10995 gst_caps_unref(player->v_stream_caps);
10996 player->v_stream_caps = NULL;
10999 player->v_stream_caps = gst_caps_copy(caps);
11000 LOGD("take caps for video state tune");
11001 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11005 if (g_strrstr(klass, "Codec/Decoder")) {
11006 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11007 LOGD("skipping %s codec", factory_name);
11008 result = GST_AUTOPLUG_SELECT_SKIP;
11014 MMPLAYER_FREEIF(caps_str);
11020 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11023 //mm_player_t* player = (mm_player_t*)data;
11024 GstCaps* caps = NULL;
11026 LOGD("[Decodebin2] pad-removed signal\n");
11028 caps = gst_pad_query_caps(new_pad, NULL);
11030 gchar* caps_str = NULL;
11031 caps_str = gst_caps_to_string(caps);
11033 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11035 MMPLAYER_FREEIF(caps_str);
11036 gst_caps_unref(caps);
11041 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11043 mm_player_t* player = (mm_player_t*)data;
11044 GstIterator *iter = NULL;
11045 GValue item = { 0, };
11046 GstPad *pad = NULL;
11047 gboolean done = FALSE;
11048 gboolean is_all_drained = TRUE;
11051 MMPLAYER_RETURN_IF_FAIL(player);
11053 LOGD("__mmplayer_gst_decode_drained");
11055 if (player->use_deinterleave == TRUE) {
11056 LOGD("group playing mode.");
11060 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11061 LOGW("Fail to get cmd lock");
11065 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11066 !__mmplayer_verify_next_play_path(player)) {
11067 LOGD("decoding is finished.");
11068 __mmplayer_reset_gapless_state(player);
11069 MMPLAYER_CMD_UNLOCK(player);
11073 player->gapless.reconfigure = TRUE;
11075 /* check decodebin src pads whether they received EOS or not */
11076 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11079 switch (gst_iterator_next(iter, &item)) {
11080 case GST_ITERATOR_OK:
11081 pad = g_value_get_object(&item);
11082 if (pad && !GST_PAD_IS_EOS(pad)) {
11083 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11084 is_all_drained = FALSE;
11087 g_value_reset(&item);
11089 case GST_ITERATOR_RESYNC:
11090 gst_iterator_resync(iter);
11092 case GST_ITERATOR_ERROR:
11093 case GST_ITERATOR_DONE:
11098 g_value_unset(&item);
11099 gst_iterator_free(iter);
11101 if (!is_all_drained) {
11102 LOGD("Wait util the all pads get EOS.");
11103 MMPLAYER_CMD_UNLOCK(player);
11108 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11109 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11111 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11112 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11113 __mmplayer_deactivate_old_path(player);
11114 MMPLAYER_CMD_UNLOCK(player);
11120 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11122 mm_player_t* player = (mm_player_t*)data;
11123 const gchar* klass = NULL;
11124 gchar* factory_name = NULL;
11126 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11127 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11129 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11131 if (__mmplayer_add_dump_buffer_probe(player, element))
11132 LOGD("add buffer probe");
11135 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11136 gchar* selected = NULL;
11137 selected = g_strdup(GST_ELEMENT_NAME(element));
11138 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11142 if (g_strrstr(klass, "Parser")) {
11143 gchar* selected = NULL;
11145 selected = g_strdup(factory_name);
11146 player->parsers = g_list_append(player->parsers, selected);
11149 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11150 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11151 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11153 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11154 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11156 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11157 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11158 "max-video-width", player->adaptive_info.limit.width,
11159 "max-video-height", player->adaptive_info.limit.height, NULL);
11161 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11162 /* FIXIT : first value will be overwritten if there's more
11163 * than 1 demuxer/parser
11166 //LOGD("plugged element is demuxer. take it\n");
11167 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11168 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11170 /*Added for multi audio support */ // Q. del?
11171 if (g_strrstr(klass, "Demux")) {
11172 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11173 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11177 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11178 int surface_type = 0;
11180 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11183 // to support trust-zone only
11184 if (g_strrstr(factory_name, "asfdemux")) {
11185 LOGD("set file-location %s\n", player->profile.uri);
11186 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11188 if (player->video_hub_download_mode == TRUE)
11189 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11190 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11191 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11192 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11193 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11194 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11195 (__mmplayer_is_only_mp3_type(player->type))) {
11196 LOGD("[mpegaudioparse] set streaming pull mode.");
11197 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11199 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11200 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11203 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11204 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11205 LOGD("plugged element is multiqueue. take it\n");
11207 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11208 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11210 if (!MMPLAYER_IS_HTTP_PD(player) &&
11211 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11212 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11213 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11214 __mm_player_streaming_set_multiqueue(player->streamer,
11217 player->ini.http_buffering_time,
11219 player->ini.http_buffering_limit);
11221 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11228 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11231 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11233 if (MMPLAYER_IS_STREAMING(player))
11236 /* This callback can be set to music player only. */
11237 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11238 LOGW("audio callback is not supported for video");
11242 if (player->audio_stream_cb) {
11243 GstPad *pad = NULL;
11245 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11248 LOGE("failed to get sink pad from audiosink to probe data\n");
11251 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11252 __mmplayer_audio_stream_probe, player, NULL);
11254 gst_object_unref(pad);
11258 LOGE("There is no audio callback to configure.\n");
11268 __mmplayer_release_misc(mm_player_t* player)
11271 bool cur_mode = player->set_mode.rich_audio;
11274 MMPLAYER_RETURN_IF_FAIL(player);
11276 player->video_stream_cb = NULL;
11277 player->video_stream_cb_user_param = NULL;
11278 player->video_stream_prerolled = FALSE;
11280 player->audio_stream_cb = NULL;
11281 player->audio_stream_render_cb_ex = NULL;
11282 player->audio_stream_cb_user_param = NULL;
11283 player->audio_stream_sink_sync = false;
11285 player->video_stream_changed_cb = NULL;
11286 player->video_stream_changed_cb_user_param = NULL;
11288 player->audio_stream_changed_cb = NULL;
11289 player->audio_stream_changed_cb_user_param = NULL;
11291 player->sent_bos = FALSE;
11292 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11294 player->doing_seek = FALSE;
11296 player->total_bitrate = 0;
11297 player->total_maximum_bitrate = 0;
11299 player->not_found_demuxer = 0;
11301 player->last_position = 0;
11302 player->duration = 0;
11303 player->http_content_size = 0;
11304 player->not_supported_codec = MISSING_PLUGIN_NONE;
11305 player->can_support_codec = FOUND_PLUGIN_NONE;
11306 player->pending_seek.is_pending = FALSE;
11307 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11308 player->pending_seek.pos = 0;
11309 player->msg_posted = FALSE;
11310 player->has_many_types = FALSE;
11311 player->max_audio_channels = 0;
11312 player->video_share_api_delta = 0;
11313 player->video_share_clock_delta = 0;
11314 player->is_subtitle_force_drop = FALSE;
11315 player->play_subtitle = FALSE;
11316 player->adjust_subtitle_pos = 0;
11317 player->last_multiwin_status = FALSE;
11318 player->has_closed_caption = FALSE;
11319 player->set_mode.media_packet_video_stream = FALSE;
11320 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11321 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11323 player->set_mode.rich_audio = cur_mode;
11325 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11326 player->bitrate[i] = 0;
11327 player->maximum_bitrate[i] = 0;
11330 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11332 /* remove media stream cb(appsrc cb) */
11333 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11334 player->media_stream_buffer_status_cb[i] = NULL;
11335 player->media_stream_seek_data_cb[i] = NULL;
11336 player->buffer_cb_user_param[i] = NULL;
11337 player->seek_cb_user_param[i] = NULL;
11339 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11341 /* free memory related to audio effect */
11342 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11344 if (player->adaptive_info.var_list) {
11345 g_list_free_full(player->adaptive_info.var_list, g_free);
11346 player->adaptive_info.var_list = NULL;
11349 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11350 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11351 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11353 /* Reset video360 settings to their defaults in case if the pipeline is to be
11356 player->video360_metadata.is_spherical = -1;
11357 player->is_openal_plugin_used = FALSE;
11359 player->is_content_spherical = FALSE;
11360 player->is_video360_enabled = TRUE;
11361 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11362 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11363 player->video360_yaw_radians = 4;
11364 player->video360_pitch_radians = 4;
11365 player->video360_zoom = 1.0f;
11366 player->video360_horizontal_fov = 0;
11367 player->video360_vertical_fov = 0;
11369 player->sound.rg_enable = false;
11375 __mmplayer_release_misc_post(mm_player_t* player)
11377 char *original_uri = NULL;
11380 /* player->pipeline is already released before. */
11382 MMPLAYER_RETURN_IF_FAIL(player);
11384 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11386 /* clean found parsers */
11387 if (player->parsers) {
11388 GList *parsers = player->parsers;
11389 for (; parsers; parsers = g_list_next(parsers)) {
11390 gchar *name = parsers->data;
11391 MMPLAYER_FREEIF(name);
11393 g_list_free(player->parsers);
11394 player->parsers = NULL;
11397 /* clean found audio decoders */
11398 if (player->audio_decoders) {
11399 GList *a_dec = player->audio_decoders;
11400 for (; a_dec; a_dec = g_list_next(a_dec)) {
11401 gchar *name = a_dec->data;
11402 MMPLAYER_FREEIF(name);
11404 g_list_free(player->audio_decoders);
11405 player->audio_decoders = NULL;
11408 /* clean the uri list except original uri */
11409 if (player->uri_info.uri_list) {
11410 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11412 if (player->attrs) {
11413 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11414 LOGD("restore original uri = %s\n", original_uri);
11416 if (mmf_attrs_commit(player->attrs))
11417 LOGE("failed to commit the original uri.\n");
11420 GList *uri_list = player->uri_info.uri_list;
11421 for (; uri_list; uri_list = g_list_next(uri_list)) {
11422 gchar *uri = uri_list->data;
11423 MMPLAYER_FREEIF(uri);
11425 g_list_free(player->uri_info.uri_list);
11426 player->uri_info.uri_list = NULL;
11429 /* clear the audio stream buffer list */
11430 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11432 /* clear the video stream bo list */
11433 __mmplayer_video_stream_destroy_bo_list(player);
11434 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11436 if (player->profile.input_mem.buf) {
11437 free(player->profile.input_mem.buf);
11438 player->profile.input_mem.buf = NULL;
11440 player->profile.input_mem.len = 0;
11441 player->profile.input_mem.offset = 0;
11443 player->uri_info.uri_idx = 0;
11447 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11449 GstElement *element = NULL;
11452 LOGD("creating %s to plug\n", name);
11454 element = gst_element_factory_make(name, NULL);
11456 LOGE("failed to create queue\n");
11460 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11461 LOGE("failed to set state READY to %s\n", name);
11462 gst_object_unref(element);
11466 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11467 LOGE("failed to add %s\n", name);
11468 gst_object_unref(element);
11472 sinkpad = gst_element_get_static_pad(element, "sink");
11474 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11475 LOGE("failed to link %s\n", name);
11476 gst_object_unref(sinkpad);
11477 gst_object_unref(element);
11481 LOGD("linked %s to pipeline successfully\n", name);
11483 gst_object_unref(sinkpad);
11489 __mmplayer_check_subtitle(mm_player_t* player)
11491 MMHandleType attrs = 0;
11492 char *subtitle_uri = NULL;
11496 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11498 /* get subtitle attribute */
11499 attrs = MMPLAYER_GET_ATTRS(player);
11503 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11504 if (!subtitle_uri || !strlen(subtitle_uri))
11507 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11508 player->is_external_subtitle_present = TRUE;
11516 __mmplayer_can_extract_pcm(mm_player_t* player)
11518 MMHandleType attrs = 0;
11519 gboolean sound_extraction = FALSE;
11521 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11523 attrs = MMPLAYER_GET_ATTRS(player);
11525 LOGE("fail to get attributes.");
11529 /* get sound_extraction property */
11530 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11532 if (!sound_extraction) {
11533 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11541 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11544 MMMessageParamType msg_param;
11545 gchar *msg_src_element = NULL;
11546 GstStructure *s = NULL;
11547 guint error_id = 0;
11548 gchar *error_string = NULL;
11552 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11553 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11555 s = gst_structure_copy(gst_message_get_structure(message));
11558 if (!gst_structure_get_uint(s, "error_id", &error_id))
11559 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11561 switch (error_id) {
11562 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11563 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11565 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11566 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11568 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11569 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11571 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11572 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11574 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11575 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11577 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11578 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11580 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11581 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11583 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11584 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11586 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11587 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11589 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11590 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11592 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11593 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11595 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11596 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11598 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11599 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11601 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11602 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11604 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11605 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11607 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11608 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11610 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11611 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11613 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11614 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11616 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11617 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11619 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11620 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11622 case MMPLAYER_STREAMING_ERROR_GONE:
11623 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11625 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11626 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11628 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11629 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11631 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11632 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11634 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11635 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11637 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11638 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11640 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11641 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11643 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11644 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11646 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11647 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11649 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11650 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11652 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11653 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11655 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11656 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11658 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11659 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11661 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11662 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11664 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11665 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11667 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11668 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11670 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11671 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11673 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11674 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11676 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11677 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11679 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11680 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11682 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11683 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11685 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11686 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11688 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11689 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11691 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11692 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11694 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11695 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11699 gst_structure_free(s);
11700 return MM_ERROR_PLAYER_STREAMING_FAIL;
11704 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11706 msg_param.data = (void *) error_string;
11708 if (message->src) {
11709 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11711 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11712 msg_src_element, msg_param.code, (char*)msg_param.data);
11715 /* post error to application */
11716 if (!player->msg_posted) {
11717 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11719 /* don't post more if one was sent already */
11720 player->msg_posted = TRUE;
11722 LOGD("skip error post because it's sent already.\n");
11724 gst_structure_free(s);
11726 g_free(error_string);
11733 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11735 MMPLAYER_RETURN_IF_FAIL(player);
11737 /* post now if delay is zero */
11738 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11739 LOGD("eos delay is zero. posting EOS now\n");
11740 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11742 if (player->set_mode.pcm_extraction)
11743 __mmplayer_cancel_eos_timer(player);
11748 /* cancel if existing */
11749 __mmplayer_cancel_eos_timer(player);
11751 /* init new timeout */
11752 /* NOTE : consider give high priority to this timer */
11753 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11755 player->eos_timer = g_timeout_add(delay_in_ms,
11756 __mmplayer_eos_timer_cb, player);
11758 player->global_default = g_main_context_default();
11759 LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
11761 /* check timer is valid. if not, send EOS now */
11762 if (player->eos_timer == 0) {
11763 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11764 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11769 __mmplayer_cancel_eos_timer(mm_player_t* player)
11771 MMPLAYER_RETURN_IF_FAIL(player);
11773 if (player->eos_timer) {
11774 LOGD("cancel eos timer");
11775 __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
11776 player->eos_timer = 0;
11783 __mmplayer_eos_timer_cb(gpointer u_data)
11785 mm_player_t* player = NULL;
11786 MMHandleType attrs = 0;
11789 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11791 player = (mm_player_t*) u_data;
11792 attrs = MMPLAYER_GET_ATTRS(player);
11794 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11797 gint ret_value = 0;
11798 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11799 if (ret_value != MM_ERROR_NONE)
11800 LOGE("seeking to 0 failed in repeat play");
11803 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11806 /* we are returning FALSE as we need only one posting */
11810 /* sending event to one of sinkelements */
11812 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11814 GstEvent * event2 = NULL;
11815 GList *sinks = NULL;
11816 gboolean res = FALSE;
11819 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11820 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11822 /* While adding subtitles in live feeds seek is getting called.
11823 Adding defensive check in framework layer.*/
11824 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11825 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11826 LOGE("Should not send seek event during live playback");
11831 if (player->play_subtitle)
11832 event2 = gst_event_copy((const GstEvent *)event);
11834 sinks = player->sink_elements;
11836 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11838 if (GST_IS_ELEMENT(sink)) {
11839 /* keep ref to the event */
11840 gst_event_ref(event);
11842 if ((res = gst_element_send_event(sink, event))) {
11843 LOGD("sending event[%s] to sink element [%s] success!\n",
11844 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11846 /* rtsp case, asyn_done is not called after seek during pause state */
11847 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11848 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11849 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11850 LOGD("RTSP seek completed, after pause state..\n");
11851 player->doing_seek = FALSE;
11852 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11858 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11859 sinks = g_list_next(sinks);
11866 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11867 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11870 sinks = g_list_next(sinks);
11873 /* Note : Textbin is not linked to the video or audio bin.
11874 * It needs to send the event to the text sink seperatelly.
11876 if (player->play_subtitle && player->pipeline) {
11877 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11879 if (GST_IS_ELEMENT(text_sink)) {
11880 /* keep ref to the event */
11881 gst_event_ref(event2);
11883 if ((res = gst_element_send_event(text_sink, event2)))
11884 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11885 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11887 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11888 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11890 gst_event_unref(event2);
11894 gst_event_unref(event);
11902 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11906 MMPLAYER_RETURN_IF_FAIL(player);
11907 MMPLAYER_RETURN_IF_FAIL(sink);
11909 player->sink_elements =
11910 g_list_append(player->sink_elements, sink);
11916 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11920 MMPLAYER_RETURN_IF_FAIL(player);
11921 MMPLAYER_RETURN_IF_FAIL(sink);
11923 player->sink_elements =
11924 g_list_remove(player->sink_elements, sink);
11930 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11931 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11932 gint64 cur, GstSeekType stop_type, gint64 stop)
11934 GstEvent* event = NULL;
11935 gboolean result = FALSE;
11939 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11941 if (player->pipeline && player->pipeline->textbin)
11942 __mmplayer_drop_subtitle(player, FALSE);
11944 event = gst_event_new_seek(rate, format, flags, cur_type,
11945 cur, stop_type, stop);
11947 result = __gst_send_event_to_sink(player, event);
11954 /* NOTE : be careful with calling this api. please refer to below glib comment
11955 * glib comment : Note that there is a bug in GObject that makes this function much
11956 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11957 * will no longer be called, but, the signal handler is not currently disconnected.
11958 * If the instance is itself being freed at the same time than this doesn't matter,
11959 * since the signal will automatically be removed, but if instance persists,
11960 * then the signal handler will leak. You should not remove the signal yourself
11961 * because in a future versions of GObject, the handler will automatically be
11964 * It's possible to work around this problem in a way that will continue to work
11965 * with future versions of GObject by checking that the signal handler is still
11966 * connected before disconnected it:
11968 * if (g_signal_handler_is_connected(instance, id))
11969 * g_signal_handler_disconnect(instance, id);
11972 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11974 GList* sig_list = NULL;
11975 MMPlayerSignalItem* item = NULL;
11979 MMPLAYER_RETURN_IF_FAIL(player);
11981 LOGD("release signals type : %d", type);
11983 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
11984 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
11985 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
11986 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
11987 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
11988 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
11992 sig_list = player->signals[type];
11994 for (; sig_list; sig_list = sig_list->next) {
11995 item = sig_list->data;
11997 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
11998 if (g_signal_handler_is_connected(item->obj, item->sig))
11999 g_signal_handler_disconnect(item->obj, item->sig);
12002 MMPLAYER_FREEIF(item);
12005 g_list_free(player->signals[type]);
12006 player->signals[type] = NULL;
12013 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12015 mm_player_t* player = 0;
12016 int prev_display_surface_type = 0;
12017 void *prev_display_overlay = NULL;
12018 const gchar *klass = NULL;
12019 gchar *cur_videosink_name = NULL;
12022 int num_of_dec = 2; /* DEC1, DEC2 */
12026 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12027 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12029 player = MM_PLAYER_CAST(handle);
12031 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12032 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12034 return MM_ERROR_INVALID_ARGUMENT;
12037 /* load previous attributes */
12038 if (player->attrs) {
12039 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12040 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12041 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12042 if (prev_display_surface_type == surface_type) {
12043 LOGD("incoming display surface type is same as previous one, do nothing..");
12045 return MM_ERROR_NONE;
12048 LOGE("failed to load attributes");
12050 return MM_ERROR_PLAYER_INTERNAL;
12053 /* check videosink element is created */
12054 if (!player->pipeline || !player->pipeline->videobin ||
12055 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12056 LOGD("videosink element is not yet ready");
12058 /* videobin is not created yet, so we just set attributes related to display surface */
12059 LOGD("store display attribute for given surface type(%d)", surface_type);
12060 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12061 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12062 if (mmf_attrs_commit(player->attrs)) {
12063 LOGE("failed to commit attribute");
12065 return MM_ERROR_PLAYER_INTERNAL;
12068 return MM_ERROR_NONE;
12070 /* get player command status */
12071 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12072 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12074 return MM_ERROR_PLAYER_INVALID_STATE;
12077 /* surface change */
12078 for (i = 0 ; i < num_of_dec ; i++) {
12079 if (player->pipeline->mainbin &&
12080 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12081 GstElementFactory *decfactory;
12082 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12084 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12085 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12086 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12087 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12091 LOGW("success to changing display surface(%d)", surface_type);
12093 return MM_ERROR_NONE;
12095 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12096 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12100 LOGW("success to changing display surface(%d)", surface_type);
12102 return MM_ERROR_NONE;
12105 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12106 ret = MM_ERROR_PLAYER_INTERNAL;
12115 /* rollback to previous attributes */
12116 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12117 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12118 if (mmf_attrs_commit(player->attrs)) {
12119 LOGE("failed to commit attributes to rollback");
12121 return MM_ERROR_PLAYER_INTERNAL;
12127 /* NOTE : It does not support some use cases, eg using colorspace converter */
12129 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12131 GstPad *src_pad_dec = NULL;
12132 GstPad *sink_pad_videosink = NULL;
12133 GstPad *sink_pad_videobin = NULL;
12134 GstClock *clock = NULL;
12135 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12136 int ret = MM_ERROR_NONE;
12137 gboolean is_audiobin_created = TRUE;
12141 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12142 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12143 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12145 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12146 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12148 /* get information whether if audiobin is created */
12149 if (!player->pipeline->audiobin ||
12150 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12151 LOGW("audiobin is null, this video content may not have audio data");
12152 is_audiobin_created = FALSE;
12155 /* get current state of player */
12156 previous_state = MMPLAYER_CURRENT_STATE(player);
12157 LOGD("previous state(%d)", previous_state);
12160 /* get src pad of decoder and block it */
12161 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12162 if (!src_pad_dec) {
12163 LOGE("failed to get src pad from decode in mainbin");
12164 return MM_ERROR_PLAYER_INTERNAL;
12167 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12168 LOGW("trying to block pad(video)");
12169 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12170 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12173 LOGE("failed to set block pad(video)");
12174 return MM_ERROR_PLAYER_INTERNAL;
12176 LOGW("pad is blocked(video)");
12178 /* no data flows, so no need to do pad_block */
12179 if (player->doing_seek)
12180 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12182 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12186 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12187 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12188 LOGE("failed to remove previous ghost_pad for videobin");
12189 return MM_ERROR_PLAYER_INTERNAL;
12192 /* change state of videobin to NULL */
12193 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12194 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12195 if (ret != GST_STATE_CHANGE_SUCCESS) {
12196 LOGE("failed to change state of videobin to NULL");
12197 return MM_ERROR_PLAYER_INTERNAL;
12200 /* unlink between decoder and videobin and remove previous videosink from videobin */
12201 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12202 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12203 LOGE("failed to remove former videosink from videobin");
12204 return MM_ERROR_PLAYER_INTERNAL;
12207 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12209 /* create a new videosink and add it to videobin */
12210 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12211 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12212 LOGE("failed to create videosink element\n");
12214 return MM_ERROR_PLAYER_INTERNAL;
12216 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12217 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12218 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12220 /* save attributes */
12221 if (player->attrs) {
12222 /* set a new display surface type */
12223 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12224 /* set a new diplay overlay */
12225 switch (surface_type) {
12226 case MM_DISPLAY_SURFACE_OVERLAY:
12227 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12228 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12231 LOGE("invalid type(%d) for changing display surface", surface_type);
12233 return MM_ERROR_INVALID_ARGUMENT;
12235 if (mmf_attrs_commit(player->attrs)) {
12236 LOGE("failed to commit");
12238 return MM_ERROR_PLAYER_INTERNAL;
12241 LOGE("player->attrs is null, failed to save attributes");
12243 return MM_ERROR_PLAYER_INTERNAL;
12246 /* update video param */
12247 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12248 LOGE("failed to update video param");
12249 return MM_ERROR_PLAYER_INTERNAL;
12252 /* change state of videobin to READY */
12253 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12254 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12255 if (ret != GST_STATE_CHANGE_SUCCESS) {
12256 LOGE("failed to change state of videobin to READY");
12257 return MM_ERROR_PLAYER_INTERNAL;
12260 /* change ghostpad */
12261 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12262 if (!sink_pad_videosink) {
12263 LOGE("failed to get sink pad from videosink element");
12264 return MM_ERROR_PLAYER_INTERNAL;
12266 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12267 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12268 LOGE("failed to set active to ghost_pad");
12269 return MM_ERROR_PLAYER_INTERNAL;
12271 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12272 LOGE("failed to change ghostpad for videobin");
12273 return MM_ERROR_PLAYER_INTERNAL;
12275 gst_object_unref(sink_pad_videosink);
12277 /* link decoder with videobin */
12278 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12279 if (!sink_pad_videobin) {
12280 LOGE("failed to get sink pad from videobin");
12281 return MM_ERROR_PLAYER_INTERNAL;
12283 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12284 LOGE("failed to link");
12285 return MM_ERROR_PLAYER_INTERNAL;
12287 gst_object_unref(sink_pad_videobin);
12289 /* clock setting for a new videosink plugin */
12290 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12291 so we set it from audiosink plugin or pipeline(system clock) */
12292 if (!is_audiobin_created) {
12293 LOGW("audiobin is not created, get clock from pipeline..");
12294 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12296 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12300 GstClockTime base_time;
12301 LOGD("set the clock to videosink");
12302 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12303 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12305 LOGD("got clock of videosink");
12306 now = gst_clock_get_time(clock);
12307 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12308 LOGD("at time %" GST_TIME_FORMAT ", base %"
12309 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12311 LOGE("failed to get clock of videosink after setting clock");
12312 return MM_ERROR_PLAYER_INTERNAL;
12315 LOGW("failed to get clock, maybe it is the time before first playing");
12317 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12318 /* change state of videobin to PAUSED */
12319 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12320 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12321 if (ret != GST_STATE_CHANGE_FAILURE) {
12322 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12324 LOGE("failed to change state of videobin to PLAYING");
12325 return MM_ERROR_PLAYER_INTERNAL;
12328 /* release blocked and unref src pad of video decoder */
12330 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12331 LOGE("failed to set pad blocked FALSE(video)");
12332 return MM_ERROR_PLAYER_INTERNAL;
12335 LOGW("pad is unblocked(video)");
12337 if (player->doing_seek)
12338 LOGW("not completed seek(%d)", player->doing_seek);
12339 /* change state of videobin to PAUSED */
12340 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12341 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12342 if (ret != GST_STATE_CHANGE_FAILURE) {
12343 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12345 LOGE("failed to change state of videobin to PLAYING");
12346 return MM_ERROR_PLAYER_INTERNAL;
12349 /* already skipped pad block */
12350 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12353 /* do get/set position for new videosink plugin */
12355 unsigned long position = 0;
12356 gint64 pos_msec = 0;
12358 LOGD("do get/set position for new videosink plugin");
12359 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12360 LOGE("failed to get position");
12361 return MM_ERROR_PLAYER_INTERNAL;
12363 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12364 /* accurate seek */
12365 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12366 LOGE("failed to set position");
12367 return MM_ERROR_PLAYER_INTERNAL;
12370 /* key unit seek */
12371 pos_msec = position * G_GINT64_CONSTANT(1000000);
12372 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12373 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12374 GST_SEEK_TYPE_SET, pos_msec,
12375 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12377 LOGE("failed to set position");
12378 return MM_ERROR_PLAYER_INTERNAL;
12384 gst_object_unref(src_pad_dec);
12385 LOGD("success to change sink");
12389 return MM_ERROR_NONE;
12393 /* Note : if silent is true, then subtitle would not be displayed. :*/
12394 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12396 mm_player_t* player = (mm_player_t*) hplayer;
12400 /* check player handle */
12401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12403 player->set_mode.subtitle_off = silent;
12405 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12409 return MM_ERROR_NONE;
12412 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12414 MMPlayerGstElement* mainbin = NULL;
12415 MMPlayerGstElement* textbin = NULL;
12416 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12417 GstState current_state = GST_STATE_VOID_PENDING;
12418 GstState element_state = GST_STATE_VOID_PENDING;
12419 GstState element_pending_state = GST_STATE_VOID_PENDING;
12421 GstEvent *event = NULL;
12422 int result = MM_ERROR_NONE;
12424 GstClock *curr_clock = NULL;
12425 GstClockTime base_time, start_time, curr_time;
12430 /* check player handle */
12431 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12432 player->pipeline &&
12433 player->pipeline->mainbin &&
12434 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12436 mainbin = player->pipeline->mainbin;
12437 textbin = player->pipeline->textbin;
12439 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12441 // sync clock with current pipeline
12442 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12443 curr_time = gst_clock_get_time(curr_clock);
12445 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12446 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12448 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12449 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12451 if (current_state > GST_STATE_READY) {
12452 // sync state with current pipeline
12453 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12454 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12455 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12457 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12458 if (GST_STATE_CHANGE_FAILURE == ret) {
12459 LOGE("fail to state change.\n");
12460 result = MM_ERROR_PLAYER_INTERNAL;
12465 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12466 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12469 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12470 gst_object_unref(curr_clock);
12473 // seek to current position
12474 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12475 result = MM_ERROR_PLAYER_INVALID_STATE;
12476 LOGE("gst_element_query_position failed, invalid state\n");
12480 LOGD("seek time = %lld, rate = %f\n", time, player->playback_rate);
12481 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);
12483 __gst_send_event_to_sink(player, event);
12485 result = MM_ERROR_PLAYER_INTERNAL;
12486 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12490 /* sync state with current pipeline */
12491 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12492 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12493 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12495 return MM_ERROR_NONE;
12498 /* release text pipeline resource */
12499 player->textsink_linked = 0;
12501 /* release signal */
12502 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12504 /* release textbin with it's childs */
12505 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12506 MMPLAYER_FREEIF(player->pipeline->textbin);
12507 player->pipeline->textbin = NULL;
12509 /* release subtitle elem */
12510 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12511 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12517 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12519 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12520 GstState current_state = GST_STATE_VOID_PENDING;
12522 MMHandleType attrs = 0;
12523 MMPlayerGstElement* mainbin = NULL;
12524 MMPlayerGstElement* textbin = NULL;
12526 gchar* subtitle_uri = NULL;
12527 int result = MM_ERROR_NONE;
12528 const gchar *charset = NULL;
12532 /* check player handle */
12533 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12534 player->pipeline &&
12535 player->pipeline->mainbin &&
12536 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12537 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12539 mainbin = player->pipeline->mainbin;
12540 textbin = player->pipeline->textbin;
12542 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12543 if (current_state < GST_STATE_READY) {
12544 result = MM_ERROR_PLAYER_INVALID_STATE;
12545 LOGE("Pipeline is not in proper state\n");
12549 attrs = MMPLAYER_GET_ATTRS(player);
12551 LOGE("cannot get content attribute\n");
12552 result = MM_ERROR_PLAYER_INTERNAL;
12556 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12557 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12558 LOGE("subtitle uri is not proper filepath\n");
12559 result = MM_ERROR_PLAYER_INVALID_URI;
12563 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12564 LOGE("failed to get storage info of subtitle path");
12565 result = MM_ERROR_PLAYER_INVALID_URI;
12569 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12570 LOGD("new subtitle file path is [%s]\n", filepath);
12572 if (!strcmp(filepath, subtitle_uri)) {
12573 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12576 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12577 if (mmf_attrs_commit(player->attrs)) {
12578 LOGE("failed to commit.\n");
12583 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12584 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12585 player->subtitle_language_list = NULL;
12586 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12588 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12589 if (ret != GST_STATE_CHANGE_SUCCESS) {
12590 LOGE("failed to change state of textbin to READY");
12591 result = MM_ERROR_PLAYER_INTERNAL;
12595 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12596 if (ret != GST_STATE_CHANGE_SUCCESS) {
12597 LOGE("failed to change state of subparse to READY");
12598 result = MM_ERROR_PLAYER_INTERNAL;
12602 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12603 if (ret != GST_STATE_CHANGE_SUCCESS) {
12604 LOGE("failed to change state of filesrc to READY");
12605 result = MM_ERROR_PLAYER_INTERNAL;
12609 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12611 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12613 charset = util_get_charset(filepath);
12615 LOGD("detected charset is %s\n", charset);
12616 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12619 result = _mmplayer_sync_subtitle_pipeline(player);
12626 /* API to switch between external subtitles */
12627 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12629 int result = MM_ERROR_NONE;
12630 mm_player_t* player = (mm_player_t*)hplayer;
12635 /* check player handle */
12636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12638 /* filepath can be null in idle state */
12640 /* check file path */
12641 if ((path = strstr(filepath, "file://")))
12642 result = util_exist_file_path(path + 7);
12644 result = util_exist_file_path(filepath);
12646 if (result != MM_ERROR_NONE) {
12647 LOGE("invalid subtitle path 0x%X", result);
12648 return result; /* file not found or permission denied */
12652 if (!player->pipeline) {
12654 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12655 if (mmf_attrs_commit(player->attrs)) {
12656 LOGE("failed to commit"); /* subtitle path will not be created */
12657 return MM_ERROR_PLAYER_INTERNAL;
12660 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12661 /* check filepath */
12662 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12664 if (!__mmplayer_check_subtitle(player)) {
12665 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12666 if (mmf_attrs_commit(player->attrs)) {
12667 LOGE("failed to commit");
12668 return MM_ERROR_PLAYER_INTERNAL;
12671 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12672 LOGE("fail to create text pipeline");
12673 return MM_ERROR_PLAYER_INTERNAL;
12676 result = _mmplayer_sync_subtitle_pipeline(player);
12678 result = __mmplayer_change_external_subtitle_language(player, filepath);
12681 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12682 player->is_external_subtitle_added_now = TRUE;
12684 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12685 if (!player->subtitle_language_list) {
12686 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12687 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12688 LOGW("subtitle language list is not updated yet");
12690 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12698 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12700 int result = MM_ERROR_NONE;
12701 gchar* change_pad_name = NULL;
12702 GstPad* sinkpad = NULL;
12703 MMPlayerGstElement* mainbin = NULL;
12704 enum MainElementID elemId = MMPLAYER_M_NUM;
12705 GstCaps* caps = NULL;
12706 gint total_track_num = 0;
12710 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12711 MM_ERROR_PLAYER_NOT_INITIALIZED);
12713 LOGD("Change Track(%d) to %d\n", type, index);
12715 mainbin = player->pipeline->mainbin;
12717 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12718 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12719 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12720 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12722 /* Changing Video Track is not supported. */
12723 LOGE("Track Type Error\n");
12727 if (mainbin[elemId].gst == NULL) {
12728 result = MM_ERROR_PLAYER_NO_OP;
12729 LOGD("Req track doesn't exist\n");
12733 total_track_num = player->selector[type].total_track_num;
12734 if (total_track_num <= 0) {
12735 result = MM_ERROR_PLAYER_NO_OP;
12736 LOGD("Language list is not available \n");
12740 if ((index < 0) || (index >= total_track_num)) {
12741 result = MM_ERROR_INVALID_ARGUMENT;
12742 LOGD("Not a proper index : %d \n", index);
12746 /*To get the new pad from the selector*/
12747 change_pad_name = g_strdup_printf("sink_%u", index);
12748 if (change_pad_name == NULL) {
12749 result = MM_ERROR_PLAYER_INTERNAL;
12750 LOGD("Pad does not exists\n");
12754 LOGD("new active pad name: %s\n", change_pad_name);
12756 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12757 if (sinkpad == NULL) {
12758 LOGD("sinkpad is NULL");
12759 result = MM_ERROR_PLAYER_INTERNAL;
12763 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12764 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12766 caps = gst_pad_get_current_caps(sinkpad);
12767 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12770 gst_object_unref(sinkpad);
12772 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12773 __mmplayer_set_audio_attrs(player, caps);
12777 MMPLAYER_FREEIF(change_pad_name);
12781 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12783 int result = MM_ERROR_NONE;
12784 mm_player_t* player = NULL;
12785 MMPlayerGstElement* mainbin = NULL;
12787 gint current_active_index = 0;
12789 GstState current_state = GST_STATE_VOID_PENDING;
12790 GstEvent* event = NULL;
12795 player = (mm_player_t*)hplayer;
12796 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12798 if (!player->pipeline) {
12799 LOGE("Track %d pre setting -> %d\n", type, index);
12801 player->selector[type].active_pad_index = index;
12805 mainbin = player->pipeline->mainbin;
12807 current_active_index = player->selector[type].active_pad_index;
12809 /*If index is same as running index no need to change the pad*/
12810 if (current_active_index == index)
12813 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12814 result = MM_ERROR_PLAYER_INVALID_STATE;
12818 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12819 if (current_state < GST_STATE_PAUSED) {
12820 result = MM_ERROR_PLAYER_INVALID_STATE;
12821 LOGW("Pipeline not in porper state\n");
12825 result = __mmplayer_change_selector_pad(player, type, index);
12826 if (result != MM_ERROR_NONE) {
12827 LOGE("change selector pad error\n");
12831 player->selector[type].active_pad_index = index;
12833 if (current_state == GST_STATE_PLAYING) {
12834 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);
12836 __gst_send_event_to_sink(player, event);
12838 result = MM_ERROR_PLAYER_INTERNAL;
12847 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12849 mm_player_t* player = (mm_player_t*) hplayer;
12853 /* check player handle */
12854 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12856 *silent = player->set_mode.subtitle_off;
12858 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12862 return MM_ERROR_NONE;
12866 __is_ms_buff_src(mm_player_t* player)
12868 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12870 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12874 __has_suffix(mm_player_t* player, const gchar* suffix)
12876 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12877 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12879 gboolean ret = FALSE;
12880 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12881 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12883 if (g_str_has_suffix(player->profile.uri, suffix))
12886 MMPLAYER_FREEIF(t_url);
12887 MMPLAYER_FREEIF(t_suffix);
12893 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12895 mm_player_t* player = (mm_player_t*) hplayer;
12897 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12899 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12900 MMPLAYER_PRINT_STATE(player);
12901 LOGE("wrong-state : can't set the download mode to parse");
12902 return MM_ERROR_PLAYER_INVALID_STATE;
12905 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12906 player->video_hub_download_mode = mode;
12908 return MM_ERROR_NONE;
12912 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12914 mm_player_t* player = (mm_player_t*) hplayer;
12916 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12918 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12919 player->sync_handler = enable;
12921 return MM_ERROR_NONE;
12925 _mmplayer_set_video_share_master_clock(MMHandleType hplayer,
12927 long long clock_delta,
12928 long long video_time,
12929 long long media_clock,
12930 long long audio_time)
12932 mm_player_t* player = (mm_player_t*) hplayer;
12933 MMPlayerGstElement* mainbin = NULL;
12934 GstClockTime start_time_audio = 0, start_time_video = 0;
12935 GstClockTimeDiff base_time = 0, new_base_time = 0;
12936 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12937 gint64 api_delta = 0;
12938 gint64 position = 0, position_delta = 0;
12939 gint64 adj_base_time = 0;
12940 GstClock *curr_clock = NULL;
12941 GstClockTime curr_time = 0;
12942 gboolean query_ret = TRUE;
12943 int result = MM_ERROR_NONE;
12947 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12948 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12949 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12951 // LOGD("in(us) : %lld, %lld, %lld, %lld, %lld", clock, clock_delta, video_time, media_clock, audio_time);
12953 if ((video_time < 0) || (player->doing_seek)) {
12954 LOGD("skip setting master clock. %lld", video_time);
12958 mainbin = player->pipeline->mainbin;
12960 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12961 curr_time = gst_clock_get_time(curr_clock);
12963 current_state = MMPLAYER_CURRENT_STATE(player);
12965 if (current_state == MM_PLAYER_STATE_PLAYING)
12966 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12968 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12970 position = player->last_position;
12971 LOGD("query fail. %lld", position);
12974 clock *= GST_USECOND;
12975 clock_delta *= GST_USECOND;
12977 api_delta = clock - curr_time;
12978 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12979 player->video_share_api_delta = api_delta;
12981 clock_delta += (api_delta - player->video_share_api_delta);
12983 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
12984 player->video_share_clock_delta = (gint64)clock_delta;
12986 position_delta = (position/GST_USECOND) - video_time;
12987 position_delta *= GST_USECOND;
12989 adj_base_time = position_delta;
12990 LOGD("video_share_clock_delta = %lld, adj = %lld", player->video_share_clock_delta, adj_base_time);
12993 gint64 new_play_time = 0;
12994 gint64 network_delay = 0;
12996 video_time *= GST_USECOND;
12998 network_delay = clock_delta - player->video_share_clock_delta;
12999 new_play_time = video_time + network_delay;
13001 adj_base_time = position - new_play_time;
13003 LOGD("%lld(delay) = %lld - %lld / %lld(adj) = %lld(slave_pos) - %lld(master_pos) - %lld(delay)",
13004 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13007 /* Adjust Current Stream Time with base_time of sink
13008 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13009 * 2. Set new base time
13010 * if adj_base_time is positive value, the stream time will be decreased.
13011 * 3. If seek event is occurred, the start time will be reset. */
13012 if ((player->pipeline->audiobin) &&
13013 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13014 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13016 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13017 LOGD("audio sink : gst_element_set_start_time -> NONE");
13018 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13021 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13024 if ((player->pipeline->videobin) &&
13025 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13026 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13028 if (start_time_video != GST_CLOCK_TIME_NONE) {
13029 LOGD("video sink : gst_element_set_start_time -> NONE");
13030 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13033 // if videobin exist, get base_time from videobin.
13034 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13037 new_base_time = base_time + adj_base_time;
13039 if ((player->pipeline->audiobin) &&
13040 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13041 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13043 if ((player->pipeline->videobin) &&
13044 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13045 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13054 _mmplayer_get_video_share_master_clock(MMHandleType hplayer,
13055 long long *video_time,
13056 long long *media_clock,
13057 long long *audio_time)
13059 mm_player_t* player = (mm_player_t*) hplayer;
13060 MMPlayerGstElement* mainbin = NULL;
13061 GstClock *curr_clock = NULL;
13062 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13063 gint64 position = 0;
13064 gboolean query_ret = TRUE;
13068 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13069 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13070 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13072 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13073 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13074 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13076 mainbin = player->pipeline->mainbin;
13078 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13080 current_state = MMPLAYER_CURRENT_STATE(player);
13082 if (current_state != MM_PLAYER_STATE_PAUSED)
13083 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13085 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13087 position = player->last_position;
13089 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13091 LOGD("media_clock: %lld, video_time: %lld(us)", *media_clock, *video_time);
13094 gst_object_unref(curr_clock);
13098 return MM_ERROR_NONE;
13102 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13104 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13105 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13107 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13108 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13112 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13113 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13114 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13115 mm_player_dump_t *dump_s;
13116 dump_s = g_malloc(sizeof(mm_player_dump_t));
13118 if (dump_s == NULL) {
13119 LOGE("malloc fail");
13123 dump_s->dump_element_file = NULL;
13124 dump_s->dump_pad = NULL;
13125 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13127 if (dump_s->dump_pad) {
13128 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13129 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]);
13130 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13131 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);
13132 /* add list for removed buffer probe and close FILE */
13133 player->dump_list = g_list_append(player->dump_list, dump_s);
13134 LOGD("%s sink pad added buffer probe for dump", factory_name);
13139 LOGE("failed to get %s sink pad added", factory_name);
13148 static GstPadProbeReturn
13149 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13151 FILE *dump_data = (FILE *) u_data;
13152 // int written = 0;
13153 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13154 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13156 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13158 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13160 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13162 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13164 return GST_PAD_PROBE_OK;
13168 __mmplayer_release_dump_list(GList *dump_list)
13171 GList *d_list = dump_list;
13172 for (; d_list; d_list = g_list_next(d_list)) {
13173 mm_player_dump_t *dump_s = d_list->data;
13174 if (dump_s->dump_pad) {
13175 if (dump_s->probe_handle_id)
13176 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13178 if (dump_s->dump_element_file) {
13179 fclose(dump_s->dump_element_file);
13180 dump_s->dump_element_file = NULL;
13182 MMPLAYER_FREEIF(dump_s);
13184 g_list_free(dump_list);
13190 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13192 mm_player_t* player = (mm_player_t*) hplayer;
13196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13197 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13199 *exist = player->has_closed_caption;
13203 return MM_ERROR_NONE;
13206 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13210 // LOGD("unref internal gst buffer %p", buffer);
13211 gst_buffer_unref((GstBuffer *)buffer);
13218 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13220 mm_player_t *player = (mm_player_t*)user_data;
13221 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13222 guint64 current_level_bytes = 0;
13224 MMPLAYER_RETURN_IF_FAIL(player);
13226 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13228 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13229 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13231 if (player->media_stream_buffer_status_cb[type])
13232 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13233 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13238 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13240 mm_player_t *player = (mm_player_t*)user_data;
13241 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13242 guint64 current_level_bytes = 0;
13244 MMPLAYER_RETURN_IF_FAIL(player);
13246 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13248 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13250 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13251 if (player->media_stream_buffer_status_cb[type])
13252 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13253 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13257 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13259 mm_player_t *player = (mm_player_t*)user_data;
13260 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13261 guint64 current_level_bytes = 0;
13263 MMPLAYER_RETURN_IF_FAIL(player);
13265 LOGI("app-src: feed subtitle\n");
13267 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13269 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13270 if (player->media_stream_buffer_status_cb[type])
13271 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13273 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13277 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13279 mm_player_t *player = (mm_player_t*)user_data;
13280 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13281 guint64 current_level_bytes = 0;
13283 MMPLAYER_RETURN_IF_FAIL(player);
13285 LOGI("app-src: audio buffer is full.\n");
13287 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13289 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13291 if (player->media_stream_buffer_status_cb[type])
13292 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13294 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13298 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13300 mm_player_t *player = (mm_player_t*)user_data;
13301 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13302 guint64 current_level_bytes = 0;
13304 MMPLAYER_RETURN_IF_FAIL(player);
13306 LOGI("app-src: video buffer is full.\n");
13308 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13310 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13311 if (player->media_stream_buffer_status_cb[type])
13312 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13314 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13318 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13320 mm_player_t *player = (mm_player_t*)user_data;
13321 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13323 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13325 LOGD("app-src: seek audio data %llu\n", position);
13326 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13328 if (player->media_stream_seek_data_cb[type])
13329 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13330 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13336 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13338 mm_player_t *player = (mm_player_t*)user_data;
13339 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13341 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13343 LOGD("app-src: seek video data %llu\n", position);
13344 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13345 if (player->media_stream_seek_data_cb[type])
13346 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13347 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13353 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13355 mm_player_t *player = (mm_player_t*)user_data;
13356 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13358 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13360 LOGD("app-src: seek subtitle data\n");
13361 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13363 if (player->media_stream_seek_data_cb[type])
13364 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13365 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13371 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13373 mm_player_t* player = (mm_player_t*) hplayer;
13377 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13379 player->pcm_samplerate = samplerate;
13380 player->pcm_channel = channel;
13383 return MM_ERROR_NONE;
13386 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13388 mm_player_t* player = (mm_player_t*) hplayer;
13392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13393 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13395 if (MMPLAYER_IS_STREAMING(player))
13396 *timeout = player->ini.live_state_change_timeout;
13398 *timeout = player->ini.localplayback_state_change_timeout;
13400 LOGD("timeout = %d\n", *timeout);
13403 return MM_ERROR_NONE;
13406 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13408 mm_player_t* player = (mm_player_t*) hplayer;
13412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13413 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13415 *num = player->video_num_buffers;
13416 *extra_num = player->video_extra_num_buffers;
13418 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13421 return MM_ERROR_NONE;
13425 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13429 MMPLAYER_RETURN_IF_FAIL(player);
13431 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13433 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13434 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13435 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13436 player->storage_info[i].id = -1;
13437 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13439 if (path_type != MMPLAYER_PATH_MAX)
13447 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13449 int ret = MM_ERROR_NONE;
13450 mm_player_t* player = (mm_player_t*)hplayer;
13451 MMMessageParamType msg_param = {0, };
13454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13456 LOGW("state changed storage %d:%d", id, state);
13458 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13459 return MM_ERROR_NONE;
13461 /* FIXME: text path should be handled seperately. */
13462 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13463 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13464 LOGW("external storage is removed");
13466 if (player->msg_posted == FALSE) {
13467 memset(&msg_param, 0, sizeof(MMMessageParamType));
13468 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13469 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13470 player->msg_posted = TRUE;
13473 /* unrealize the player */
13474 ret = _mmplayer_unrealize(hplayer);
13475 if (ret != MM_ERROR_NONE)
13476 LOGE("failed to unrealize");
13483 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13485 int ret = MM_ERROR_NONE;
13486 mm_player_t* player = (mm_player_t*) hplayer;
13487 int idx = 0, total = 0;
13488 gchar *result = NULL, *tmp = NULL;
13491 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13492 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13494 total = *num = g_list_length(player->adaptive_info.var_list);
13496 LOGW("There is no stream variant info.");
13500 result = g_strdup("");
13501 for (idx = 0 ; idx < total ; idx++) {
13502 VariantData *v_data = NULL;
13503 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13506 gchar data[64] = {0};
13507 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13509 tmp = g_strconcat(result, data, NULL);
13513 LOGW("There is no variant data in %d", idx);
13518 *var_info = (char *)result;
13520 LOGD("variant info %d:%s", *num, *var_info);
13525 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13527 int ret = MM_ERROR_NONE;
13528 mm_player_t* player = (mm_player_t*) hplayer;
13531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13533 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13535 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13536 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13537 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13539 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13540 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13541 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13542 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13544 /* FIXME: seek to current position for applying new variant limitation */
13552 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13554 int ret = MM_ERROR_NONE;
13555 mm_player_t* player = (mm_player_t*) hplayer;
13558 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13559 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13561 *bandwidth = player->adaptive_info.limit.bandwidth;
13562 *width = player->adaptive_info.limit.width;
13563 *height = player->adaptive_info.limit.height;
13565 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13571 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13573 int ret = MM_ERROR_NONE;
13574 mm_player_t* player = (mm_player_t*) hplayer;
13577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13579 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13580 LOGW("buffer_ms will not be applied.");
13583 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13585 if (player->streamer == NULL) {
13586 player->streamer = __mm_player_streaming_create();
13587 __mm_player_streaming_initialize(player->streamer);
13590 if (buffer_ms >= 0)
13591 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13593 if (rebuffer_ms >= 0)
13594 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13601 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13603 int ret = MM_ERROR_NONE;
13604 mm_player_t* player = (mm_player_t*) hplayer;
13607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13608 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13610 if (player->streamer == NULL) {
13611 player->streamer = __mm_player_streaming_create();
13612 __mm_player_streaming_initialize(player->streamer);
13615 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13616 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13618 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13624 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13626 #define IDX_FIRST_SW_CODEC 0
13627 mm_player_t* player = (mm_player_t*) hplayer;
13628 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13629 MMHandleType attrs = 0;
13632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13634 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13635 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13636 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13638 switch (stream_type) {
13639 case MM_PLAYER_STREAM_TYPE_AUDIO:
13640 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13641 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13642 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13643 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13644 LOGE("There is no a codec for codec_type %d", codec_type);
13645 return MM_ERROR_PLAYER_NO_OP;
13648 case MM_PLAYER_STREAM_TYPE_VIDEO:
13649 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13650 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13651 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13652 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13653 LOGE("There is no v codec for codec_type %d", codec_type);
13654 return MM_ERROR_PLAYER_NO_OP;
13659 LOGE("Invalid stream type %d", stream_type);
13660 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13664 LOGD("update %s codec_type to %d", attr_name, codec_type);
13666 attrs = MMPLAYER_GET_ATTRS(player);
13667 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13669 if (mmf_attrs_commit(player->attrs)) {
13670 LOGE("failed to commit codec_type attributes");
13671 return MM_ERROR_PLAYER_INTERNAL;
13675 return MM_ERROR_NONE;
13679 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13681 mm_player_t* player = (mm_player_t*) hplayer;
13682 GstElement* rg_vol_element = NULL;
13686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13688 player->sound.rg_enable = enabled;
13690 /* just hold rgvolume enable value if pipeline is not ready */
13691 if (!player->pipeline || !player->pipeline->audiobin) {
13692 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13693 return MM_ERROR_NONE;
13696 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13698 if (!rg_vol_element) {
13699 LOGD("rgvolume element is not created");
13700 return MM_ERROR_PLAYER_INTERNAL;
13704 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13706 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13710 return MM_ERROR_NONE;
13714 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13716 mm_player_t* player = (mm_player_t*) hplayer;
13717 GstElement* rg_vol_element = NULL;
13718 gboolean enable = FALSE;
13722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13723 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13725 /* just hold enable_rg value if pipeline is not ready */
13726 if (!player->pipeline || !player->pipeline->audiobin) {
13727 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13728 *enabled = player->sound.rg_enable;
13729 return MM_ERROR_NONE;
13732 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13734 if (!rg_vol_element) {
13735 LOGD("rgvolume element is not created");
13736 return MM_ERROR_PLAYER_INTERNAL;
13739 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13744 return MM_ERROR_NONE;