4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
42 #include <mm_attrs_private.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
55 /*===========================================================================================
57 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
59 ========================================================================================== */
61 /*---------------------------------------------------------------------------
62 | GLOBAL CONSTANT DEFINITIONS: |
63 ---------------------------------------------------------------------------*/
65 /*---------------------------------------------------------------------------
66 | IMPORTED VARIABLE DECLARATIONS: |
67 ---------------------------------------------------------------------------*/
69 /*---------------------------------------------------------------------------
70 | IMPORTED FUNCTION DECLARATIONS: |
71 ---------------------------------------------------------------------------*/
73 /*---------------------------------------------------------------------------
75 ---------------------------------------------------------------------------*/
76 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
77 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
79 #define MM_VOLUME_FACTOR_DEFAULT 1.0
80 #define MM_VOLUME_FACTOR_MIN 0
81 #define MM_VOLUME_FACTOR_MAX 1.0
83 /* Don't need to sleep for sound fadeout
84 * fadeout related fucntion will be deleted(Deprecated)
86 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
88 #define DEFAULT_PLAYBACK_RATE 1.0
89 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
91 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
92 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
93 (player->ini.http_use_file_buffer) && \
94 (player->http_file_buffering_path) && \
95 (strlen(player->http_file_buffering_path) > 0))
97 #define PLAYER_DISPLAY_MODE_DST_ROI 5
99 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
104 #define PLAYER_BUS_MSG_DEFAULT_TIMEOUT 500 /* bus msg wait timeout */
105 #define PLAYER_BUS_MSG_PREPARE_TIMEOUT 10
107 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
108 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
109 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
110 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
112 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
113 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
115 /*---------------------------------------------------------------------------
116 | LOCAL CONSTANT DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
119 /*---------------------------------------------------------------------------
120 | LOCAL DATA TYPE DEFINITIONS: |
121 ---------------------------------------------------------------------------*/
123 /*---------------------------------------------------------------------------
124 | GLOBAL VARIABLE DEFINITIONS: |
125 ---------------------------------------------------------------------------*/
127 /*---------------------------------------------------------------------------
128 | LOCAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
130 static sound_stream_info_h stream_info;
132 /*---------------------------------------------------------------------------
133 | LOCAL FUNCTION PROTOTYPES: |
134 ---------------------------------------------------------------------------*/
135 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
138 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
140 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
141 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
143 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
144 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
146 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
149 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
150 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
151 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
152 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
153 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
154 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
155 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
156 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
157 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
158 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
159 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
161 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
162 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
163 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player);
164 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
165 static void __mmplayer_release_misc(mm_player_t* player);
166 static void __mmplayer_release_misc_post(mm_player_t* player);
167 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
168 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
169 static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
170 static gboolean __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
171 static gboolean __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
172 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
173 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
175 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
176 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
177 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
179 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
180 static gboolean __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message);
181 static void __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms);
182 static void __mmplayer_cancel_eos_timer(mm_player_t* player);
183 static gboolean __mmplayer_eos_timer_cb(gpointer u_data);
184 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
185 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
186 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player);
187 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
188 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
189 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
190 static gpointer __mmplayer_next_play_thread(gpointer data);
191 static gboolean _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag);
193 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
194 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
195 static void __mmplayer_release_dump_list(GList *dump_list);
197 static int __gst_realize(mm_player_t* player);
198 static int __gst_unrealize(mm_player_t* player);
199 static int __gst_start(mm_player_t* player);
200 static int __gst_stop(mm_player_t* player);
201 static int __gst_pause(mm_player_t* player, gboolean async);
202 static int __gst_resume(mm_player_t* player, gboolean async);
203 static gboolean __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
204 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
205 gint64 cur, GstSeekType stop_type, gint64 stop);
206 static int __gst_pending_seek(mm_player_t* player);
208 static int __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called);
209 static int __gst_get_position(mm_player_t* player, int format, gint64 *position);
210 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos);
211 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
212 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
214 static gboolean __gst_send_event_to_sink(mm_player_t* player, GstEvent* event);
216 static int __mmplayer_set_pcm_extraction(mm_player_t* player);
217 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
220 static gboolean __is_ms_buff_src(mm_player_t* player);
221 static gboolean __has_suffix(mm_player_t * player, const gchar * suffix);
223 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
224 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
225 static int __mmplayer_start_streaming_ext(mm_player_t *player);
226 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
227 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
229 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
230 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
231 static void __mmplayer_check_pipeline(mm_player_t* player);
232 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
233 static void __mmplayer_deactivate_old_path(mm_player_t *player);
235 static void __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg);
236 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
238 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
239 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
240 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
241 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
242 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
243 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
244 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
245 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
246 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
247 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
248 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
249 static void __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all);
250 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
251 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
252 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags, mm_player_spherical_metadata_t *metadata);
253 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
255 /*===========================================================================================
257 | FUNCTION DEFINITIONS |
259 ========================================================================================== */
263 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
267 count = gst_tag_list_get_tag_size(list, tag);
269 LOGD("count = %d", count);
271 for (i = 0; i < count; i++) {
274 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
275 if (!gst_tag_list_get_string_index(list, tag, i, &str))
276 g_assert_not_reached();
278 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
281 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
283 g_print(" : %s\n", str);
290 /* This function should be called after the pipeline goes PAUSED or higher
293 _mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
295 static gboolean has_duration = FALSE;
296 static gboolean has_video_attrs = FALSE;
297 static gboolean has_audio_attrs = FALSE;
298 static gboolean has_bitrate = FALSE;
299 gboolean missing_only = FALSE;
300 gboolean all = FALSE;
302 GstStructure* p = NULL;
303 MMHandleType attrs = 0;
309 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
311 /* check player state here */
312 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
313 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
314 /* give warning now only */
315 LOGW("be careful. content attributes may not available in this state ");
318 /* get content attribute first */
319 attrs = MMPLAYER_GET_ATTRS(player);
321 LOGE("cannot get content attribute");
325 /* get update flag */
327 if (flag & ATTR_MISSING_ONLY) {
329 LOGD("updating missed attr only");
332 if (flag & ATTR_ALL) {
334 has_duration = FALSE;
335 has_video_attrs = FALSE;
336 has_audio_attrs = FALSE;
339 LOGD("updating all attrs");
342 if (missing_only && all) {
343 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
344 missing_only = FALSE;
347 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
348 LOGD("try to update duration");
349 has_duration = FALSE;
351 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
352 player->duration = dur_nsec;
353 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
357 if (player->duration < 0) {
358 LOGW("duration is Non-Initialized !!!");
359 player->duration = 0;
362 /* update streaming service type */
363 player->streaming_type = __mmplayer_get_stream_service_type(player);
365 /* check duration is OK */
366 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
367 /* FIXIT : find another way to get duration here. */
368 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
372 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
373 /* update audio params
374 NOTE : We need original audio params and it can be only obtained from src pad of audio
375 decoder. Below code only valid when we are not using 'resampler' just before
378 LOGD("try to update audio attrs");
379 has_audio_attrs = FALSE;
381 if (player->pipeline->audiobin &&
382 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
383 GstCaps *caps_a = NULL;
385 gint samplerate = 0, channels = 0;
387 pad = gst_element_get_static_pad(
388 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
391 caps_a = gst_pad_get_current_caps(pad);
394 p = gst_caps_get_structure(caps_a, 0);
396 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
398 gst_structure_get_int(p, "rate", &samplerate);
399 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
401 gst_structure_get_int(p, "channels", &channels);
402 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
404 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
406 gst_caps_unref(caps_a);
409 has_audio_attrs = TRUE;
411 LOGW("not ready to get audio caps");
413 gst_object_unref(pad);
415 LOGW("failed to get pad from audiosink");
419 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
420 LOGD("try to update video attrs");
421 has_video_attrs = FALSE;
423 if (player->pipeline->videobin &&
424 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
425 GstCaps *caps_v = NULL;
430 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
432 caps_v = gst_pad_get_current_caps(pad);
434 /* Use v_stream_caps, if fail to get video_sink sink pad*/
435 if (!caps_v && player->v_stream_caps) {
436 caps_v = player->v_stream_caps;
437 gst_caps_ref(caps_v);
441 p = gst_caps_get_structure(caps_v, 0);
442 gst_structure_get_int(p, "width", &width);
443 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
445 gst_structure_get_int(p, "height", &height);
446 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
448 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
450 SECURE_LOGD("width : %d height : %d", width, height);
452 gst_caps_unref(caps_v);
456 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
457 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
460 has_video_attrs = TRUE;
462 LOGD("no negitiated caps from videosink");
463 gst_object_unref(pad);
466 LOGD("no videosink sink pad");
472 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
475 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
476 if (player->duration) {
477 guint64 data_size = 0;
479 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
480 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
482 if (stat(path, &sb) == 0)
483 data_size = (guint64)sb.st_size;
484 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
485 data_size = player->http_content_size;
487 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
491 guint64 msec_dur = 0;
493 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
495 bitrate = data_size * 8 * 1000 / msec_dur;
496 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
497 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
501 LOGD("player duration is less than 0");
505 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
506 if (player->total_bitrate) {
507 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
515 if (mmf_attrs_commit(attrs)) {
516 LOGE("failed to update attributes\n");
525 static MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
527 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
531 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
533 player->pipeline->mainbin &&
534 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
535 STREAMING_SERVICE_NONE);
537 /* streaming service type if streaming */
538 if (!MMPLAYER_IS_STREAMING(player))
539 return STREAMING_SERVICE_NONE;
541 if (MMPLAYER_IS_HTTP_STREAMING(player))
542 streaming_type = (player->duration == 0) ?
543 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
545 switch (streaming_type) {
546 case STREAMING_SERVICE_LIVE:
547 LOGD("it's live streaming");
549 case STREAMING_SERVICE_VOD:
550 LOGD("it's vod streaming");
553 LOGE("should not get here");
559 return streaming_type;
563 /* this function sets the player state and also report
564 * it to applicaton by calling callback function
567 __mmplayer_set_state(mm_player_t* player, int state)
569 MMMessageParamType msg = {0, };
570 gboolean post_bos = FALSE;
572 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
574 if (MMPLAYER_CURRENT_STATE(player) == state) {
575 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
576 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
577 return MM_ERROR_NONE;
580 /* update player states */
581 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
582 MMPLAYER_CURRENT_STATE(player) = state;
584 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
585 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
588 MMPLAYER_PRINT_STATE(player);
590 switch (MMPLAYER_CURRENT_STATE(player)) {
591 case MM_PLAYER_STATE_NULL:
592 case MM_PLAYER_STATE_READY:
595 case MM_PLAYER_STATE_PAUSED:
597 if (!player->sent_bos) {
598 /* rtsp case, get content attrs by GstMessage */
599 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
600 /* it's first time to update all content attrs. */
601 _mmplayer_update_content_attrs(player, ATTR_ALL);
605 /* add audio callback probe if condition is satisfied */
606 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
607 __mmplayer_configure_audio_callback(player);
609 /* FIXIT : handle return value */
613 case MM_PLAYER_STATE_PLAYING:
615 /* try to get content metadata */
616 if (!player->sent_bos) {
617 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
618 * c-api since c-api doesn't use _start() anymore. It may not work propery with
619 * legacy mmfw-player api */
620 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
623 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
624 if (!player->sent_bos)
625 __mmplayer_handle_missed_plugin(player);
628 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
629 /* initialize because auto resume is done well. */
630 player->resumed_by_rewind = FALSE;
631 player->playback_rate = 1.0;
634 if (!player->sent_bos) {
635 /* check audio codec field is set or not
636 * we can get it from typefinder or codec's caps.
638 gchar *audio_codec = NULL;
639 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
641 /* The codec format can't be sent for audio only case like amr, mid etc.
642 * Because, parser don't make related TAG.
643 * So, if it's not set yet, fill it with found data.
646 if (g_strrstr(player->type, "audio/midi"))
647 audio_codec = g_strdup("MIDI");
648 else if (g_strrstr(player->type, "audio/x-amr"))
649 audio_codec = g_strdup("AMR");
650 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
651 audio_codec = g_strdup("AAC");
653 audio_codec = g_strdup("unknown");
654 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
656 MMPLAYER_FREEIF(audio_codec);
657 if (mmf_attrs_commit(player->attrs))
658 LOGE("failed to update attributes\n");
660 LOGD("set audio codec type with caps\n");
668 case MM_PLAYER_STATE_NONE:
670 LOGW("invalid target state, there is nothing to do.\n");
675 /* post message to application */
676 if (MMPLAYER_TARGET_STATE(player) == state) {
677 /* fill the message with state of player */
678 msg.union_type = MM_MSG_UNION_STATE;
679 msg.state.previous = MMPLAYER_PREV_STATE(player);
680 msg.state.current = MMPLAYER_CURRENT_STATE(player);
682 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
684 /* state changed by resource callback */
685 if (player->interrupted_by_resource) {
686 msg.state.code = MM_PLAYER_FOCUS_CHANGED_BY_RESOURCE_CONFLICT;
687 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
688 } else { /* state changed by usecase */
689 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
692 LOGD("intermediate state, do nothing.\n");
693 MMPLAYER_PRINT_STATE(player);
694 return MM_ERROR_NONE;
698 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
699 player->sent_bos = TRUE;
702 return MM_ERROR_NONE;
705 static gpointer __mmplayer_next_play_thread(gpointer data)
707 mm_player_t* player = (mm_player_t*) data;
708 MMPlayerGstElement *mainbin = NULL;
710 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
712 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
713 while (!player->next_play_thread_exit) {
714 LOGD("next play thread started. waiting for signal.\n");
715 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
717 LOGD("reconfigure pipeline for gapless play.\n");
719 if (player->next_play_thread_exit) {
720 if (player->gapless.reconfigure) {
721 player->gapless.reconfigure = false;
722 MMPLAYER_PLAYBACK_UNLOCK(player);
724 LOGD("exiting gapless play thread\n");
728 mainbin = player->pipeline->mainbin;
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
731 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
732 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
733 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
734 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
736 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
738 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
744 __mmplayer_update_buffer_setting(mm_player_t *player, GstMessage *buffering_msg)
746 MMHandleType attrs = 0;
747 guint64 data_size = 0;
752 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
754 __gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &pos_nsec); /* to update player->last_position */
756 attrs = MMPLAYER_GET_ATTRS(player);
758 LOGE("fail to get attributes.\n");
762 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
763 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
765 if (stat(path, &sb) == 0)
766 data_size = (guint64)sb.st_size;
767 } else if (MMPLAYER_IS_HTTP_STREAMING(player))
768 data_size = player->http_content_size;
770 __mm_player_streaming_buffering(player->streamer,
773 player->last_position,
776 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
782 __mmplayer_handle_buffering_message(mm_player_t* player)
784 int ret = MM_ERROR_NONE;
785 MMPlayerStateType prev_state = MM_PLAYER_STATE_NONE;
786 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
787 MMPlayerStateType target_state = MM_PLAYER_STATE_NONE;
788 MMPlayerStateType pending_state = MM_PLAYER_STATE_NONE;
790 if (!player || !player->streamer || (MMPLAYER_IS_LIVE_STREAMING(player) && MMPLAYER_IS_RTSP_STREAMING(player))) {
791 LOGW("do nothing for buffering msg\n");
792 ret = MM_ERROR_PLAYER_INVALID_STATE;
796 prev_state = MMPLAYER_PREV_STATE(player);
797 current_state = MMPLAYER_CURRENT_STATE(player);
798 target_state = MMPLAYER_TARGET_STATE(player);
799 pending_state = MMPLAYER_PENDING_STATE(player);
801 LOGD("player state : prev %s, current %s, pending %s, target %s, buffering %d",
802 MMPLAYER_STATE_GET_NAME(prev_state),
803 MMPLAYER_STATE_GET_NAME(current_state),
804 MMPLAYER_STATE_GET_NAME(pending_state),
805 MMPLAYER_STATE_GET_NAME(target_state),
806 player->streamer->is_buffering);
808 if (!player->streamer->is_buffering) {
809 /* NOTE : if buffering has done, player has to go to target state. */
810 switch (target_state) {
811 case MM_PLAYER_STATE_PAUSED:
813 switch (pending_state) {
814 case MM_PLAYER_STATE_PLAYING:
815 __gst_pause(player, TRUE);
818 case MM_PLAYER_STATE_PAUSED:
819 LOGD("player is already going to paused state, there is nothing to do.\n");
822 case MM_PLAYER_STATE_NONE:
823 case MM_PLAYER_STATE_NULL:
824 case MM_PLAYER_STATE_READY:
826 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
832 case MM_PLAYER_STATE_PLAYING:
834 switch (pending_state) {
835 case MM_PLAYER_STATE_NONE:
837 if (current_state != MM_PLAYER_STATE_PLAYING)
838 __gst_resume(player, TRUE);
842 case MM_PLAYER_STATE_PAUSED:
843 /* NOTE: It should be worked as asynchronously.
844 * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly.
846 if (current_state == MM_PLAYER_STATE_PLAYING) {
847 /* NOTE: If the current state is PLAYING, it means, async __gst_pause() is not completed yet.
848 * The current state should be changed to paused purposely to prevent state conflict.
850 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
852 __gst_resume(player, TRUE);
855 case MM_PLAYER_STATE_PLAYING:
856 LOGD("player is already going to playing state, there is nothing to do.\n");
859 case MM_PLAYER_STATE_NULL:
860 case MM_PLAYER_STATE_READY:
862 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
868 case MM_PLAYER_STATE_NULL:
869 case MM_PLAYER_STATE_READY:
870 case MM_PLAYER_STATE_NONE:
872 LOGW("invalid target state [%s].\n", MMPLAYER_STATE_GET_NAME(target_state));
876 /* NOTE : during the buffering, pause the player for stopping pipeline clock.
877 * it's for stopping the pipeline clock to prevent dropping the data in sink element.
879 switch (pending_state) {
880 case MM_PLAYER_STATE_NONE:
882 if (current_state != MM_PLAYER_STATE_PAUSED) {
883 /* rtsp streaming pause makes rtsp server stop sending data. */
884 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
885 LOGD("set pause state during buffering\n");
886 __gst_pause(player, TRUE);
892 case MM_PLAYER_STATE_PLAYING:
893 /* rtsp streaming pause makes rtsp server stop sending data. */
894 if (!MMPLAYER_IS_RTSP_STREAMING(player))
895 __gst_pause(player, TRUE);
898 case MM_PLAYER_STATE_PAUSED:
901 case MM_PLAYER_STATE_NULL:
902 case MM_PLAYER_STATE_READY:
904 LOGW("invalid pending state [%s].\n", MMPLAYER_STATE_GET_NAME(pending_state));
914 __mmplayer_drop_subtitle(mm_player_t* player, gboolean is_drop)
916 MMPlayerGstElement *textbin;
919 MMPLAYER_RETURN_IF_FAIL(player &&
921 player->pipeline->textbin);
923 MMPLAYER_RETURN_IF_FAIL(player->pipeline->textbin[MMPLAYER_T_IDENTITY].gst);
925 textbin = player->pipeline->textbin;
928 LOGD("Drop subtitle text after getting EOS\n");
930 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", FALSE, NULL);
931 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)1.0, NULL);
933 player->is_subtitle_force_drop = TRUE;
935 if (player->is_subtitle_force_drop == TRUE) {
936 LOGD("Enable subtitle data path without drop\n");
938 g_object_set(textbin[MMPLAYER_T_IDENTITY].gst, "drop-probability", (gfloat)0.0, NULL);
939 g_object_set(textbin[MMPLAYER_T_FAKE_SINK].gst, "async", TRUE, NULL);
941 LOGD("non-connected with external display");
943 player->is_subtitle_force_drop = FALSE;
949 __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
951 VariantData *var_info = NULL;
952 g_return_val_if_fail(self != NULL, NULL);
954 var_info = g_new0(VariantData, 1);
955 if (!var_info) return NULL;
956 var_info->bandwidth = self->bandwidth;
957 var_info->width = self->width;
958 var_info->height = self->height;
962 void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
964 mm_player_t* player = (mm_player_t*)hplayer;
965 GstMessage *msg = NULL;
966 GQueue *queue = NULL;
969 MMPLAYER_RETURN_IF_FAIL(player);
971 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
973 /* destroy the gst bus msg thread */
974 if (player->bus_msg_thread) {
975 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
976 player->bus_msg_thread_exit = TRUE;
977 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
978 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
980 LOGD("gst bus msg thread exit.");
981 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
982 player->bus_msg_thread = NULL;
984 g_mutex_clear(&player->bus_msg_thread_mutex);
985 g_cond_clear(&player->bus_msg_thread_cond);
988 g_mutex_lock(&player->bus_msg_q_lock);
989 queue = player->bus_msg_q;
990 while (!g_queue_is_empty(queue)) {
991 msg = (GstMessage *)g_queue_pop_head(queue);
992 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
993 gst_message_unref(msg);
995 g_mutex_unlock(&player->bus_msg_q_lock);
1000 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
1002 mm_player_t *player = (mm_player_t *) data;
1004 g_return_val_if_fail(player, FALSE);
1005 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
1007 gst_message_ref(msg);
1009 g_mutex_lock(&player->bus_msg_q_lock);
1010 g_queue_push_tail(player->bus_msg_q, msg);
1011 g_mutex_unlock(&player->bus_msg_q_lock);
1013 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1014 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
1015 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1019 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
1021 mm_player_t *player = (mm_player_t*)(data);
1022 GstMessage *msg = NULL;
1026 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1028 player->pipeline->mainbin &&
1029 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
1032 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
1034 LOGE("cannot get BUS from the pipeline");
1038 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1040 LOGD("[handle: %p] gst bus msg thread will be started.", player);
1041 while (!player->bus_msg_thread_exit) {
1042 g_mutex_lock(&player->bus_msg_q_lock);
1043 msg = g_queue_pop_head(player->bus_msg_q);
1044 g_mutex_unlock(&player->bus_msg_q_lock);
1046 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
1049 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1050 /* handle the gst msg */
1051 __mmplayer_gst_callback(msg, player);
1052 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
1053 gst_message_unref(msg);
1056 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
1057 gst_object_unref(GST_OBJECT(bus));
1064 __mmplayer_gst_callback(GstMessage *msg, gpointer data)
1066 mm_player_t* player = (mm_player_t*)(data);
1067 static gboolean async_done = FALSE;
1069 MMPLAYER_RETURN_IF_FAIL(player);
1070 MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
1072 switch (GST_MESSAGE_TYPE(msg)) {
1073 case GST_MESSAGE_UNKNOWN:
1074 LOGD("unknown message received\n");
1077 case GST_MESSAGE_EOS:
1079 MMHandleType attrs = 0;
1082 LOGD("GST_MESSAGE_EOS received\n");
1084 /* NOTE : EOS event is comming multiple time. watch out it */
1085 /* check state. we only process EOS when pipeline state goes to PLAYING */
1086 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME)) {
1087 LOGD("EOS received on non-playing state. ignoring it\n");
1091 if (player->pipeline) {
1092 if (player->pipeline->textbin)
1093 __mmplayer_drop_subtitle(player, TRUE);
1095 if ((player->audio_stream_cb) && (player->set_mode.pcm_extraction) && (!player->audio_stream_render_cb_ex)) {
1098 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
1100 LOGD("release audio callback\n");
1102 /* release audio callback */
1103 gst_pad_remove_probe(pad, player->audio_cb_probe_id);
1104 player->audio_cb_probe_id = 0;
1105 /* audio callback should be free because it can be called even though probe remove.*/
1106 player->audio_stream_cb = NULL;
1107 player->audio_stream_cb_user_param = NULL;
1111 if ((player->audio_stream_render_cb_ex) && (!player->audio_stream_sink_sync))
1112 __mmplayer_audio_stream_clear_buffer(player, TRUE);
1114 /* rewind if repeat count is greater then zero */
1115 /* get play count */
1116 attrs = MMPLAYER_GET_ATTRS(player);
1119 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
1121 LOGD("play count: %d, playback rate: %f\n", count, player->playback_rate);
1123 if (count == -1 || player->playback_rate < 0.0) /* default value is 1 */ {
1124 if (player->playback_rate < 0.0) {
1125 player->resumed_by_rewind = TRUE;
1126 _mmplayer_set_mute((MMHandleType)player, 0);
1127 MMPLAYER_POST_MSG(player, MM_MESSAGE_RESUMED_BY_REW, NULL);
1130 __mmplayer_handle_eos_delay(player, player->ini.delay_before_repeat);
1133 player->sent_bos = FALSE;
1135 /* not posting eos when repeating */
1140 if (player->pipeline)
1141 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-eos");
1143 /* post eos message to application */
1144 __mmplayer_handle_eos_delay(player, player->ini.eos_delay);
1146 /* reset last position */
1147 player->last_position = 0;
1151 case GST_MESSAGE_ERROR:
1153 GError *error = NULL;
1154 gchar* debug = NULL;
1156 /* generating debug info before returning error */
1157 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-error");
1159 /* get error code */
1160 gst_message_parse_error(msg, &error, &debug);
1162 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
1163 /* Note : the streaming error from the streaming source is handled
1164 * using __mmplayer_handle_streaming_error.
1166 __mmplayer_handle_streaming_error(player, msg);
1168 /* dump state of all element */
1169 __mmplayer_dump_pipeline_state(player);
1171 /* traslate gst error code to msl error code. then post it
1172 * to application if needed
1174 __mmplayer_handle_gst_error(player, msg, error);
1177 LOGE("error debug : %s", debug);
1180 if (MMPLAYER_IS_HTTP_PD(player))
1181 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
1183 MMPLAYER_FREEIF(debug);
1184 g_error_free(error);
1188 case GST_MESSAGE_WARNING:
1191 GError* error = NULL;
1193 gst_message_parse_warning(msg, &error, &debug);
1195 LOGD("warning : %s\n", error->message);
1196 LOGD("debug : %s\n", debug);
1198 MMPLAYER_POST_MSG(player, MM_MESSAGE_WARNING, NULL);
1200 MMPLAYER_FREEIF(debug);
1201 g_error_free(error);
1205 case GST_MESSAGE_TAG:
1207 LOGD("GST_MESSAGE_TAG\n");
1208 if (!__mmplayer_gst_extract_tag_from_msg(player, msg))
1209 LOGW("failed to extract tags from gstmessage\n");
1213 case GST_MESSAGE_BUFFERING:
1215 MMMessageParamType msg_param = {0, };
1216 int bRet = MM_ERROR_NONE;
1218 if (!(player->pipeline && player->pipeline->mainbin)) {
1219 LOGE("player pipeline handle is null");
1223 if (!MMPLAYER_IS_STREAMING(player))
1226 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
1227 if (!MMPLAYER_CMD_TRYLOCK(player)) {
1228 /* skip the playback control by buffering msg while user request is handled. */
1231 LOGW("[PD mode] can't get cmd lock, only post buffering msg");
1233 gst_message_parse_buffering(msg, &per);
1234 LOGD("[PD mode][%s] buffering %d %%....", GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)), per);
1236 msg_param.connection.buffering = per;
1237 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1241 MMPLAYER_CMD_LOCK(player);
1244 /* ignore the prev buffering message */
1245 if ((player->streamer) && (player->streamer->is_buffering == FALSE)
1246 && (player->streamer->is_buffering_done == TRUE)) {
1247 gint buffer_percent = 0;
1249 gst_message_parse_buffering(msg, &buffer_percent);
1251 if (buffer_percent == MAX_BUFFER_PERCENT) {
1252 LOGD("Ignored all the previous buffering msg!(got %d%%)\n", buffer_percent);
1253 player->streamer->is_buffering_done = FALSE;
1255 MMPLAYER_CMD_UNLOCK(player);
1259 __mmplayer_update_buffer_setting(player, msg);
1261 bRet = __mmplayer_handle_buffering_message(player);
1263 if (bRet == MM_ERROR_NONE) {
1264 msg_param.connection.buffering = player->streamer->buffering_percent;
1265 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1267 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1268 player->pending_resume &&
1269 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1271 player->is_external_subtitle_added_now = FALSE;
1272 player->pending_resume = FALSE;
1273 _mmplayer_resume((MMHandleType)player);
1276 if (MMPLAYER_IS_RTSP_STREAMING(player) &&
1277 (player->streamer->buffering_percent >= MAX_BUFFER_PERCENT)) {
1279 if (player->doing_seek) {
1280 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1281 player->doing_seek = FALSE;
1282 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1283 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1288 } else if (bRet == MM_ERROR_PLAYER_INVALID_STATE) {
1289 if (!player->streamer) {
1290 LOGW("player->streamer is NULL, so discarding the buffering percent update\n");
1291 MMPLAYER_CMD_UNLOCK(player);
1295 if ((MMPLAYER_IS_LIVE_STREAMING(player)) && (MMPLAYER_IS_RTSP_STREAMING(player))) {
1297 LOGD("player->last_position=%"G_GINT64_FORMAT" , player->streamer->buffering_percent=%d \n",
1298 GST_TIME_AS_SECONDS(player->last_position), player->streamer->buffering_percent);
1300 if ((GST_TIME_AS_SECONDS(player->last_position) <= 0) && (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED)) {
1301 msg_param.connection.buffering = player->streamer->buffering_percent;
1302 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1304 LOGD("Not updating Buffering Message for Live RTSP case !!!\n");
1307 msg_param.connection.buffering = player->streamer->buffering_percent;
1308 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1311 MMPLAYER_CMD_UNLOCK(player);
1315 case GST_MESSAGE_STATE_CHANGED:
1317 MMPlayerGstElement *mainbin;
1318 const GValue *voldstate, *vnewstate, *vpending;
1319 GstState oldstate = GST_STATE_NULL;
1320 GstState newstate = GST_STATE_NULL;
1321 GstState pending = GST_STATE_NULL;
1323 if (!(player->pipeline && player->pipeline->mainbin)) {
1324 LOGE("player pipeline handle is null");
1328 mainbin = player->pipeline->mainbin;
1330 /* we only handle messages from pipeline */
1331 if (msg->src != (GstObject *)mainbin[MMPLAYER_M_PIPE].gst)
1334 /* get state info from msg */
1335 voldstate = gst_structure_get_value(gst_message_get_structure(msg), "old-state");
1336 vnewstate = gst_structure_get_value(gst_message_get_structure(msg), "new-state");
1337 vpending = gst_structure_get_value(gst_message_get_structure(msg), "pending-state");
1339 if (!voldstate || !vnewstate) {
1340 LOGE("received msg has wrong format.");
1344 oldstate = (GstState)voldstate->data[0].v_int;
1345 newstate = (GstState)vnewstate->data[0].v_int;
1347 pending = (GstState)vpending->data[0].v_int;
1349 LOGD("state changed [%s] : %s ---> %s final : %s\n",
1350 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
1351 gst_element_state_get_name((GstState)oldstate),
1352 gst_element_state_get_name((GstState)newstate),
1353 gst_element_state_get_name((GstState)pending));
1355 if (newstate == GST_STATE_PLAYING) {
1356 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (player->pending_seek.is_pending)) {
1358 int retVal = MM_ERROR_NONE;
1359 LOGD("trying to play from (%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
1361 retVal = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, TRUE);
1363 if (MM_ERROR_NONE != retVal)
1364 LOGE("failed to seek pending postion. just keep staying current position.\n");
1366 player->pending_seek.is_pending = FALSE;
1370 if (oldstate == newstate) {
1371 LOGD("pipeline reports state transition to old state");
1376 case GST_STATE_VOID_PENDING:
1379 case GST_STATE_NULL:
1382 case GST_STATE_READY:
1385 case GST_STATE_PAUSED:
1387 gboolean prepare_async = FALSE;
1388 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1390 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
1391 __mmplayer_configure_audio_callback(player);
1393 if (!player->sent_bos && oldstate == GST_STATE_READY) {
1394 // managed prepare async case
1395 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &prepare_async);
1396 LOGD("checking prepare mode for async transition - %d", prepare_async);
1399 if (MMPLAYER_IS_STREAMING(player) || MMPLAYER_IS_MS_BUFF_SRC(player) || prepare_async) {
1400 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
1402 if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
1403 __mm_player_streaming_set_content_bitrate(player->streamer,
1404 player->total_maximum_bitrate, player->total_bitrate);
1406 if (player->pending_seek.is_pending) {
1407 LOGW("trying to do pending seek");
1408 MMPLAYER_CMD_LOCK(player);
1409 __gst_pending_seek(player);
1410 MMPLAYER_CMD_UNLOCK(player);
1416 case GST_STATE_PLAYING:
1418 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
1420 if (MMPLAYER_IS_STREAMING(player)) {
1421 // managed prepare async case when buffering is completed
1422 // pending state should be reset otherwise, it's still playing even though it's resumed after bufferging.
1423 if ((MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) ||
1424 (MMPLAYER_PENDING_STATE(player) == MM_PLAYER_STATE_PLAYING))
1425 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
1427 if (MMPLAYER_IS_RTSP_STREAMING(player) && (MMPLAYER_IS_LIVE_STREAMING(player))) {
1429 LOGD("Current Buffering Percent = %d", player->streamer->buffering_percent);
1430 if (player->streamer->buffering_percent < 100) {
1432 MMMessageParamType msg_param = {0, };
1433 LOGW("Posting Buffering Completed Message to Application !!!");
1435 msg_param.connection.buffering = 100;
1436 MMPLAYER_POST_MSG(player, MM_MESSAGE_BUFFERING, &msg_param);
1441 if (player->gapless.stream_changed) {
1442 _mmplayer_update_content_attrs(player, ATTR_ALL);
1443 player->gapless.stream_changed = FALSE;
1446 if (player->doing_seek && async_done) {
1447 player->doing_seek = FALSE;
1449 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1460 case GST_MESSAGE_CLOCK_LOST:
1462 GstClock *clock = NULL;
1463 gboolean need_new_clock = FALSE;
1465 gst_message_parse_clock_lost(msg, &clock);
1466 LOGD("GST_MESSAGE_CLOCK_LOST : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1468 if (!player->videodec_linked)
1469 need_new_clock = TRUE;
1470 else if (!player->ini.use_system_clock)
1471 need_new_clock = TRUE;
1473 if (need_new_clock) {
1474 LOGD("Provide clock is TRUE, do pause->resume\n");
1475 __gst_pause(player, FALSE);
1476 __gst_resume(player, FALSE);
1481 case GST_MESSAGE_NEW_CLOCK:
1483 GstClock *clock = NULL;
1484 gst_message_parse_new_clock(msg, &clock);
1485 LOGD("GST_MESSAGE_NEW_CLOCK : %s\n", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
1489 case GST_MESSAGE_ELEMENT:
1491 const gchar *structure_name;
1492 gint count = 0, idx = 0;
1493 MMHandleType attrs = 0;
1495 attrs = MMPLAYER_GET_ATTRS(player);
1497 LOGE("cannot get content attribute");
1501 if (gst_message_get_structure(msg) == NULL)
1504 structure_name = gst_structure_get_name(gst_message_get_structure(msg));
1505 if (!structure_name)
1508 LOGD("GST_MESSAGE_ELEMENT %s from %s", structure_name, GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)));
1510 if (!strcmp(structure_name, "adaptive-streaming-variant")) {
1511 const GValue *var_info = NULL;
1513 var_info = gst_structure_get_value(gst_message_get_structure(msg), "video-variant-info");
1514 if (var_info != NULL) {
1515 if (player->adaptive_info.var_list)
1516 g_list_free_full(player->adaptive_info.var_list, g_free);
1518 /* share addr or copy the list */
1519 player->adaptive_info.var_list =
1520 g_list_copy_deep((GList *)g_value_get_pointer(var_info), (GCopyFunc)__mmplayer_adaptive_var_info, NULL);
1522 count = g_list_length(player->adaptive_info.var_list);
1524 VariantData *temp = NULL;
1526 /* print out for debug */
1527 LOGD("num of variant_info %d", count);
1528 for (idx = 0; idx < count; idx++) {
1529 temp = g_list_nth_data(player->adaptive_info.var_list, idx);
1531 LOGD("variant(%d) [b]%d [w]%d [h]%d ", idx, temp->bandwidth, temp->width, temp->height);
1537 if (!strcmp(structure_name, "prepare-decode-buffers")) {
1538 gint num_buffers = 0;
1539 gint extra_num_buffers = 0;
1541 if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) {
1542 player->video_num_buffers = num_buffers;
1543 LOGD("video_num_buffers : %d", player->video_num_buffers);
1546 if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) {
1547 player->video_extra_num_buffers = extra_num_buffers;
1548 LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers);
1553 if (!strcmp(structure_name, "Language_list")) {
1554 const GValue *lang_list = NULL;
1555 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1556 if (lang_list != NULL) {
1557 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1559 LOGD("Total audio tracks(from parser) = %d \n", count);
1563 if (!strcmp(structure_name, "Ext_Sub_Language_List")) {
1564 const GValue *lang_list = NULL;
1565 MMPlayerLangStruct *temp = NULL;
1567 lang_list = gst_structure_get_value(gst_message_get_structure(msg), "lang_list");
1568 if (lang_list != NULL) {
1569 count = g_list_length((GList *)g_value_get_pointer(lang_list));
1571 MMPLAYER_SUBTITLE_INFO_LOCK(player);
1572 player->subtitle_language_list = (GList *)g_value_get_pointer(lang_list);
1573 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)count);
1574 if (mmf_attrs_commit(attrs))
1575 LOGE("failed to commit.\n");
1576 LOGD("Total subtitle tracks = %d \n", count);
1579 temp = g_list_nth_data(player->subtitle_language_list, count - 1);
1581 LOGD("value of lang_key is %s and lang_code is %s",
1582 temp->language_key, temp->language_code);
1585 MMPLAYER_SUBTITLE_INFO_SIGNAL(player);
1586 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
1591 /* custom message */
1592 if (!strcmp(structure_name, "audio_codec_not_supported")) {
1593 MMMessageParamType msg_param = {0,};
1594 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
1595 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
1598 /* custom message for RTSP attribute :
1599 RTSP case, buffer is not come from server before PLAYING state. However,we have to get attribute after PAUSE state chaged.
1600 sdp which has contents info is received when rtsp connection is opened.
1601 extract duration ,codec info , resolution from sdp and get it by GstMessage */
1602 if (!strcmp(structure_name, "rtspsrc_properties")) {
1604 gchar *audio_codec = NULL;
1605 gchar *video_codec = NULL;
1606 gchar *video_frame_size = NULL;
1608 gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL);
1609 LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration));
1610 player->streaming_type = __mmplayer_get_stream_service_type(player);
1612 gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL);
1613 LOGD("rtsp_audio_codec : %s", audio_codec);
1615 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
1617 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL);
1618 LOGD("rtsp_video_codec : %s", video_codec);
1620 mm_attrs_set_string_by_name(player->attrs, "content_video_codec", video_codec);
1622 gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL);
1623 LOGD("rtsp_video_frame_size : %s", video_frame_size);
1624 if (video_frame_size) {
1626 char *seperator = strchr(video_frame_size, '-');
1629 char video_width[10] = {0,};
1630 int frame_size_len = strlen(video_frame_size);
1631 int separtor_len = strlen(seperator);
1633 strncpy(video_width, video_frame_size, (frame_size_len - separtor_len));
1634 mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width));
1637 mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator));
1641 if (mmf_attrs_commit(attrs))
1642 LOGE("failed to commit.\n");
1647 case GST_MESSAGE_DURATION_CHANGED:
1649 LOGD("GST_MESSAGE_DURATION_CHANGED\n");
1650 if (!__mmplayer_gst_handle_duration(player, msg))
1651 LOGW("failed to update duration");
1656 case GST_MESSAGE_ASYNC_START:
1657 LOGD("GST_MESSAGE_ASYNC_START : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1660 case GST_MESSAGE_ASYNC_DONE:
1662 LOGD("GST_MESSAGE_ASYNC_DONE : %s\n", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg)));
1664 /* we only handle messages from pipeline */
1665 if (msg->src != (GstObject *)player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)
1668 if (player->doing_seek) {
1669 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
1670 player->doing_seek = FALSE;
1671 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
1672 } else if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PLAYING) {
1673 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1674 (player->streamer) &&
1675 (player->streamer->streaming_buffer_type == BUFFER_TYPE_MUXED) &&
1676 (player->streamer->is_buffering == FALSE)) {
1677 GstQuery *query = NULL;
1678 gboolean busy = FALSE;
1681 if (player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer) {
1682 query = gst_query_new_buffering(GST_FORMAT_PERCENT);
1683 if (gst_element_query(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer, query))
1684 gst_query_parse_buffering_percent(query, &busy, &percent);
1685 gst_query_unref(query);
1687 LOGD("buffered percent(%s): %d\n",
1688 GST_ELEMENT_NAME(player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffer), percent);
1691 if (percent >= 100) {
1692 player->streamer->is_buffering = FALSE;
1693 __mmplayer_handle_buffering_message(player);
1703 #if 0 /* delete unnecessary logs */
1704 case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE\n"); break;
1705 case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START\n"); break;
1706 case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS\n"); break;
1707 case GST_MESSAGE_PROGRESS: LOGD("GST_MESSAGE_PROGRESS\n"); break;
1708 case GST_MESSAGE_ANY: LOGD("GST_MESSAGE_ANY\n"); break;
1709 case GST_MESSAGE_INFO: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1710 case GST_MESSAGE_STATE_DIRTY: LOGD("GST_MESSAGE_STATE_DIRTY\n"); break;
1711 case GST_MESSAGE_STEP_DONE: LOGD("GST_MESSAGE_STEP_DONE\n"); break;
1712 case GST_MESSAGE_CLOCK_PROVIDE: LOGD("GST_MESSAGE_CLOCK_PROVIDE\n"); break;
1713 case GST_MESSAGE_STRUCTURE_CHANGE: LOGD("GST_MESSAGE_STRUCTURE_CHANGE\n"); break;
1714 case GST_MESSAGE_STREAM_STATUS: LOGD("GST_MESSAGE_STREAM_STATUS\n"); break;
1715 case GST_MESSAGE_APPLICATION: LOGD("GST_MESSAGE_APPLICATION\n"); break;
1716 case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START\n"); break;
1717 case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE\n"); break;
1718 case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY\n"); break;
1725 /* should not call 'gst_message_unref(msg)' */
1730 __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg)
1736 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1737 MMPLAYER_RETURN_VAL_IF_FAIL(msg, FALSE);
1739 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1740 (msg->src) && (msg->src == (GstObject *)player->pipeline->mainbin[MMPLAYER_M_SRC].gst)) {
1741 LOGD("msg src : [%s]", GST_ELEMENT_NAME(GST_ELEMENT_CAST(msg->src)));
1743 if (gst_element_query_duration(GST_ELEMENT_CAST(msg->src), GST_FORMAT_BYTES, &bytes)) {
1744 LOGD("data total size of http content: %"G_GINT64_FORMAT, bytes);
1745 player->http_content_size = (bytes > 0) ? (bytes) : (0);
1748 /* handling audio clip which has vbr. means duration is keep changing */
1749 _mmplayer_update_content_attrs(player, ATTR_DURATION);
1756 static void __mmplayer_get_metadata_360_from_tags(GstTagList *tags,
1757 mm_player_spherical_metadata_t *metadata) {
1758 gst_tag_list_get_int(tags, "is_spherical", &metadata->is_spherical);
1759 gst_tag_list_get_int(tags, "is_stitched", &metadata->is_stitched);
1760 gst_tag_list_get_string(tags, "stitching_software",
1761 &metadata->stitching_software);
1762 gst_tag_list_get_string(tags, "projection_type",
1763 &metadata->projection_type_string);
1764 gst_tag_list_get_string(tags, "stereo_mode", &metadata->stereo_mode_string);
1765 gst_tag_list_get_int(tags, "source_count", &metadata->source_count);
1766 gst_tag_list_get_int(tags, "init_view_heading",
1767 &metadata->init_view_heading);
1768 gst_tag_list_get_int(tags, "init_view_pitch", &metadata->init_view_pitch);
1769 gst_tag_list_get_int(tags, "init_view_roll", &metadata->init_view_roll);
1770 gst_tag_list_get_int(tags, "timestamp", &metadata->timestamp);
1771 gst_tag_list_get_int(tags, "full_pano_width_pixels",
1772 &metadata->full_pano_width_pixels);
1773 gst_tag_list_get_int(tags, "full_pano_height_pixels",
1774 &metadata->full_pano_height_pixels);
1775 gst_tag_list_get_int(tags, "cropped_area_image_width",
1776 &metadata->cropped_area_image_width);
1777 gst_tag_list_get_int(tags, "cropped_area_image_height",
1778 &metadata->cropped_area_image_height);
1779 gst_tag_list_get_int(tags, "cropped_area_left",
1780 &metadata->cropped_area_left);
1781 gst_tag_list_get_int(tags, "cropped_area_top", &metadata->cropped_area_top);
1782 gst_tag_list_get_int(tags, "ambisonic_type", &metadata->ambisonic_type);
1783 gst_tag_list_get_int(tags, "ambisonic_format", &metadata->ambisonic_format);
1784 gst_tag_list_get_int(tags, "ambisonic_order", &metadata->ambisonic_order);
1788 __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage* msg)
1791 /* macro for better code readability */
1792 #define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \
1793 if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\
1794 if (string != NULL) { \
1795 SECURE_LOGD("update tag string : %s\n", string); \
1796 if (strlen(string) > MM_MAX_STRING_LENGTH) { \
1797 char *new_string = malloc(MM_MAX_STRING_LENGTH); \
1798 strncpy(new_string, string, MM_MAX_STRING_LENGTH-1); \
1799 new_string[MM_MAX_STRING_LENGTH-1] = '\0'; \
1800 mm_attrs_set_string_by_name(attribute, playertag, new_string); \
1801 g_free(new_string); \
1802 new_string = NULL; \
1804 mm_attrs_set_string_by_name(attribute, playertag, string); \
1811 #define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \
1813 GstSample *sample = NULL;\
1814 if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\
1815 GstMapInfo info = GST_MAP_INFO_INIT;\
1816 buffer = gst_sample_get_buffer(sample);\
1817 if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) {\
1818 LOGD("failed to get image data from tag");\
1819 gst_sample_unref(sample);\
1822 SECURE_LOGD("update album cover data : %p, size : %d\n", info.data, info.size);\
1823 MMPLAYER_FREEIF(player->album_art);\
1824 player->album_art = (gchar *)g_malloc(info.size);\
1825 if (player->album_art) {\
1826 memcpy(player->album_art, info.data, info.size);\
1827 mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\
1828 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\
1829 msg_param.data = (void *)player->album_art;\
1830 msg_param.size = info.size;\
1831 MMPLAYER_POST_MSG(player, MM_MESSAGE_IMAGE_BUFFER, &msg_param);\
1832 SECURE_LOGD("post message image buffer data : %p, size : %d\n", info.data, info.size);\
1835 gst_buffer_unmap(buffer, &info);\
1836 gst_sample_unref(sample);\
1840 #define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \
1842 if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \
1845 gchar *tag_list_str = NULL; \
1846 MMPlayerTrackType track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1847 if (strstr(GST_OBJECT_NAME(msg->src), "audio")) \
1848 track_type = MM_PLAYER_TRACK_TYPE_AUDIO; \
1849 else if (strstr(GST_OBJECT_NAME(msg->src), "video")) \
1850 track_type = MM_PLAYER_TRACK_TYPE_VIDEO; \
1852 track_type = MM_PLAYER_TRACK_TYPE_TEXT; \
1853 if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \
1854 if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \
1855 mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \
1856 player->bitrate[track_type] = v_uint; \
1857 player->total_bitrate = 0; \
1858 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1859 player->total_bitrate += player->bitrate[i]; \
1860 mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \
1861 SECURE_LOGD("update bitrate %d[bps] of stream #%d.\n", v_uint, (int)track_type); \
1862 } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \
1863 player->maximum_bitrate[track_type] = v_uint; \
1864 player->total_maximum_bitrate = 0; \
1865 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \
1866 player->total_maximum_bitrate += player->maximum_bitrate[i]; \
1867 mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\
1868 SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d\n", v_uint, (int)track_type);\
1870 mm_attrs_set_int_by_name(attribute, playertag, v_uint); \
1873 g_free(tag_list_str); \
1878 #define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \
1879 if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\
1880 if (date != NULL) {\
1881 string = g_strdup_printf("%d", g_date_get_year(date));\
1882 mm_attrs_set_string_by_name(attribute, playertag, string);\
1883 SECURE_LOGD("metainfo year : %s\n", string);\
1884 MMPLAYER_FREEIF(string);\
1889 #define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \
1890 if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\
1891 if (datetime != NULL) {\
1892 string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\
1893 mm_attrs_set_string_by_name(attribute, playertag, string);\
1894 SECURE_LOGD("metainfo year : %s\n", string);\
1895 MMPLAYER_FREEIF(string);\
1896 gst_date_time_unref(datetime);\
1900 #define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \
1901 if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\
1903 /* FIXIT : don't know how to store date */\
1909 #define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \
1910 if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\
1912 /* FIXIT : don't know how to store date */\
1918 /* function start */
1919 GstTagList* tag_list = NULL;
1921 MMHandleType attrs = 0;
1923 char *string = NULL;
1926 GstDateTime *datetime = NULL;
1928 GstBuffer *buffer = NULL;
1930 MMMessageParamType msg_param = {0, };
1932 /* currently not used. but those are needed for above macro */
1933 //guint64 v_uint64 = 0;
1934 //gdouble v_double = 0;
1936 MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE);
1938 attrs = MMPLAYER_GET_ATTRS(player);
1940 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE);
1942 /* get tag list from gst message */
1943 gst_message_parse_tag(msg, &tag_list);
1945 /* store tags to player attributes */
1946 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title");
1947 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */
1948 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist");
1949 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */
1950 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album");
1951 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */
1952 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author");
1953 MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date");
1954 MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date");
1955 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre");
1956 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */
1957 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */
1958 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num");
1959 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */
1960 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */
1961 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */
1962 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */
1963 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description");
1964 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */
1965 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */
1966 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */
1967 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright");
1968 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */
1969 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */
1970 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */
1971 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */
1972 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */
1973 /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */
1974 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */
1975 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec");
1976 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec");
1977 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate");
1978 MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate");
1979 MMPLAYER_UPDATE_TAG_LOCK(player);
1980 MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover");
1981 MMPLAYER_UPDATE_TAG_UNLOCK(player);
1982 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */
1983 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */
1984 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */
1985 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */
1986 /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */
1987 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */
1988 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */
1989 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */
1990 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */
1991 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */
1992 /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */
1993 /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */
1994 MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation");
1996 if (strstr(GST_OBJECT_NAME(msg->src), "demux")) {
1997 if (player->video360_metadata.is_spherical == -1) {
1998 __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata);
1999 mm_attrs_set_int_by_name(attrs, "content_video_is_spherical",
2000 player->video360_metadata.is_spherical);
2001 if (player->video360_metadata.is_spherical == 1) {
2002 LOGD("This is spherical content for 360 playback.");
2003 player->is_content_spherical = TRUE;
2005 LOGD("This is not spherical content");
2006 player->is_content_spherical = FALSE;
2009 if (player->video360_metadata.projection_type_string) {
2010 if (!strcmp(player->video360_metadata.projection_type_string, "equirectangular")) {
2011 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
2013 LOGE("Projection %s: code not implemented.\n", player->video360_metadata.projection_type_string);
2014 player->is_content_spherical = player->is_video360_enabled = FALSE;
2018 if (player->video360_metadata.stereo_mode_string) {
2019 if (!strcmp(player->video360_metadata.stereo_mode_string, "mono")) {
2020 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
2021 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "left-right")) {
2022 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_LEFT_RIGHT;
2023 } else if (!strcmp(player->video360_metadata.stereo_mode_string, "top-bottom")) {
2024 player->video360_metadata.stereo_mode = VIDEO360_MODE_STEREOSCOPIC_TOP_BOTTOM;
2026 LOGE("Stereo mode %s: code not implemented.\n", player->video360_metadata.stereo_mode_string);
2027 player->is_content_spherical = player->is_video360_enabled = FALSE;
2033 if (mmf_attrs_commit(attrs))
2034 LOGE("failed to commit.\n");
2036 gst_tag_list_free(tag_list);
2042 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
2044 mm_player_t* player = (mm_player_t*) data;
2048 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
2049 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
2050 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
2051 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
2053 * [1] audio and video will be dumped with filesink.
2054 * [2] autoplugging is done by just using pad caps.
2055 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
2056 * and the video will be dumped via filesink.
2058 if (player->num_dynamic_pad == 0) {
2059 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
2061 if (!__mmplayer_gst_remove_fakesink(player,
2062 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
2063 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
2064 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
2065 * source element are not same. To overcome this situation, this function will called
2066 * several places and several times. Therefore, this is not an error case.
2071 /* create dot before error-return. for debugging */
2072 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
2074 player->no_more_pad = TRUE;
2080 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
2082 GstElement* parent = NULL;
2084 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
2086 /* if we have no fakesink. this meas we are using decodebin which doesn'
2087 t need to add extra fakesink */
2088 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
2091 MMPLAYER_FSINK_LOCK(player);
2096 /* get parent of fakesink */
2097 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
2099 LOGD("fakesink already removed\n");
2103 gst_element_set_locked_state(fakesink->gst, TRUE);
2105 /* setting the state to NULL never returns async
2106 * so no need to wait for completion of state transiton
2108 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
2109 LOGE("fakesink state change failure!\n");
2110 /* FIXIT : should I return here? or try to proceed to next? */
2113 /* remove fakesink from it's parent */
2114 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
2115 LOGE("failed to remove fakesink\n");
2117 gst_object_unref(parent);
2122 gst_object_unref(parent);
2124 LOGD("state-holder removed\n");
2126 gst_element_set_locked_state(fakesink->gst, FALSE);
2128 MMPLAYER_FSINK_UNLOCK(player);
2133 gst_element_set_locked_state(fakesink->gst, FALSE);
2135 MMPLAYER_FSINK_UNLOCK(player);
2141 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
2143 GstPad *sinkpad = NULL;
2144 GstCaps* caps = NULL;
2145 GstElement* new_element = NULL;
2146 GstStructure* str = NULL;
2147 const gchar* name = NULL;
2149 mm_player_t* player = (mm_player_t*) data;
2153 MMPLAYER_RETURN_IF_FAIL(element && pad);
2154 MMPLAYER_RETURN_IF_FAIL(player &&
2156 player->pipeline->mainbin);
2159 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
2160 * num_dynamic_pad will decreased after creating a sinkbin.
2162 player->num_dynamic_pad++;
2163 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
2165 caps = gst_pad_query_caps(pad, NULL);
2167 MMPLAYER_CHECK_NULL(caps);
2169 /* clear previous result*/
2170 player->have_dynamic_pad = FALSE;
2172 str = gst_caps_get_structure(caps, 0);
2175 LOGE("cannot get structure from caps.\n");
2179 name = gst_structure_get_name(str);
2181 LOGE("cannot get mimetype from structure.\n");
2185 if (strstr(name, "video")) {
2187 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2189 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
2190 if (player->v_stream_caps) {
2191 gst_caps_unref(player->v_stream_caps);
2192 player->v_stream_caps = NULL;
2195 new_element = gst_element_factory_make("fakesink", NULL);
2196 player->num_dynamic_pad--;
2201 /* clear previous result*/
2202 player->have_dynamic_pad = FALSE;
2204 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
2205 LOGE("failed to autoplug for caps");
2209 /* check if there's dynamic pad*/
2210 if (player->have_dynamic_pad) {
2211 LOGE("using pad caps assums there's no dynamic pad !\n");
2215 gst_caps_unref(caps);
2220 /* excute new_element if created*/
2222 LOGD("adding new element to pipeline\n");
2224 /* set state to READY before add to bin */
2225 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
2227 /* add new element to the pipeline */
2228 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
2229 LOGE("failed to add autoplug element to bin\n");
2233 /* get pad from element */
2234 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
2236 LOGE("failed to get sinkpad from autoplug element\n");
2241 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2242 LOGE("failed to link autoplug element\n");
2246 gst_object_unref(sinkpad);
2249 /* run. setting PLAYING here since streamming source is live source */
2250 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
2254 gst_caps_unref(caps);
2260 STATE_CHANGE_FAILED:
2262 /* FIXIT : take care if new_element has already added to pipeline */
2264 gst_object_unref(GST_OBJECT(new_element));
2267 gst_object_unref(GST_OBJECT(sinkpad));
2270 gst_caps_unref(caps);
2272 /* FIXIT : how to inform this error to MSL ????? */
2273 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
2274 * then post an error to application
2278 static GstPadProbeReturn
2279 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
2281 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
2282 return GST_PAD_PROBE_OK;
2285 static GstPadProbeReturn
2286 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
2288 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2289 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
2290 mm_player_t* player = (mm_player_t*)data;
2291 GstCaps* caps = NULL;
2292 GstStructure* str = NULL;
2293 const gchar* name = NULL;
2294 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2297 if (GST_EVENT_IS_DOWNSTREAM(event)) {
2298 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
2299 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
2300 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
2301 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
2303 } else if (GST_EVENT_IS_UPSTREAM(event)) {
2304 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
2308 caps = gst_pad_query_caps(pad, NULL);
2310 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
2314 str = gst_caps_get_structure(caps, 0);
2316 LOGE("failed to get structure from caps");
2320 name = gst_structure_get_name(str);
2322 LOGE("failed to get name from str");
2326 if (strstr(name, "audio")) {
2327 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2328 } else if (strstr(name, "video")) {
2329 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2331 /* text track is not supportable */
2332 LOGE("invalid name %s", name);
2336 switch (GST_EVENT_TYPE(event)) {
2339 /* in case of gapless, drop eos event not to send it to sink */
2340 if (player->gapless.reconfigure && !player->msg_posted) {
2341 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
2342 ret = GST_PAD_PROBE_DROP;
2346 case GST_EVENT_STREAM_START:
2348 gint64 stop_running_time = 0;
2349 gint64 position_running_time = 0;
2350 gint64 position = 0;
2353 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
2354 if ((player->gapless.update_segment[idx] == TRUE) ||
2355 !(player->selector[idx].event_probe_id)) {
2356 /* LOGW("[%d] skip", idx); */
2360 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
2362 gst_segment_to_running_time(&player->gapless.segment[idx],
2363 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
2364 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
2366 gst_segment_to_running_time(&player->gapless.segment[idx],
2367 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
2369 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
2371 gst_segment_to_running_time(&player->gapless.segment[idx],
2372 GST_FORMAT_TIME, player->duration);
2375 position_running_time =
2376 gst_segment_to_running_time(&player->gapless.segment[idx],
2377 GST_FORMAT_TIME, player->gapless.segment[idx].position);
2379 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
2380 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
2382 GST_TIME_ARGS(stop_running_time),
2383 GST_TIME_ARGS(position_running_time),
2384 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
2385 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
2387 position_running_time = MAX(position_running_time, stop_running_time);
2388 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
2389 GST_FORMAT_TIME, player->gapless.segment[idx].start);
2390 position_running_time = MAX(0, position_running_time);
2391 position = MAX(position, position_running_time);
2394 if (position != 0) {
2395 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2396 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
2397 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
2399 player->gapless.start_time[stream_type] += position;
2403 case GST_EVENT_FLUSH_STOP:
2405 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
2406 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
2407 player->gapless.start_time[stream_type] = 0;
2410 case GST_EVENT_SEGMENT:
2415 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
2416 gst_event_copy_segment(event, &segment);
2418 if (segment.format == GST_FORMAT_TIME) {
2419 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
2420 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
2421 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
2422 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
2423 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
2424 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
2426 /* keep the all the segment ev to cover the seeking */
2427 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
2428 player->gapless.update_segment[stream_type] = TRUE;
2430 if (!player->gapless.running)
2433 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
2435 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
2437 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
2438 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
2439 gst_event_unref(event);
2440 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2446 gdouble proportion = 0.0;
2447 GstClockTimeDiff diff = 0;
2448 GstClockTime timestamp = 0;
2449 gint64 running_time_diff = -1;
2450 GstQOSType type = 0;
2451 GstEvent *tmpev = NULL;
2453 running_time_diff = player->gapless.segment[stream_type].base;
2455 if (running_time_diff <= 0) /* don't need to adjust */
2458 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
2459 gst_event_unref(event);
2461 if (timestamp < running_time_diff) {
2462 LOGW("QOS event from previous group");
2463 ret = GST_PAD_PROBE_DROP;
2467 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
2468 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
2469 stream_type, GST_TIME_ARGS(timestamp),
2470 GST_TIME_ARGS(running_time_diff),
2471 GST_TIME_ARGS(timestamp - running_time_diff));
2473 timestamp -= running_time_diff;
2475 /* That case is invalid for QoS events */
2476 if (diff < 0 && -diff > timestamp) {
2477 LOGW("QOS event from previous group");
2478 ret = GST_PAD_PROBE_DROP;
2482 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
2483 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
2493 gst_caps_unref(caps);
2498 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2500 mm_player_t* player = NULL;
2501 GstElement* pipeline = NULL;
2502 GstElement* selector = NULL;
2503 GstElement* fakesink = NULL;
2504 GstCaps* caps = NULL;
2505 GstStructure* str = NULL;
2506 const gchar* name = NULL;
2507 GstPad* sinkpad = NULL;
2508 GstPad* srcpad = NULL;
2509 gboolean first_track = FALSE;
2511 enum MainElementID elemId = MMPLAYER_M_NUM;
2512 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2515 player = (mm_player_t*)data;
2517 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2518 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2520 //LOGD("pad-added signal handling\n");
2522 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2524 /* get mimetype from caps */
2525 caps = gst_pad_query_caps(pad, NULL);
2527 LOGE("cannot get caps from pad.\n");
2531 str = gst_caps_get_structure(caps, 0);
2533 LOGE("cannot get structure from caps.\n");
2537 name = gst_structure_get_name(str);
2539 LOGE("cannot get mimetype from structure.\n");
2543 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2544 //LOGD("detected mimetype : %s\n", name);
2546 if (strstr(name, "video")) {
2549 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
2550 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
2552 /* don't make video because of not required, and not support multiple track */
2553 if (stype == MM_DISPLAY_SURFACE_NULL) {
2554 LOGD("no video sink by null surface");
2556 gchar *caps_str = gst_caps_to_string(caps);
2557 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2558 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2559 player->set_mode.video_zc = TRUE;
2561 MMPLAYER_FREEIF(caps_str);
2563 if (player->v_stream_caps) {
2564 gst_caps_unref(player->v_stream_caps);
2565 player->v_stream_caps = NULL;
2568 LOGD("create fakesink instead of videobin");
2571 fakesink = gst_element_factory_make("fakesink", NULL);
2572 if (fakesink == NULL) {
2573 LOGE("ERROR : fakesink create error\n");
2577 if (player->ini.set_dump_element_flag)
2578 __mmplayer_add_dump_buffer_probe(player, fakesink);
2580 player->video_fakesink = fakesink;
2582 /* store it as it's sink element */
2583 __mmplayer_add_sink(player, player->video_fakesink);
2585 gst_bin_add(GST_BIN(pipeline), fakesink);
2588 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2590 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2591 LOGW("failed to link fakesink\n");
2592 gst_object_unref(GST_OBJECT(fakesink));
2596 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
2597 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2598 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
2601 if (player->set_mode.media_packet_video_stream) {
2602 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
2604 MMPLAYER_SIGNAL_CONNECT(player,
2606 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2608 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
2611 MMPLAYER_SIGNAL_CONNECT(player,
2613 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
2615 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
2619 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
2620 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2624 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2625 __mmplayer_gst_decode_callback(elem, pad, player);
2629 LOGD("video selector \n");
2630 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
2631 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
2633 if (strstr(name, "audio")) {
2634 gint samplerate = 0;
2637 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
2638 __mmplayer_gst_decode_callback(elem, pad, player);
2642 LOGD("audio selector \n");
2643 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
2644 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
2646 gst_structure_get_int(str, "rate", &samplerate);
2647 gst_structure_get_int(str, "channels", &channels);
2649 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
2651 fakesink = gst_element_factory_make("fakesink", NULL);
2652 if (fakesink == NULL) {
2653 LOGE("ERROR : fakesink create error\n");
2657 gst_bin_add(GST_BIN(pipeline), fakesink);
2660 sinkpad = gst_element_get_static_pad(fakesink, "sink");
2662 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2663 LOGW("failed to link fakesink\n");
2664 gst_object_unref(GST_OBJECT(fakesink));
2668 g_object_set(G_OBJECT(fakesink), "async", TRUE, NULL);
2669 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
2670 gst_element_set_state(fakesink, GST_STATE_PAUSED);
2674 } else if (strstr(name, "text")) {
2675 LOGD("text selector \n");
2676 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
2677 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
2679 LOGE("wrong elem id \n");
2684 selector = player->pipeline->mainbin[elemId].gst;
2685 if (selector == NULL) {
2686 selector = gst_element_factory_make("input-selector", NULL);
2687 LOGD("Creating input-selector\n");
2688 if (selector == NULL) {
2689 LOGE("ERROR : input-selector create error\n");
2692 g_object_set(selector, "sync-streams", TRUE, NULL);
2694 player->pipeline->mainbin[elemId].id = elemId;
2695 player->pipeline->mainbin[elemId].gst = selector;
2698 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
2700 srcpad = gst_element_get_static_pad(selector, "src");
2702 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2703 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2704 __mmplayer_gst_selector_blocked, NULL, NULL);
2705 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2706 __mmplayer_gst_selector_event_probe, player, NULL);
2708 gst_element_set_state(selector, GST_STATE_PAUSED);
2709 gst_bin_add(GST_BIN(pipeline), selector);
2711 LOGD("input-selector is already created.\n");
2714 LOGD("Calling request pad with selector %p \n", selector);
2715 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2717 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
2719 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2720 LOGW("failed to link selector\n");
2721 gst_object_unref(GST_OBJECT(selector));
2726 LOGD("this is first track --> active track \n");
2727 g_object_set(selector, "active-pad", sinkpad, NULL);
2730 _mmplayer_track_update_info(player, stream_type, sinkpad);
2737 gst_caps_unref(caps);
2740 gst_object_unref(GST_OBJECT(sinkpad));
2745 gst_object_unref(GST_OBJECT(srcpad));
2752 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
2754 GstPad* srcpad = NULL;
2755 MMHandleType attrs = 0;
2756 gint active_index = 0;
2758 // [link] input-selector :: textbin
2759 srcpad = gst_element_get_static_pad(text_selector, "src");
2761 LOGE("failed to get srcpad from selector\n");
2765 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
2767 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
2768 if ((active_index != DEFAULT_TRACK) &&
2769 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
2770 LOGW("failed to change text track\n");
2771 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
2774 player->no_more_pad = TRUE;
2775 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
2777 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2778 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
2779 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
2780 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
2783 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2785 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
2786 player->has_closed_caption = TRUE;
2788 attrs = MMPLAYER_GET_ATTRS(player);
2790 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
2791 if (mmf_attrs_commit(attrs))
2792 LOGE("failed to commit.\n");
2794 LOGE("cannot get content attribute");
2797 gst_object_unref(GST_OBJECT(srcpad));
2803 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2805 mm_player_t* player = (mm_player_t*)data;
2806 GstElement* selector = NULL;
2807 GstElement* queue = NULL;
2809 GstPad* srcpad = NULL;
2810 GstPad* sinkpad = NULL;
2811 GstCaps* caps = NULL;
2812 gchar* caps_str = NULL;
2815 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2817 caps = gst_pad_get_current_caps(pad);
2818 caps_str = gst_caps_to_string(caps);
2819 LOGD("deinterleave new caps : %s\n", caps_str);
2820 MMPLAYER_FREEIF(caps_str);
2821 gst_caps_unref(caps);
2823 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
2824 LOGE("ERROR : queue create error\n");
2828 g_object_set(G_OBJECT(queue),
2829 "max-size-buffers", 10,
2830 "max-size-bytes", 0,
2831 "max-size-time", (guint64)0,
2834 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2837 LOGE("there is no audio channel selector.\n");
2841 srcpad = gst_element_get_static_pad(queue, "src");
2842 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2844 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
2846 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2847 LOGW("failed to link deinterleave - selector\n");
2851 gst_element_set_state(queue, GST_STATE_PAUSED);
2852 player->audio_mode.total_track_num++;
2857 gst_object_unref(GST_OBJECT(srcpad));
2862 gst_object_unref(GST_OBJECT(sinkpad));
2871 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
2873 mm_player_t* player = NULL;
2874 GstElement* selector = NULL;
2875 GstPad* sinkpad = NULL;
2876 gint active_index = 0;
2877 gchar* change_pad_name = NULL;
2878 GstCaps* caps = NULL; // no need to unref
2879 gint default_audio_ch = 0;
2882 player = (mm_player_t*) data;
2884 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
2887 LOGE("there is no audio channel selector.\n");
2891 active_index = player->audio_mode.active_pad_index;
2893 if (active_index != default_audio_ch) {
2894 gint audio_ch = default_audio_ch;
2896 /*To get the new pad from the selector*/
2897 change_pad_name = g_strdup_printf("sink%d", active_index);
2898 if (change_pad_name != NULL) {
2899 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
2900 if (sinkpad != NULL) {
2901 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
2902 g_object_set(selector, "active-pad", sinkpad, NULL);
2904 audio_ch = active_index;
2906 caps = gst_pad_get_current_caps(sinkpad);
2907 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2909 __mmplayer_set_audio_attrs(player, caps);
2910 gst_caps_unref(caps);
2912 MMPLAYER_FREEIF(change_pad_name);
2915 player->audio_mode.active_pad_index = audio_ch;
2916 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
2922 gst_object_unref(sinkpad);
2929 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
2931 mm_player_t* player = NULL;
2932 MMPlayerGstElement *mainbin = NULL;
2934 GstElement* tee = NULL;
2935 GstElement* stereo_queue = NULL;
2936 GstElement* mono_queue = NULL;
2937 GstElement* conv = NULL;
2938 GstElement* filter = NULL;
2939 GstElement* deinterleave = NULL;
2940 GstElement* selector = NULL;
2942 GstPad* srcpad = NULL;
2943 GstPad* selector_srcpad = NULL;
2944 GstPad* sinkpad = NULL;
2945 GstCaps* caps = NULL;
2946 gulong block_id = 0;
2951 player = (mm_player_t*) data;
2953 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2954 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2956 mainbin = player->pipeline->mainbin;
2959 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
2960 LOGE("ERROR : tee create error\n");
2964 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
2965 mainbin[MMPLAYER_M_A_TEE].gst = tee;
2967 gst_element_set_state(tee, GST_STATE_PAUSED);
2970 srcpad = gst_element_get_request_pad(tee, "src_%u");
2971 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2972 LOGE("ERROR : stereo queue create error\n");
2976 g_object_set(G_OBJECT(stereo_queue),
2977 "max-size-buffers", 10,
2978 "max-size-bytes", 0,
2979 "max-size-time", (guint64)0,
2982 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
2983 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
2986 gst_object_unref(GST_OBJECT(srcpad));
2990 srcpad = gst_element_get_request_pad(tee, "src_%u");
2992 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
2993 LOGE("ERROR : mono queue create error\n");
2997 g_object_set(G_OBJECT(mono_queue),
2998 "max-size-buffers", 10,
2999 "max-size-bytes", 0,
3000 "max-size-time", (guint64)0,
3003 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
3004 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
3006 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
3007 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
3010 srcpad = gst_element_get_static_pad(mono_queue, "src");
3011 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
3012 LOGE("ERROR : audioconvert create error\n");
3016 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
3017 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
3021 gst_object_unref(GST_OBJECT(srcpad));
3024 srcpad = gst_element_get_static_pad(conv, "src");
3026 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
3027 LOGE("ERROR : capsfilter create error\n");
3031 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
3032 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
3034 caps = gst_caps_from_string("audio/x-raw-int, "
3035 "width = (int) 16, "
3036 "depth = (int) 16, "
3037 "channels = (int) 2");
3039 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
3040 gst_caps_unref(caps);
3042 gst_element_set_state(conv, GST_STATE_PAUSED);
3043 gst_element_set_state(filter, GST_STATE_PAUSED);
3047 gst_object_unref(GST_OBJECT(srcpad));
3050 srcpad = gst_element_get_static_pad(filter, "src");
3052 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
3053 LOGE("ERROR : deinterleave create error\n");
3057 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
3059 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3060 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
3062 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
3063 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
3065 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
3066 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
3069 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
3070 if (selector == NULL) {
3071 LOGE("ERROR : audio-selector create error\n");
3075 g_object_set(selector, "sync-streams", TRUE, NULL);
3076 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
3078 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
3079 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
3081 selector_srcpad = gst_element_get_static_pad(selector, "src");
3083 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3085 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3086 __mmplayer_gst_selector_blocked, NULL, NULL);
3089 gst_object_unref(GST_OBJECT(srcpad));
3093 srcpad = gst_element_get_static_pad(stereo_queue, "src");
3094 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
3096 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
3097 LOGW("failed to link queue_stereo - selector\n");
3101 player->audio_mode.total_track_num++;
3103 g_object_set(selector, "active-pad", sinkpad, NULL);
3104 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
3105 gst_element_set_state(selector, GST_STATE_PAUSED);
3107 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
3111 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
3112 if (block_id != 0) {
3113 gst_pad_remove_probe(selector_srcpad, block_id);
3118 gst_object_unref(GST_OBJECT(sinkpad));
3123 gst_object_unref(GST_OBJECT(srcpad));
3127 if (selector_srcpad) {
3128 gst_object_unref(GST_OBJECT(selector_srcpad));
3129 selector_srcpad = NULL;
3137 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
3139 mm_player_t* player = NULL;
3140 GstPad* srcpad = NULL;
3141 GstElement* video_selector = NULL;
3142 GstElement* audio_selector = NULL;
3143 GstElement* text_selector = NULL;
3144 MMHandleType attrs = 0;
3145 gint active_index = 0;
3146 gint64 dur_bytes = 0L;
3148 player = (mm_player_t*) data;
3150 LOGD("no-more-pad signal handling\n");
3152 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
3153 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
3154 LOGW("no need to go more");
3156 if (player->gapless.reconfigure) {
3157 player->gapless.reconfigure = FALSE;
3158 MMPLAYER_PLAYBACK_UNLOCK(player);
3164 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
3165 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
3166 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
3167 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
3168 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
3170 if (NULL == player->streamer) {
3171 LOGW("invalid state for buffering");
3175 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
3176 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
3178 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
3179 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
3181 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
3183 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
3184 LOGE("fail to get duration.\n");
3186 // enable use-buffering on queue2 instead of multiqueue(ex)audio only streaming
3187 // use file information was already set on Q2 when it was created.
3188 __mm_player_streaming_set_queue2(player->streamer,
3189 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
3190 TRUE, // use_buffering
3192 init_buffering_time,
3194 player->ini.http_buffering_limit, // high percent
3195 MUXED_BUFFER_TYPE_MEM_QUEUE,
3197 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
3200 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
3201 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
3202 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3203 if (video_selector) {
3204 // [link] input-selector :: videobin
3205 srcpad = gst_element_get_static_pad(video_selector, "src");
3207 LOGE("failed to get srcpad from video selector\n");
3211 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
3212 if (!text_selector && !audio_selector)
3213 player->no_more_pad = TRUE;
3215 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
3217 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3218 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
3219 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
3220 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
3224 if (audio_selector) {
3225 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
3226 if ((active_index != DEFAULT_TRACK) &&
3227 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
3228 LOGW("failed to change audio track\n");
3229 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
3232 // [link] input-selector :: audiobin
3233 srcpad = gst_element_get_static_pad(audio_selector, "src");
3235 LOGE("failed to get srcpad from selector\n");
3239 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
3241 player->no_more_pad = TRUE;
3243 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
3244 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3245 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3246 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3247 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3250 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
3252 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
3254 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
3255 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
3256 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
3257 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
3261 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3263 attrs = MMPLAYER_GET_ATTRS(player);
3265 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
3266 if (mmf_attrs_commit(attrs))
3267 LOGE("failed to commit.\n");
3269 LOGE("cannot get content attribute");
3271 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
3272 LOGD("There is no audio track : remove audiobin");
3274 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
3275 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
3277 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
3278 MMPLAYER_FREEIF(player->pipeline->audiobin);
3281 if (player->num_dynamic_pad == 0)
3282 __mmplayer_pipeline_complete(NULL, player);
3285 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
3287 __mmplayer_handle_text_decode_path(player, text_selector);
3294 gst_object_unref(GST_OBJECT(srcpad));
3298 if (player->gapless.reconfigure) {
3299 player->gapless.reconfigure = FALSE;
3300 MMPLAYER_PLAYBACK_UNLOCK(player);
3305 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
3307 mm_player_t* player = NULL;
3308 MMHandleType attrs = 0;
3309 GstElement* pipeline = NULL;
3310 GstCaps* caps = NULL;
3311 gchar* caps_str = NULL;
3312 GstStructure* str = NULL;
3313 const gchar* name = NULL;
3314 GstPad* sinkpad = NULL;
3315 GstElement* sinkbin = NULL;
3316 gboolean reusing = FALSE;
3317 GstElement *text_selector = NULL;
3320 player = (mm_player_t*) data;
3322 MMPLAYER_RETURN_IF_FAIL(elem && pad);
3323 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3325 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
3327 attrs = MMPLAYER_GET_ATTRS(player);
3329 LOGE("cannot get content attribute\n");
3333 /* get mimetype from caps */
3334 caps = gst_pad_query_caps(pad, NULL);
3336 LOGE("cannot get caps from pad.\n");
3339 caps_str = gst_caps_to_string(caps);
3341 str = gst_caps_get_structure(caps, 0);
3343 LOGE("cannot get structure from caps.\n");
3347 name = gst_structure_get_name(str);
3349 LOGE("cannot get mimetype from structure.\n");
3353 //LOGD("detected mimetype : %s\n", name);
3355 if (strstr(name, "audio")) {
3356 if (player->pipeline->audiobin == NULL) {
3357 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
3358 LOGE("failed to create audiobin. continuing without audio\n");
3362 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3363 LOGD("creating audiosink bin success\n");
3366 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
3367 LOGD("reusing audiobin\n");
3368 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
3371 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
3372 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
3374 player->audiosink_linked = 1;
3376 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3378 LOGE("failed to get pad from sinkbin\n");
3381 } else if (strstr(name, "video")) {
3382 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
3383 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
3384 player->set_mode.video_zc = TRUE;
3386 if (player->pipeline->videobin == NULL) {
3387 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
3388 /* get video surface type */
3389 int surface_type = 0;
3390 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3391 LOGD("display_surface_type(%d)\n", surface_type);
3393 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
3394 LOGD("not make videobin because it dose not want\n");
3398 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3399 /* mark video overlay for acquire */
3400 if (player->video_overlay_resource == NULL) {
3401 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
3402 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3403 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3404 &player->video_overlay_resource)
3405 != MM_RESOURCE_MANAGER_ERROR_NONE) {
3406 LOGE("could not mark video_overlay resource for acquire\n");
3412 player->interrupted_by_resource = FALSE;
3413 /* acquire resources for video overlay */
3414 if (mm_resource_manager_commit(player->resource_manager) !=
3415 MM_RESOURCE_MANAGER_ERROR_NONE) {
3416 LOGE("could not acquire resources for video playing\n");
3420 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
3421 LOGE("failed to create videobin. continuing without video\n");
3425 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3426 LOGD("creating videosink bin success\n");
3429 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
3430 LOGD("re-using videobin\n");
3431 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
3434 player->videosink_linked = 1;
3436 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
3438 LOGE("failed to get pad from sinkbin\n");
3441 } else if (strstr(name, "text")) {
3442 if (player->pipeline->textbin == NULL) {
3443 MMPlayerGstElement* mainbin = NULL;
3445 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3446 LOGE("failed to create text sink bin. continuing without text\n");
3450 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3451 LOGD("creating textsink bin success\n");
3453 /* FIXIT : track number shouldn't be hardcoded */
3454 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
3456 player->textsink_linked = 1;
3457 LOGI("player->textsink_linked set to 1\n");
3459 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
3461 LOGE("failed to get pad from sinkbin\n");
3465 mainbin = player->pipeline->mainbin;
3467 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
3468 /* input selector */
3469 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
3470 if (!text_selector) {
3471 LOGE("failed to create subtitle input selector element\n");
3474 g_object_set(text_selector, "sync-streams", TRUE, NULL);
3476 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
3477 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
3480 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
3481 LOGE("failed to set state(READY) to sinkbin\n");
3485 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
3486 LOGW("failed to add subtitle input selector\n");
3490 LOGD("created element input-selector");
3493 LOGD("already having subtitle input selector");
3494 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
3497 if (!player->textsink_linked) {
3498 LOGD("re-using textbin\n");
3501 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
3503 player->textsink_linked = 1;
3504 LOGI("player->textsink_linked set to 1\n");
3506 LOGD("ignoring internal subtutle since external subtitle is available");
3509 LOGW("unknown type of elementary stream!ignoring it...\n");
3516 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
3517 LOGE("failed to set state(READY) to sinkbin\n");
3521 /* Added for multi audio support to avoid adding audio bin again*/
3523 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
3524 LOGE("failed to add sinkbin to pipeline\n");
3530 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3531 LOGE("failed to get pad from sinkbin\n");
3537 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
3538 LOGE("failed to set state(PAUSED) to sinkbin\n");
3542 if (text_selector) {
3543 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
3544 LOGE("failed to set state(PAUSED) to sinkbin\n");
3550 gst_object_unref(sinkpad);
3554 LOGD("[handle: %p] linking sink bin success", player);
3556 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
3557 * streaming task. if the task blocked, then buffer will not flow to the next element
3558 *(autoplugging element). so this is special hack for streaming. please try to remove it
3560 /* dec stream count. we can remove fakesink if it's zero */
3561 if (player->num_dynamic_pad)
3562 player->num_dynamic_pad--;
3564 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
3566 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
3567 __mmplayer_pipeline_complete(NULL, player);
3571 MMPLAYER_FREEIF(caps_str);
3574 gst_caps_unref(caps);
3577 gst_object_unref(GST_OBJECT(sinkpad));
3579 /* flusing out new attributes */
3580 if (mmf_attrs_commit(attrs))
3581 LOGE("failed to comit attributes\n");
3587 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
3589 int pro_value = 0; // in the case of expection, default will be returned.
3590 int dest_angle = rotation_angle;
3591 int rotation_type = -1;
3593 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3594 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
3595 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
3597 if (rotation_angle >= 360)
3598 dest_angle = rotation_angle - 360;
3600 /* chech if supported or not */
3601 if (dest_angle % 90) {
3602 LOGD("not supported rotation angle = %d", rotation_angle);
3608 * custom_convert - none (B)
3609 * videoflip - none (C)
3611 if (player->set_mode.video_zc) {
3612 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
3613 rotation_type = ROTATION_USING_CUSTOM;
3615 rotation_type = ROTATION_USING_SINK;
3617 int surface_type = 0;
3618 rotation_type = ROTATION_USING_FLIP;
3620 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3621 LOGD("check display surface type attribute: %d", surface_type);
3623 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
3624 rotation_type = ROTATION_USING_SINK;
3626 rotation_type = ROTATION_USING_FLIP; //C
3628 LOGD("using %d type for rotation", rotation_type);
3631 /* get property value for setting */
3632 switch (rotation_type) {
3633 case ROTATION_USING_SINK: // tizenwlsink
3635 switch (dest_angle) {
3639 pro_value = 3; // clockwise 90
3645 pro_value = 1; // counter-clockwise 90
3650 case ROTATION_USING_CUSTOM:
3652 gchar *ename = NULL;
3653 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
3655 if (g_strrstr(ename, "fimcconvert")) {
3656 switch (dest_angle) {
3660 pro_value = 90; // clockwise 90
3666 pro_value = 270; // counter-clockwise 90
3672 case ROTATION_USING_FLIP: // videoflip
3674 switch (dest_angle) {
3678 pro_value = 1; // clockwise 90
3684 pro_value = 3; // counter-clockwise 90
3691 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
3699 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
3701 /* check video sinkbin is created */
3702 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3704 player->pipeline->videobin &&
3705 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
3706 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3707 MM_ERROR_PLAYER_NOT_INITIALIZED);
3709 return MM_ERROR_NONE;
3713 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
3715 int rotation_value = 0;
3716 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
3720 /* check video sinkbin is created */
3721 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3724 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
3726 /* get rotation value to set */
3727 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
3728 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
3729 LOGD("set video param : rotate %d", rotation_value);
3733 __mmplayer_video_param_set_display_visible(mm_player_t* player)
3735 MMHandleType attrs = 0;
3739 /* check video sinkbin is created */
3740 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3743 attrs = MMPLAYER_GET_ATTRS(player);
3744 MMPLAYER_RETURN_IF_FAIL(attrs);
3746 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
3747 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
3748 LOGD("set video param : visible %d", visible);
3752 __mmplayer_video_param_set_display_method(mm_player_t* player)
3754 MMHandleType attrs = 0;
3755 int display_method = 0;
3758 /* check video sinkbin is created */
3759 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3762 attrs = MMPLAYER_GET_ATTRS(player);
3763 MMPLAYER_RETURN_IF_FAIL(attrs);
3765 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
3766 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
3767 LOGD("set video param : method %d", display_method);
3771 __mmplayer_video_param_set_render_rectangle(mm_player_t* player)
3773 MMHandleType attrs = 0;
3774 void *handle = NULL;
3776 int wl_window_x = 0;
3777 int wl_window_y = 0;
3778 int wl_window_width = 0;
3779 int wl_window_height = 0;
3782 /* check video sinkbin is created */
3783 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3786 attrs = MMPLAYER_GET_ATTRS(player);
3787 MMPLAYER_RETURN_IF_FAIL(attrs);
3789 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3792 /*It should be set after setting window*/
3793 mm_attrs_get_int_by_name(attrs, "wl_window_render_x", &wl_window_x);
3794 mm_attrs_get_int_by_name(attrs, "wl_window_render_y", &wl_window_y);
3795 mm_attrs_get_int_by_name(attrs, "wl_window_render_width", &wl_window_width);
3796 mm_attrs_get_int_by_name(attrs, "wl_window_render_height", &wl_window_height);
3798 /* After setting window handle, set render rectangle */
3799 gst_video_overlay_set_render_rectangle(
3800 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3801 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3802 LOGD("set video param : render rectangle : x(%d) y(%d) width(%d) height(%d)",
3803 wl_window_x, wl_window_y, wl_window_width, wl_window_height);
3808 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
3810 MMHandleType attrs = 0;
3811 void *handle = NULL;
3813 /* check video sinkbin is created */
3814 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3817 attrs = MMPLAYER_GET_ATTRS(player);
3818 MMPLAYER_RETURN_IF_FAIL(attrs);
3820 /* common case if using overlay surface */
3821 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
3824 /* default is using wl_surface_id */
3825 unsigned int wl_surface_id = 0;
3826 wl_surface_id = *(int*)handle;
3827 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
3828 gst_video_overlay_set_wl_window_wl_surface_id(
3829 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3832 /* FIXIT : is it error case? */
3833 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
3838 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
3840 bool update_all_param = FALSE;
3843 /* check video sinkbin is created */
3844 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3845 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3847 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
3848 LOGE("can not find tizenwlsink");
3849 return MM_ERROR_PLAYER_INTERNAL;
3852 LOGD("param_name : %s", param_name);
3853 if (!g_strcmp0(param_name, "update_all_param"))
3854 update_all_param = TRUE;
3856 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
3857 __mmplayer_video_param_set_display_overlay(player);
3858 if (update_all_param || !g_strcmp0(param_name, "display_method"))
3859 __mmplayer_video_param_set_display_method(player);
3860 if (update_all_param || !g_strcmp0(param_name, "wl_window_render_x"))
3861 __mmplayer_video_param_set_render_rectangle(player);
3862 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
3863 __mmplayer_video_param_set_display_visible(player);
3864 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
3865 __mmplayer_video_param_set_display_rotation(player);
3867 return MM_ERROR_NONE;
3871 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
3873 MMHandleType attrs = 0;
3874 int surface_type = 0;
3875 int ret = MM_ERROR_NONE;
3879 /* check video sinkbin is created */
3880 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
3881 return MM_ERROR_PLAYER_NOT_INITIALIZED;
3883 attrs = MMPLAYER_GET_ATTRS(player);
3885 LOGE("cannot get content attribute");
3886 return MM_ERROR_PLAYER_INTERNAL;
3888 LOGD("param_name : %s", param_name);
3890 /* update display surface */
3891 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
3892 LOGD("check display surface type attribute: %d", surface_type);
3894 /* configuring display */
3895 switch (surface_type) {
3896 case MM_DISPLAY_SURFACE_OVERLAY:
3898 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
3899 if (ret != MM_ERROR_NONE)
3907 return MM_ERROR_NONE;
3911 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
3913 gboolean disable_overlay = FALSE;
3914 mm_player_t* player = (mm_player_t*) hplayer;
3915 int ret = MM_ERROR_NONE;
3918 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3919 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3920 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3921 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3923 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3924 LOGW("Display control is not supported");
3925 return MM_ERROR_PLAYER_INTERNAL;
3928 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3930 if (audio_only == (bool)disable_overlay) {
3931 LOGE("It's the same with current setting: (%d)", audio_only);
3932 return MM_ERROR_NONE;
3936 LOGE("disable overlay");
3937 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
3939 /* release overlay resource */
3940 if (player->video_overlay_resource != NULL) {
3941 ret = mm_resource_manager_mark_for_release(player->resource_manager,
3942 player->video_overlay_resource);
3943 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3944 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
3947 player->video_overlay_resource = NULL;
3950 ret = mm_resource_manager_commit(player->resource_manager);
3951 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3952 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
3956 /* mark video overlay for acquire */
3957 if (player->video_overlay_resource == NULL) {
3958 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
3959 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
3960 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
3961 &player->video_overlay_resource);
3962 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3963 LOGE("could not prepare for video_overlay resource\n");
3968 player->interrupted_by_resource = FALSE;
3969 /* acquire resources for video overlay */
3970 ret = mm_resource_manager_commit(player->resource_manager);
3971 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
3972 LOGE("could not acquire resources for video playing\n");
3976 LOGD("enable overlay");
3977 __mmplayer_video_param_set_display_overlay(player);
3978 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
3983 return MM_ERROR_NONE;
3987 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
3989 mm_player_t* player = (mm_player_t*) hplayer;
3990 gboolean disable_overlay = FALSE;
3994 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3995 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3996 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3997 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3998 MM_ERROR_PLAYER_NO_OP); /* invalid op */
4000 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
4001 LOGW("Display control is not supported");
4002 return MM_ERROR_PLAYER_INTERNAL;
4005 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
4007 *paudio_only = (bool)(disable_overlay);
4009 LOGD("audio_only : %d", *paudio_only);
4013 return MM_ERROR_NONE;
4017 __mmplayer_gst_element_link_bucket(GList* element_bucket)
4019 GList* bucket = element_bucket;
4020 MMPlayerGstElement* element = NULL;
4021 MMPlayerGstElement* prv_element = NULL;
4022 gint successful_link_count = 0;
4026 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
4028 prv_element = (MMPlayerGstElement*)bucket->data;
4029 bucket = bucket->next;
4031 for (; bucket; bucket = bucket->next) {
4032 element = (MMPlayerGstElement*)bucket->data;
4034 if (element && element->gst) {
4035 /* If next element is audio appsrc then make a separate audio pipeline */
4036 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
4037 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
4038 prv_element = element;
4042 if (prv_element && prv_element->gst) {
4043 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
4044 LOGD("linking [%s] to [%s] success\n",
4045 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4046 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4047 successful_link_count++;
4049 LOGD("linking [%s] to [%s] failed\n",
4050 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
4051 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
4057 prv_element = element;
4062 return successful_link_count;
4066 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
4068 GList* bucket = element_bucket;
4069 MMPlayerGstElement* element = NULL;
4070 int successful_add_count = 0;
4074 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
4075 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
4077 for (; bucket; bucket = bucket->next) {
4078 element = (MMPlayerGstElement*)bucket->data;
4080 if (element && element->gst) {
4081 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
4082 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
4083 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
4084 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
4087 successful_add_count++;
4093 return successful_add_count;
4096 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
4098 mm_player_t* player = (mm_player_t*) data;
4099 GstCaps *caps = NULL;
4100 GstStructure *str = NULL;
4105 MMPLAYER_RETURN_IF_FAIL(pad)
4106 MMPLAYER_RETURN_IF_FAIL(unused)
4107 MMPLAYER_RETURN_IF_FAIL(data)
4109 caps = gst_pad_get_current_caps(pad);
4113 str = gst_caps_get_structure(caps, 0);
4117 name = gst_structure_get_name(str);
4121 LOGD("name = %s\n", name);
4123 if (strstr(name, "audio")) {
4124 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
4126 if (player->audio_stream_changed_cb) {
4127 LOGE("call the audio stream changed cb\n");
4128 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
4130 } else if (strstr(name, "video")) {
4131 if ((name = gst_structure_get_string(str, "format")))
4132 player->set_mode.video_zc = name[0] == 'S';
4134 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
4136 if (player->video_stream_changed_cb) {
4137 LOGE("call the video stream changed cb\n");
4138 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
4145 gst_caps_unref(caps);
4155 * This function is to create audio pipeline for playing.
4157 * @param player [in] handle of player
4159 * @return This function returns zero on success.
4161 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
4163 /* macro for code readability. just for sinkbin-creation functions */
4164 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
4166 x_bin[x_id].id = x_id;\
4167 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
4168 if (!x_bin[x_id].gst) {\
4169 LOGE("failed to create %s \n", x_factory);\
4172 if (x_player->ini.set_dump_element_flag)\
4173 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
4176 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
4180 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
4185 MMPLAYER_RETURN_IF_FAIL(player);
4187 if (player->audio_stream_buff_list) {
4188 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4189 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4192 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
4193 __mmplayer_audio_stream_send_data(player, tmp);
4196 g_free(tmp->pcm_data);
4200 g_list_free(player->audio_stream_buff_list);
4201 player->audio_stream_buff_list = NULL;
4208 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
4210 MMPlayerAudioStreamDataType audio_stream = { 0, };
4213 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4215 audio_stream.bitrate = a_buffer->bitrate;
4216 audio_stream.channel = a_buffer->channel;
4217 audio_stream.depth = a_buffer->depth;
4218 audio_stream.is_little_endian = a_buffer->is_little_endian;
4219 audio_stream.channel_mask = a_buffer->channel_mask;
4220 audio_stream.data_size = a_buffer->data_size;
4221 audio_stream.data = a_buffer->pcm_data;
4223 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
4224 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
4230 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4232 mm_player_t* player = (mm_player_t*) data;
4237 gint endianness = 0;
4238 guint64 channel_mask = 0;
4239 void *a_data = NULL;
4241 mm_player_audio_stream_buff_t *a_buffer = NULL;
4242 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4246 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
4248 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4249 a_data = mapinfo.data;
4250 a_size = mapinfo.size;
4252 GstCaps *caps = gst_pad_get_current_caps(pad);
4253 GstStructure *structure = gst_caps_get_structure(caps, 0);
4255 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4256 gst_structure_get_int(structure, "rate", &rate);
4257 gst_structure_get_int(structure, "channels", &channel);
4258 gst_structure_get_int(structure, "depth", &depth);
4259 gst_structure_get_int(structure, "endianness", &endianness);
4260 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
4261 gst_caps_unref(GST_CAPS(caps));
4263 /* In case of the sync is false, use buffer list. *
4264 * The num of buffer list depends on the num of audio channels */
4265 if (player->audio_stream_buff_list) {
4266 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
4267 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
4269 if (channel_mask == tmp->channel_mask) {
4270 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
4271 if (tmp->data_size + a_size < tmp->buff_size) {
4272 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
4273 tmp->data_size += a_size;
4275 /* send data to client */
4276 __mmplayer_audio_stream_send_data(player, tmp);
4278 if (a_size > tmp->buff_size) {
4279 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
4280 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
4281 if (tmp->pcm_data == NULL) {
4282 LOGE("failed to realloc data.");
4285 tmp->buff_size = a_size;
4287 memset(tmp->pcm_data, 0x00, tmp->buff_size);
4288 memcpy(tmp->pcm_data, a_data, a_size);
4289 tmp->data_size = a_size;
4294 LOGE("data is empty in list.");
4300 /* create new audio stream data */
4301 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
4302 if (a_buffer == NULL) {
4303 LOGE("failed to alloc data.");
4306 a_buffer->bitrate = rate;
4307 a_buffer->channel = channel;
4308 a_buffer->depth = depth;
4309 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
4310 a_buffer->channel_mask = channel_mask;
4311 a_buffer->data_size = a_size;
4313 if (!player->audio_stream_sink_sync) {
4314 /* If sync is FALSE, use buffer list to reduce the IPC. */
4315 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
4316 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
4317 if (a_buffer->pcm_data == NULL) {
4318 LOGE("failed to alloc data.");
4322 memcpy(a_buffer->pcm_data, a_data, a_size);
4323 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
4324 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
4326 /* If sync is TRUE, send data directly. */
4327 a_buffer->pcm_data = a_data;
4328 __mmplayer_audio_stream_send_data(player, a_buffer);
4333 gst_buffer_unmap(buffer, &mapinfo);
4338 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
4340 mm_player_t* player = (mm_player_t*)data;
4341 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4342 GstPad* sinkpad = NULL;
4343 GstElement *queue = NULL, *sink = NULL;
4346 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
4348 queue = gst_element_factory_make("queue", NULL);
4349 if (queue == NULL) {
4350 LOGD("fail make queue\n");
4354 sink = gst_element_factory_make("fakesink", NULL);
4356 LOGD("fail make fakesink\n");
4360 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
4362 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
4363 LOGW("failed to link queue & sink\n");
4367 sinkpad = gst_element_get_static_pad(queue, "sink");
4369 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
4370 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
4374 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
4376 gst_object_unref(sinkpad);
4377 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
4378 g_object_set(sink, "signal-handoffs", TRUE, NULL);
4380 gst_element_set_state(sink, GST_STATE_PAUSED);
4381 gst_element_set_state(queue, GST_STATE_PAUSED);
4383 MMPLAYER_SIGNAL_CONNECT(player,
4385 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4387 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
4394 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
4396 gst_object_unref(GST_OBJECT(queue));
4400 gst_object_unref(GST_OBJECT(sink));
4404 gst_object_unref(GST_OBJECT(sinkpad));
4411 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
4413 #define MAX_PROPS_LEN 128
4414 gint latency_mode = 0;
4415 gchar *stream_type = NULL;
4416 gchar *latency = NULL;
4418 gchar stream_props[MAX_PROPS_LEN] = {0,};
4419 GstStructure *props = NULL;
4422 * It should be set after player creation through attribute.
4423 * But, it can not be changed during playing.
4426 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
4427 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
4430 LOGE("stream_type is null.\n");
4432 if (player->sound.focus_id)
4433 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
4434 stream_type, stream_id, player->sound.focus_id);
4436 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
4437 stream_type, stream_id);
4438 props = gst_structure_from_string(stream_props, NULL);
4439 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
4440 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
4441 stream_type, stream_id, player->sound.focus_id, stream_props);
4442 gst_structure_free(props);
4445 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
4447 switch (latency_mode) {
4448 case AUDIO_LATENCY_MODE_LOW:
4449 latency = g_strndup("low", 3);
4451 case AUDIO_LATENCY_MODE_MID:
4452 latency = g_strndup("mid", 3);
4454 case AUDIO_LATENCY_MODE_HIGH:
4455 latency = g_strndup("high", 4);
4459 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
4463 LOGD("audiosink property - latency=%s \n", latency);
4471 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
4473 MMPlayerGstElement* first_element = NULL;
4474 MMPlayerGstElement* audiobin = NULL;
4475 MMHandleType attrs = 0;
4477 GstPad *ghostpad = NULL;
4478 GList* element_bucket = NULL;
4479 gboolean link_audio_sink_now = TRUE;
4485 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4488 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
4490 LOGE("failed to allocate memory for audiobin\n");
4491 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4494 attrs = MMPLAYER_GET_ATTRS(player);
4497 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
4498 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
4499 if (!audiobin[MMPLAYER_A_BIN].gst) {
4500 LOGE("failed to create audiobin\n");
4505 player->pipeline->audiobin = audiobin;
4507 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
4509 /* Adding audiotp plugin for reverse trickplay feature */
4510 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
4513 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
4515 /* replaygain volume */
4516 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
4517 if (player->sound.rg_enable)
4518 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
4520 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
4523 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
4525 if (player->set_mode.pcm_extraction) {
4526 // pcm extraction only and no sound output
4527 if (player->audio_stream_render_cb_ex) {
4528 char *caps_str = NULL;
4529 GstCaps* caps = NULL;
4530 gchar *format = NULL;
4533 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4535 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
4537 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
4539 caps = gst_caps_new_simple("audio/x-raw",
4540 "format", G_TYPE_STRING, format,
4541 "rate", G_TYPE_INT, player->pcm_samplerate,
4542 "channels", G_TYPE_INT, player->pcm_channel,
4544 caps_str = gst_caps_to_string(caps);
4545 LOGD("new caps : %s\n", caps_str);
4547 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4550 gst_caps_unref(caps);
4551 MMPLAYER_FREEIF(caps_str);
4553 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
4555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
4556 /* raw pad handling signal */
4557 MMPLAYER_SIGNAL_CONNECT(player,
4558 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
4559 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
4560 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
4562 int dst_samplerate = 0;
4563 int dst_channels = 0;
4565 char *caps_str = NULL;
4566 GstCaps* caps = NULL;
4568 /* get conf. values */
4569 mm_attrs_multiple_get(player->attrs,
4571 "pcm_extraction_samplerate", &dst_samplerate,
4572 "pcm_extraction_channels", &dst_channels,
4573 "pcm_extraction_depth", &dst_depth,
4577 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
4578 caps = gst_caps_new_simple("audio/x-raw",
4579 "rate", G_TYPE_INT, dst_samplerate,
4580 "channels", G_TYPE_INT, dst_channels,
4581 "depth", G_TYPE_INT, dst_depth,
4583 caps_str = gst_caps_to_string(caps);
4584 LOGD("new caps : %s\n", caps_str);
4586 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4589 gst_caps_unref(caps);
4590 MMPLAYER_FREEIF(caps_str);
4593 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
4596 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
4600 //GstCaps* caps = NULL;
4603 /* for logical volume control */
4604 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
4605 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
4607 if (player->sound.mute) {
4608 LOGD("mute enabled\n");
4609 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
4614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
4615 caps = gst_caps_from_string("audio/x-raw-int, "
4616 "endianness = (int) LITTLE_ENDIAN, "
4617 "signed = (boolean) true, "
4618 "width = (int) 16, "
4619 "depth = (int) 16");
4620 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
4621 gst_caps_unref(caps);
4624 /* check if multi-channels */
4625 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
4626 GstPad *srcpad = NULL;
4627 GstCaps *caps = NULL;
4629 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
4630 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
4631 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
4632 GstStructure *str = gst_caps_get_structure(caps, 0);
4634 gst_structure_get_int(str, "channels", &channels);
4635 gst_caps_unref(caps);
4637 gst_object_unref(srcpad);
4641 /* audio effect element. if audio effect is enabled */
4642 if ((strcmp(player->ini.audioeffect_element, ""))
4644 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
4647 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
4649 if ((!player->bypass_audio_effect)
4650 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
4651 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
4652 if (!_mmplayer_audio_effect_custom_apply(player))
4653 LOGI("apply audio effect(custom) setting success\n");
4657 if ((strcmp(player->ini.audioeffect_element_custom, ""))
4658 && (player->set_mode.rich_audio))
4659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
4662 /* create audio sink */
4663 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
4664 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
4665 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
4667 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
4668 if (player->is_360_feature_enabled &&
4669 player->is_content_spherical &&
4671 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
4672 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
4673 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
4675 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
4677 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
4679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
4680 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
4681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
4682 gst_caps_unref(acaps);
4684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
4685 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
4686 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
4687 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
4689 player->is_openal_plugin_used = TRUE;
4691 if (player->video360_yaw_radians <= M_PI &&
4692 player->video360_yaw_radians >= -M_PI &&
4693 player->video360_pitch_radians <= M_PI_2 &&
4694 player->video360_pitch_radians >= -M_PI_2) {
4695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4696 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4697 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4698 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4699 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
4700 "source-orientation-y", player->video360_metadata.init_view_heading,
4701 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
4704 if (player->is_360_feature_enabled && player->is_content_spherical)
4705 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
4706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
4710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
4711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
4714 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
4715 (player->videodec_linked && player->ini.use_system_clock)) {
4716 LOGD("system clock will be used.\n");
4717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
4720 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
4721 __mmplayer_gst_set_audiosink_property(player, attrs);
4724 if (audiobin[MMPLAYER_A_SINK].gst) {
4725 GstPad *sink_pad = NULL;
4726 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
4727 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
4728 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4729 gst_object_unref(GST_OBJECT(sink_pad));
4732 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
4734 /* adding created elements to bin */
4735 LOGD("adding created elements to bin\n");
4736 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
4737 LOGE("failed to add elements\n");
4741 /* linking elements in the bucket by added order. */
4742 LOGD("Linking elements in the bucket by added order.\n");
4743 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4744 LOGE("failed to link elements\n");
4748 /* get first element's sinkpad for creating ghostpad */
4749 first_element = (MMPlayerGstElement *)element_bucket->data;
4750 if (!first_element) {
4751 LOGE("failed to get first elem\n");
4755 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4757 LOGE("failed to get pad from first element of audiobin\n");
4761 ghostpad = gst_ghost_pad_new("sink", pad);
4763 LOGE("failed to create ghostpad\n");
4767 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
4768 LOGE("failed to add ghostpad to audiobin\n");
4772 gst_object_unref(pad);
4774 g_list_free(element_bucket);
4777 return MM_ERROR_NONE;
4781 LOGD("ERROR : releasing audiobin\n");
4784 gst_object_unref(GST_OBJECT(pad));
4787 gst_object_unref(GST_OBJECT(ghostpad));
4790 g_list_free(element_bucket);
4792 /* release element which are not added to bin */
4793 for (i = 1; i < MMPLAYER_A_NUM; i++) {
4794 /* NOTE : skip bin */
4795 if (audiobin[i].gst) {
4796 GstObject* parent = NULL;
4797 parent = gst_element_get_parent(audiobin[i].gst);
4800 gst_object_unref(GST_OBJECT(audiobin[i].gst));
4801 audiobin[i].gst = NULL;
4803 gst_object_unref(GST_OBJECT(parent));
4807 /* release audiobin with it's childs */
4808 if (audiobin[MMPLAYER_A_BIN].gst)
4809 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
4811 MMPLAYER_FREEIF(audiobin);
4813 player->pipeline->audiobin = NULL;
4815 return MM_ERROR_PLAYER_INTERNAL;
4818 static GstPadProbeReturn
4819 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4821 mm_player_t* player = (mm_player_t*) u_data;
4822 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
4823 GstMapInfo probe_info = GST_MAP_INFO_INIT;
4825 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
4827 if (player->audio_stream_cb && probe_info.size && probe_info.data)
4828 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
4830 return GST_PAD_PROBE_OK;
4833 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
4835 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
4838 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
4840 int ret = MM_ERROR_NONE;
4842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4843 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
4845 MMPLAYER_VIDEO_BO_LOCK(player);
4847 if (player->video_bo_list) {
4848 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4849 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4850 if (tmp && tmp->bo == bo) {
4852 LOGD("release bo %p", bo);
4853 tbm_bo_unref(tmp->bo);
4854 MMPLAYER_VIDEO_BO_UNLOCK(player);
4855 MMPLAYER_VIDEO_BO_SIGNAL(player);
4860 /* hw codec is running or the list was reset for DRC. */
4861 LOGW("there is no bo list.");
4863 MMPLAYER_VIDEO_BO_UNLOCK(player);
4865 LOGW("failed to find bo %p", bo);
4870 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
4875 MMPLAYER_RETURN_IF_FAIL(player);
4877 MMPLAYER_VIDEO_BO_LOCK(player);
4878 if (player->video_bo_list) {
4879 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
4880 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4881 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4884 tbm_bo_unref(tmp->bo);
4888 g_list_free(player->video_bo_list);
4889 player->video_bo_list = NULL;
4891 player->video_bo_size = 0;
4892 MMPLAYER_VIDEO_BO_UNLOCK(player);
4899 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
4902 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
4903 gboolean ret = TRUE;
4905 /* check DRC, if it is, destroy the prev bo list to create again */
4906 if (player->video_bo_size != size) {
4907 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
4908 __mmplayer_video_stream_destroy_bo_list(player);
4909 player->video_bo_size = size;
4912 MMPLAYER_VIDEO_BO_LOCK(player);
4914 if ((!player->video_bo_list) ||
4915 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
4917 /* create bo list */
4919 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
4921 if (player->video_bo_list) {
4922 /* if bo list did not created all, try it again. */
4923 idx = g_list_length(player->video_bo_list);
4924 LOGD("bo list exist(len: %d)", idx);
4927 for (; idx < player->ini.num_of_video_bo; idx++) {
4928 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
4930 LOGE("Fail to alloc bo_info.");
4933 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
4935 LOGE("Fail to tbm_bo_alloc.");
4939 bo_info->using = FALSE;
4940 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
4943 /* update video num buffers */
4944 player->video_num_buffers = idx;
4945 if (idx == player->ini.num_of_video_bo)
4946 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
4949 MMPLAYER_VIDEO_BO_UNLOCK(player);
4953 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
4957 /* get bo from list*/
4958 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
4959 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
4960 if (tmp && (tmp->using == FALSE)) {
4961 LOGD("found bo %p to use", tmp->bo);
4963 MMPLAYER_VIDEO_BO_UNLOCK(player);
4964 return tbm_bo_ref(tmp->bo);
4968 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
4969 MMPLAYER_VIDEO_BO_UNLOCK(player);
4973 if (player->ini.video_bo_timeout <= 0) {
4974 MMPLAYER_VIDEO_BO_WAIT(player);
4976 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
4977 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
4984 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4986 mm_player_t* player = (mm_player_t*)data;
4988 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4990 /* send prerolled pkt */
4991 player->video_stream_prerolled = FALSE;
4993 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4995 /* not to send prerolled pkt again */
4996 player->video_stream_prerolled = TRUE;
5000 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5002 mm_player_t* player = (mm_player_t*)data;
5003 GstCaps *caps = NULL;
5004 MMPlayerVideoStreamDataType *stream = NULL;
5005 MMVideoBuffer *video_buffer = NULL;
5006 GstMemory *dataBlock = NULL;
5007 GstMemory *metaBlock = NULL;
5008 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5009 GstStructure *structure = NULL;
5010 const gchar *string_format = NULL;
5011 unsigned int fourcc = 0;
5014 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
5016 if (player->video_stream_prerolled) {
5017 player->video_stream_prerolled = FALSE;
5018 LOGD("skip the prerolled pkt not to send it again");
5022 caps = gst_pad_get_current_caps(pad);
5024 LOGE("Caps is NULL.");
5028 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
5030 /* clear stream data structure */
5031 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
5033 LOGE("failed to alloc mem for video data");
5037 structure = gst_caps_get_structure(caps, 0);
5038 gst_structure_get_int(structure, "width", &(stream->width));
5039 gst_structure_get_int(structure, "height", &(stream->height));
5040 string_format = gst_structure_get_string(structure, "format");
5042 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
5043 stream->format = util_get_pixtype(fourcc);
5044 gst_caps_unref(caps);
5047 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
5050 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
5051 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
5054 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
5055 LOGE("Wrong condition!!");
5059 /* set size and timestamp */
5060 dataBlock = gst_buffer_peek_memory(buffer, 0);
5061 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
5062 stream->timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/GST_MSECOND); /* nano sec -> mili sec */
5064 /* check zero-copy */
5065 if (player->set_mode.video_zc &&
5066 player->set_mode.media_packet_video_stream &&
5067 gst_buffer_n_memory(buffer) > 1) {
5068 metaBlock = gst_buffer_peek_memory(buffer, 1);
5069 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
5070 video_buffer = (MMVideoBuffer *)mapinfo.data;
5073 if (video_buffer) { /* hw codec */
5075 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
5078 /* copy pointer of tbm bo, stride, elevation */
5079 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
5080 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
5084 LOGE("Not support video buffer format");
5087 memcpy(stream->stride, video_buffer->stride_width,
5088 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5089 memcpy(stream->elevation, video_buffer->stride_height,
5090 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
5092 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
5093 stream->internal_buffer = gst_buffer_ref(buffer);
5094 } else { /* sw codec */
5098 int ret = TBM_SURFACE_ERROR_NONE;
5099 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5100 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
5102 unsigned char *src = NULL;
5103 unsigned char *dest = NULL;
5104 tbm_bo_handle thandle;
5105 tbm_surface_h surface;
5106 tbm_surface_info_s info;
5109 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
5111 LOGE("fail to gst_memory_map");
5116 if (stream->format == MM_PIXEL_FORMAT_I420) {
5117 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
5119 ret = tbm_surface_get_info(surface, &info);
5121 if (ret != TBM_SURFACE_ERROR_NONE) {
5122 tbm_surface_destroy(surface);
5125 tbm_surface_destroy(surface);
5127 src_stride[0] = GST_ROUND_UP_4(stream->width);
5128 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
5129 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
5130 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
5131 stream->stride[0] = info.planes[0].stride;
5132 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
5133 stream->stride[1] = info.planes[1].stride;
5134 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
5135 stream->stride[2] = info.planes[2].stride;
5136 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
5137 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
5138 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5139 stream->stride[0] = stream->width * 4;
5140 stream->elevation[0] = stream->height;
5141 size = stream->stride[0] * stream->height;
5143 LOGE("Not support format %d", stream->format);
5147 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
5148 if (!stream->bo[0]) {
5149 LOGE("Fail to tbm_bo_alloc!!");
5153 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
5154 if (thandle.ptr && mapinfo.data) {
5155 if (stream->format == MM_PIXEL_FORMAT_I420) {
5156 for (i = 0; i < 3; i++) {
5157 src = mapinfo.data + src_offset[i];
5158 dest = thandle.ptr + info.planes[i].offset;
5161 for (j = 0; j < stream->height>>k; j++) {
5162 memcpy(dest, src, stream->width>>k);
5163 src += src_stride[i];
5164 dest += stream->stride[i];
5167 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
5168 memcpy(thandle.ptr, mapinfo.data, size);
5170 LOGE("Not support format %d", stream->format);
5174 LOGE("data pointer is wrong. dest : %p, src : %p",
5175 thandle.ptr, mapinfo.data);
5178 tbm_bo_unmap(stream->bo[0]);
5181 if (player->video_stream_cb) { /* This has been already checked at the entry */
5182 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
5183 LOGE("failed to send video stream data.");
5189 gst_memory_unmap(metaBlock, &mapinfo);
5191 gst_memory_unmap(dataBlock, &mapinfo);
5196 LOGE("release video stream resource.");
5199 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
5201 tbm_bo_unref(stream->bo[i]);
5203 gst_memory_unmap(metaBlock, &mapinfo);
5205 /* unref gst buffer */
5206 if (stream->internal_buffer)
5207 gst_buffer_unref(stream->internal_buffer);
5208 } else if (dataBlock) {
5210 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
5211 gst_memory_unmap(dataBlock, &mapinfo);
5219 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
5221 gchar* video_csc = "videoconvert"; /* default colorspace converter */
5222 GList* element_bucket = NULL;
5224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5228 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
5229 LOGD("do not need to add video filters.");
5230 return MM_ERROR_NONE;
5233 /* in case of sw codec except 360 playback,
5234 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
5235 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
5236 LOGD("using video converter: %s", video_csc);
5238 /* set video rotator */
5239 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
5241 *bucket = element_bucket;
5243 return MM_ERROR_NONE;
5245 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
5246 g_list_free(element_bucket);
5250 return MM_ERROR_PLAYER_INTERNAL;
5254 * This function is to create video pipeline.
5256 * @param player [in] handle of player
5257 * caps [in] src caps of decoder
5258 * surface_type [in] surface type for video rendering
5260 * @return This function returns zero on success.
5262 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
5266 * - video overlay surface(arm/x86) : tizenwlsink
5269 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
5273 GList*element_bucket = NULL;
5274 MMPlayerGstElement* first_element = NULL;
5275 MMPlayerGstElement* videobin = NULL;
5276 gchar *videosink_element = NULL;
5280 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5283 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
5285 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5287 player->pipeline->videobin = videobin;
5289 attrs = MMPLAYER_GET_ATTRS(player);
5291 LOGE("cannot get content attribute");
5292 return MM_ERROR_PLAYER_INTERNAL;
5296 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
5297 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
5298 if (!videobin[MMPLAYER_V_BIN].gst) {
5299 LOGE("failed to create videobin");
5303 int enable_video_decoded_cb = 0;
5304 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
5306 if (player->is_360_feature_enabled && player->is_content_spherical) {
5307 LOGD("video360 elem will be added.");
5309 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
5310 "video-360", TRUE, player);
5312 /* Set spatial media metadata and/or user settings to the element.
5314 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5315 "projection-type", player->video360_metadata.projection_type, NULL);
5317 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5318 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
5320 if (player->video360_metadata.full_pano_width_pixels &&
5321 player->video360_metadata.full_pano_height_pixels &&
5322 player->video360_metadata.cropped_area_image_width &&
5323 player->video360_metadata.cropped_area_image_height) {
5324 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5325 "projection-bounds-top", player->video360_metadata.cropped_area_top,
5326 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
5327 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
5328 "projection-bounds-left", player->video360_metadata.cropped_area_left,
5329 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
5330 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
5334 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
5335 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5336 "horizontal-fov", player->video360_horizontal_fov,
5337 "vertical-fov", player->video360_vertical_fov, NULL);
5340 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
5341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5342 "zoom", 1.0f / player->video360_zoom, NULL);
5345 if (player->video360_yaw_radians <= M_PI &&
5346 player->video360_yaw_radians >= -M_PI &&
5347 player->video360_pitch_radians <= M_PI_2 &&
5348 player->video360_pitch_radians >= -M_PI_2) {
5349 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5350 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
5351 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
5352 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
5353 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5354 "pose-yaw", player->video360_metadata.init_view_heading,
5355 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
5358 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
5359 "passthrough", !player->is_video360_enabled, NULL);
5362 /* set video sink */
5363 switch (surface_type) {
5364 case MM_DISPLAY_SURFACE_OVERLAY:
5365 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
5367 if (strlen(player->ini.videosink_element_overlay) > 0)
5368 videosink_element = player->ini.videosink_element_overlay;
5372 case MM_DISPLAY_SURFACE_NULL:
5373 if (strlen(player->ini.videosink_element_fake) > 0)
5374 videosink_element = player->ini.videosink_element_fake;
5378 case MM_DISPLAY_SURFACE_REMOTE:
5379 if (strlen(player->ini.videosink_element_fake) > 0)
5380 videosink_element = player->ini.videosink_element_fake;
5385 LOGE("unidentified surface type");
5388 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
5390 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
5392 /* additional setting for sink plug-in */
5393 switch (surface_type) {
5394 case MM_DISPLAY_SURFACE_OVERLAY:
5396 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
5398 LOGD("selected videosink name: %s", videosink_element);
5400 /* support shard memory with S/W codec on HawkP */
5401 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
5402 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
5403 "use-tbm", use_tbm, NULL);
5409 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5412 LOGD("disable last-sample");
5413 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5417 if (player->set_mode.media_packet_video_stream) {
5419 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
5421 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
5423 MMPLAYER_SIGNAL_CONNECT(player,
5424 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5425 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5427 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5430 MMPLAYER_SIGNAL_CONNECT(player,
5431 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5432 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5434 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5439 case MM_DISPLAY_SURFACE_REMOTE:
5441 if (player->set_mode.media_packet_video_stream) {
5442 LOGE("add data probe at videosink");
5443 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5444 "sync", TRUE, "signal-handoffs", TRUE, NULL);
5446 MMPLAYER_SIGNAL_CONNECT(player,
5447 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5448 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5450 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
5453 MMPLAYER_SIGNAL_CONNECT(player,
5454 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
5455 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5457 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
5462 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
5465 LOGD("disable last-sample");
5466 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
5476 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
5479 if (videobin[MMPLAYER_V_SINK].gst) {
5480 GstPad *sink_pad = NULL;
5481 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
5483 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
5484 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
5485 gst_object_unref(GST_OBJECT(sink_pad));
5487 LOGW("failed to get sink pad from videosink\n");
5490 /* store it as it's sink element */
5491 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
5493 /* adding created elements to bin */
5494 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
5495 LOGE("failed to add elements\n");
5499 /* Linking elements in the bucket by added order */
5500 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5501 LOGE("failed to link elements\n");
5505 /* get first element's sinkpad for creating ghostpad */
5507 first_element = (MMPlayerGstElement *)element_bucket->data;
5508 if (!first_element) {
5509 LOGE("failed to get first element from bucket\n");
5513 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
5515 LOGE("failed to get pad from first element\n");
5519 /* create ghostpad */
5520 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
5521 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
5522 LOGE("failed to add ghostpad to videobin\n");
5525 gst_object_unref(pad);
5527 /* done. free allocated variables */
5529 g_list_free(element_bucket);
5533 return MM_ERROR_NONE;
5536 LOGE("ERROR : releasing videobin\n");
5538 g_list_free(element_bucket);
5541 gst_object_unref(GST_OBJECT(pad));
5543 /* release videobin with it's childs */
5544 if (videobin[MMPLAYER_V_BIN].gst)
5545 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
5548 MMPLAYER_FREEIF(videobin);
5550 player->pipeline->videobin = NULL;
5552 return MM_ERROR_PLAYER_INTERNAL;
5555 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
5557 GList *element_bucket = NULL;
5558 MMPlayerGstElement *textbin = player->pipeline->textbin;
5560 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
5561 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
5562 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
5563 "signal-handoffs", FALSE,
5566 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
5567 MMPLAYER_SIGNAL_CONNECT(player,
5568 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
5569 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
5571 G_CALLBACK(__mmplayer_update_subtitle),
5574 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "async", TRUE, NULL);
5575 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
5576 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
5578 if (!player->play_subtitle) {
5579 LOGD("add textbin sink as sink element of whole pipeline.\n");
5580 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
5583 /* adding created elements to bin */
5584 LOGD("adding created elements to bin\n");
5585 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
5586 LOGE("failed to add elements\n");
5590 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
5591 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
5592 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
5594 /* linking elements in the bucket by added order. */
5595 LOGD("Linking elements in the bucket by added order.\n");
5596 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5597 LOGE("failed to link elements\n");
5601 /* done. free allocated variables */
5602 g_list_free(element_bucket);
5604 if (textbin[MMPLAYER_T_QUEUE].gst) {
5606 GstPad *ghostpad = NULL;
5608 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
5610 LOGE("failed to get sink pad of text queue");
5614 ghostpad = gst_ghost_pad_new("text_sink", pad);
5615 gst_object_unref(pad);
5618 LOGE("failed to create ghostpad of textbin\n");
5622 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
5623 LOGE("failed to add ghostpad to textbin\n");
5624 gst_object_unref(ghostpad);
5629 return MM_ERROR_NONE;
5632 g_list_free(element_bucket);
5634 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
5635 LOGE("remove textbin sink from sink list");
5636 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
5639 /* release element at __mmplayer_gst_create_text_sink_bin */
5640 return MM_ERROR_PLAYER_INTERNAL;
5643 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
5645 MMPlayerGstElement *textbin = NULL;
5646 GList *element_bucket = NULL;
5647 int surface_type = 0;
5652 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5655 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
5657 LOGE("failed to allocate memory for textbin\n");
5658 return MM_ERROR_PLAYER_NO_FREE_SPACE;
5662 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
5663 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
5664 if (!textbin[MMPLAYER_T_BIN].gst) {
5665 LOGE("failed to create textbin\n");
5670 player->pipeline->textbin = textbin;
5673 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
5674 LOGD("surface type for subtitle : %d", surface_type);
5675 switch (surface_type) {
5676 case MM_DISPLAY_SURFACE_OVERLAY:
5677 case MM_DISPLAY_SURFACE_NULL:
5678 case MM_DISPLAY_SURFACE_REMOTE:
5679 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
5680 LOGE("failed to make plain text elements\n");
5691 return MM_ERROR_NONE;
5695 LOGD("ERROR : releasing textbin\n");
5697 g_list_free(element_bucket);
5699 /* release signal */
5700 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5702 /* release element which are not added to bin */
5703 for (i = 1; i < MMPLAYER_T_NUM; i++) {
5704 /* NOTE : skip bin */
5705 if (textbin[i].gst) {
5706 GstObject* parent = NULL;
5707 parent = gst_element_get_parent(textbin[i].gst);
5710 gst_object_unref(GST_OBJECT(textbin[i].gst));
5711 textbin[i].gst = NULL;
5713 gst_object_unref(GST_OBJECT(parent));
5718 /* release textbin with it's childs */
5719 if (textbin[MMPLAYER_T_BIN].gst)
5720 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5722 MMPLAYER_FREEIF(player->pipeline->textbin);
5723 player->pipeline->textbin = NULL;
5726 return MM_ERROR_PLAYER_INTERNAL;
5731 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
5733 MMPlayerGstElement* mainbin = NULL;
5734 MMPlayerGstElement* textbin = NULL;
5735 MMHandleType attrs = 0;
5736 GstElement *subsrc = NULL;
5737 GstElement *subparse = NULL;
5738 gchar *subtitle_uri = NULL;
5739 const gchar *charset = NULL;
5745 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5747 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
5749 mainbin = player->pipeline->mainbin;
5751 attrs = MMPLAYER_GET_ATTRS(player);
5753 LOGE("cannot get content attribute\n");
5754 return MM_ERROR_PLAYER_INTERNAL;
5757 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
5758 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
5759 LOGE("subtitle uri is not proper filepath.\n");
5760 return MM_ERROR_PLAYER_INVALID_URI;
5763 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
5764 LOGE("failed to get storage info of subtitle path");
5765 return MM_ERROR_PLAYER_INVALID_URI;
5768 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
5770 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5771 player->subtitle_language_list = NULL;
5772 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5774 /* create the subtitle source */
5775 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
5777 LOGE("failed to create filesrc element\n");
5780 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
5782 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5783 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
5785 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
5786 LOGW("failed to add queue\n");
5787 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
5788 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
5789 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
5794 subparse = gst_element_factory_make("subparse", "subtitle_parser");
5796 LOGE("failed to create subparse element\n");
5800 charset = util_get_charset(subtitle_uri);
5802 LOGD("detected charset is %s\n", charset);
5803 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
5806 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
5807 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
5809 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
5810 LOGW("failed to add subparse\n");
5811 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
5812 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
5813 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
5817 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
5818 LOGW("failed to link subsrc and subparse\n");
5822 player->play_subtitle = TRUE;
5823 player->adjust_subtitle_pos = 0;
5825 LOGD("play subtitle using subtitle file\n");
5827 if (player->pipeline->textbin == NULL) {
5828 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
5829 LOGE("failed to create text sink bin. continuing without text\n");
5833 textbin = player->pipeline->textbin;
5835 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
5836 LOGW("failed to add textbin\n");
5838 /* release signal */
5839 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5841 /* release textbin with it's childs */
5842 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
5843 MMPLAYER_FREEIF(player->pipeline->textbin);
5844 player->pipeline->textbin = textbin = NULL;
5848 LOGD("link text input selector and textbin ghost pad");
5850 player->textsink_linked = 1;
5851 player->external_text_idx = 0;
5852 LOGI("player->textsink_linked set to 1\n");
5854 textbin = player->pipeline->textbin;
5855 LOGD("text bin has been created. reuse it.");
5856 player->external_text_idx = 1;
5859 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
5860 LOGW("failed to link subparse and textbin\n");
5864 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
5866 LOGE("failed to get sink pad from textsink to probe data");
5870 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
5871 __mmplayer_subtitle_adjust_position_probe, player, NULL);
5873 gst_object_unref(pad);
5876 /* create dot. for debugging */
5877 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
5880 return MM_ERROR_NONE;
5883 /* release text pipeline resource */
5884 player->textsink_linked = 0;
5886 /* release signal */
5887 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
5889 if (player->pipeline->textbin) {
5890 LOGE("remove textbin");
5892 /* release textbin with it's childs */
5893 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
5894 MMPLAYER_FREEIF(player->pipeline->textbin);
5895 player->pipeline->textbin = NULL;
5899 /* release subtitle elem */
5900 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
5901 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
5903 return MM_ERROR_PLAYER_INTERNAL;
5907 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
5909 mm_player_t* player = (mm_player_t*) data;
5910 MMMessageParamType msg = {0, };
5911 GstClockTime duration = 0;
5912 gpointer text = NULL;
5913 guint text_size = 0;
5914 gboolean ret = TRUE;
5915 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
5919 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5920 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
5922 if (player->is_subtitle_force_drop) {
5923 LOGW("subtitle is dropped forcedly.");
5927 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
5928 text = mapinfo.data;
5929 text_size = mapinfo.size;
5930 duration = GST_BUFFER_DURATION(buffer);
5932 if (player->set_mode.subtitle_off) {
5933 LOGD("subtitle is OFF.\n");
5937 if (!text || (text_size == 0)) {
5938 LOGD("There is no subtitle to be displayed.\n");
5942 msg.data = (void *) text;
5943 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
5945 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
5947 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
5948 gst_buffer_unmap(buffer, &mapinfo);
5955 static GstPadProbeReturn
5956 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
5958 mm_player_t *player = (mm_player_t *) u_data;
5959 GstClockTime cur_timestamp = 0;
5960 gint64 adjusted_timestamp = 0;
5961 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
5963 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
5965 if (player->set_mode.subtitle_off) {
5966 LOGD("subtitle is OFF.\n");
5970 if (player->adjust_subtitle_pos == 0) {
5971 LOGD("nothing to do");
5975 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
5976 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
5978 if (adjusted_timestamp < 0) {
5979 LOGD("adjusted_timestamp under zero");
5984 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
5985 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
5986 GST_TIME_ARGS(cur_timestamp),
5987 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
5989 return GST_PAD_PROBE_OK;
5991 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5995 /* check player and subtitlebin are created */
5996 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5997 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5999 if (position == 0) {
6000 LOGD("nothing to do\n");
6002 return MM_ERROR_NONE;
6006 case MM_PLAYER_POS_FORMAT_TIME:
6008 /* check current postion */
6009 player->adjust_subtitle_pos = position;
6011 LOGD("save adjust_subtitle_pos in player") ;
6017 LOGW("invalid format.\n");
6019 return MM_ERROR_INVALID_ARGUMENT;
6025 return MM_ERROR_NONE;
6029 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
6031 GstElement *appsrc = element;
6032 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6033 GstBuffer *buffer = NULL;
6034 GstFlowReturn ret = GST_FLOW_OK;
6037 MMPLAYER_RETURN_IF_FAIL(element);
6038 MMPLAYER_RETURN_IF_FAIL(buf);
6040 buffer = gst_buffer_new();
6042 if (buf->offset >= buf->len) {
6043 LOGD("call eos appsrc\n");
6044 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
6048 if (buf->len - buf->offset < size)
6049 len = buf->len - buf->offset;
6051 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
6052 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
6053 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
6055 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
6056 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
6062 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
6064 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
6066 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
6068 buf->offset = (int)size;
6073 static GstBusSyncReply
6074 __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
6076 mm_player_t *player = (mm_player_t *)data;
6077 GstBusSyncReply reply = GST_BUS_DROP;
6079 if (!(player->pipeline && player->pipeline->mainbin)) {
6080 LOGE("player pipeline handle is null");
6081 return GST_BUS_PASS;
6084 if (!__mmplayer_check_useful_message(player, message)) {
6085 gst_message_unref(message);
6086 return GST_BUS_DROP;
6089 switch (GST_MESSAGE_TYPE(message)) {
6090 case GST_MESSAGE_STATE_CHANGED:
6091 /* post directly for fast launch */
6092 if (player->sync_handler) {
6093 __mmplayer_gst_callback(message, player);
6094 reply = GST_BUS_DROP;
6096 reply = GST_BUS_PASS;
6098 case GST_MESSAGE_TAG:
6099 __mmplayer_gst_extract_tag_from_msg(player, message);
6103 GstTagList *tags = NULL;
6105 gst_message_parse_tag(message, &tags);
6107 LOGE("TAGS received from element \"%s\".\n",
6108 GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
6110 gst_tag_list_foreach(tags, print_tag, NULL);
6111 gst_tag_list_free(tags);
6119 case GST_MESSAGE_DURATION_CHANGED:
6120 __mmplayer_gst_handle_duration(player, message);
6122 case GST_MESSAGE_ASYNC_DONE:
6123 /* NOTE:Don't call gst_callback directly
6124 * because previous frame can be showed even though this message is received for seek.
6127 reply = GST_BUS_PASS;
6131 if (reply == GST_BUS_DROP)
6132 gst_message_unref(message);
6138 __mmplayer_gst_create_decoder(mm_player_t *player,
6139 MMPlayerTrackType track,
6141 enum MainElementID elemId,
6144 gboolean ret = TRUE;
6145 GstPad *sinkpad = NULL;
6149 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6151 player->pipeline->mainbin, FALSE);
6152 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
6153 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
6154 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
6156 GstElement *decodebin = NULL;
6157 GstCaps *dec_caps = NULL;
6159 /* create decodebin */
6160 decodebin = gst_element_factory_make("decodebin", name);
6163 LOGE("error : fail to create decodebin for %d decoder\n", track);
6168 /* raw pad handling signal */
6169 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6170 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
6172 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6173 before looking for any elements that can handle that stream.*/
6174 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6175 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
6177 /* This signal is emitted when a element is added to the bin.*/
6178 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6179 G_CALLBACK(__mmplayer_gst_element_added), player);
6181 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6182 LOGE("failed to add new decodebin\n");
6187 dec_caps = gst_pad_query_caps(srcpad, NULL);
6189 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
6190 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
6191 gst_caps_unref(dec_caps);
6194 player->pipeline->mainbin[elemId].id = elemId;
6195 player->pipeline->mainbin[elemId].gst = decodebin;
6197 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6199 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6200 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
6201 gst_object_unref(GST_OBJECT(decodebin));
6204 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
6205 LOGE("failed to sync second level decodebin state with parent\n");
6207 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
6211 gst_object_unref(GST_OBJECT(sinkpad));
6220 * This function is to create audio or video pipeline for playing.
6222 * @param player [in] handle of player
6224 * @return This function returns zero on success.
6229 __mmplayer_gst_create_pipeline(mm_player_t* player)
6232 MMPlayerGstElement *mainbin = NULL;
6233 MMHandleType attrs = 0;
6234 GstElement* element = NULL;
6235 GstElement* elem_src_audio = NULL;
6236 GstElement* elem_src_subtitle = NULL;
6237 GstElement* es_video_queue = NULL;
6238 GstElement* es_audio_queue = NULL;
6239 GstElement* es_subtitle_queue = NULL;
6240 GList* element_bucket = NULL;
6241 gboolean need_state_holder = TRUE;
6243 #ifdef SW_CODEC_ONLY
6244 int surface_type = 0;
6248 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6250 /* get profile attribute */
6251 attrs = MMPLAYER_GET_ATTRS(player);
6253 LOGE("cannot get content attribute\n");
6257 /* create pipeline handles */
6258 if (player->pipeline) {
6259 LOGW("pipeline should be released before create new one\n");
6263 player->video360_metadata.is_spherical = -1;
6264 player->is_openal_plugin_used = FALSE;
6266 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
6267 if (player->pipeline == NULL)
6270 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
6272 /* create mainbin */
6273 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
6274 if (mainbin == NULL)
6277 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
6279 /* create pipeline */
6280 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
6281 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
6282 if (!mainbin[MMPLAYER_M_PIPE].gst) {
6283 LOGE("failed to create pipeline\n");
6286 player->demux_pad_index = 0;
6287 player->subtitle_language_list = NULL;
6289 player->is_subtitle_force_drop = FALSE;
6290 player->last_multiwin_status = FALSE;
6292 _mmplayer_track_initialize(player);
6293 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6295 /* create source element */
6296 switch (player->profile.uri_type) {
6297 /* rtsp streamming */
6298 case MM_PLAYER_URI_TYPE_URL_RTSP:
6302 element = gst_element_factory_make("rtspsrc", "rtsp source");
6305 LOGE("failed to create streaming source element\n");
6313 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6315 SECURE_LOGD("user_agent : %s\n", user_agent);
6317 /* setting property to streaming source */
6318 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6320 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6322 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6323 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
6324 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6325 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
6330 case MM_PLAYER_URI_TYPE_URL_HTTP:
6332 gchar *user_agent, *cookies, **cookie_list;
6333 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6334 user_agent = cookies = NULL;
6336 gint mode = MM_PLAYER_PD_MODE_NONE;
6338 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
6340 player->pd_mode = mode;
6342 LOGD("http playback, PD mode : %d\n", player->pd_mode);
6344 if (!MMPLAYER_IS_HTTP_PD(player)) {
6345 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
6347 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
6350 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
6353 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
6354 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
6356 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6357 LOGD("get timeout from ini\n");
6358 http_timeout = player->ini.http_timeout;
6362 SECURE_LOGD("location : %s\n", player->profile.uri);
6363 SECURE_LOGD("cookies : %s\n", cookies);
6364 SECURE_LOGD("user_agent : %s\n", user_agent);
6365 LOGD("timeout : %d\n", http_timeout);
6367 /* setting property to streaming source */
6368 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6369 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6370 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
6372 /* parsing cookies */
6373 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
6374 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
6375 g_strfreev(cookie_list);
6378 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
6380 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
6381 LOGW("it's dash. and it's still experimental feature.");
6383 // progressive download
6384 gchar* location = NULL;
6386 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6389 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
6391 MMPLAYER_FREEIF(player->pd_file_save_path);
6393 LOGD("PD Location : %s\n", path);
6396 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
6397 LOGE("failed to get storage info");
6400 player->pd_file_save_path = g_strdup(path);
6402 LOGE("can't find pd location so, it should be set \n");
6407 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
6409 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
6413 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
6414 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
6416 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6417 g_object_get(element, "location", &location, NULL);
6418 LOGD("PD_LOCATION [%s].\n", location);
6426 case MM_PLAYER_URI_TYPE_FILE:
6428 LOGD("using filesrc for 'file://' handler.\n");
6429 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
6430 LOGE("failed to get storage info");
6434 element = gst_element_factory_make("filesrc", "source");
6436 LOGE("failed to create filesrc\n");
6440 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
6444 case MM_PLAYER_URI_TYPE_SS:
6446 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
6447 element = gst_element_factory_make("souphttpsrc", "http streaming source");
6449 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
6453 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
6454 LOGD("get timeout from ini\n");
6455 http_timeout = player->ini.http_timeout;
6458 /* setting property to streaming source */
6459 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
6460 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
6463 case MM_PLAYER_URI_TYPE_MS_BUFF:
6465 LOGD("MS buff src is selected\n");
6467 if (player->v_stream_caps) {
6468 element = gst_element_factory_make("appsrc", "video_appsrc");
6470 LOGF("failed to create video app source element[appsrc].\n");
6474 if (player->a_stream_caps) {
6475 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
6476 if (!elem_src_audio) {
6477 LOGF("failed to create audio app source element[appsrc].\n");
6481 } else if (player->a_stream_caps) {
6482 /* no video, only audio pipeline*/
6483 element = gst_element_factory_make("appsrc", "audio_appsrc");
6485 LOGF("failed to create audio app source element[appsrc].\n");
6490 if (player->s_stream_caps) {
6491 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
6492 if (!elem_src_subtitle) {
6493 LOGF("failed to create subtitle app source element[appsrc].\n");
6498 LOGD("setting app sources properties.\n");
6499 LOGD("location : %s\n", player->profile.uri);
6501 if (player->v_stream_caps && element) {
6502 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6503 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
6504 "caps", player->v_stream_caps, NULL);
6506 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6507 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6508 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
6509 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
6511 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6512 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6513 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6514 G_CALLBACK(__gst_seek_video_data), player);
6516 if (player->a_stream_caps && elem_src_audio) {
6517 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
6518 "caps", player->a_stream_caps, NULL);
6520 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6521 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6522 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6523 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6525 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6526 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
6527 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6528 G_CALLBACK(__gst_seek_audio_data), player);
6530 } else if (player->a_stream_caps && element) {
6531 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
6532 "caps", player->a_stream_caps, NULL);
6534 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6535 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6536 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
6537 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
6539 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
6540 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
6541 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6542 G_CALLBACK(__gst_seek_audio_data), player);
6545 if (player->s_stream_caps && elem_src_subtitle) {
6546 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
6547 "caps", player->s_stream_caps, NULL);
6549 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6550 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6551 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
6552 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
6554 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
6556 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6557 G_CALLBACK(__gst_seek_subtitle_data), player);
6560 if (player->v_stream_caps && element) {
6561 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6562 G_CALLBACK(__gst_appsrc_feed_video_data), player);
6563 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6564 G_CALLBACK(__gst_appsrc_enough_video_data), player);
6566 if (player->a_stream_caps && elem_src_audio) {
6567 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6568 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6569 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6570 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6572 } else if (player->a_stream_caps && element) {
6573 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6574 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
6575 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
6576 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
6579 if (player->s_stream_caps && elem_src_subtitle)
6580 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6581 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
6583 need_state_holder = FALSE;
6585 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
6586 if (mmf_attrs_commit(attrs)) /* return -1 if error */
6587 LOGE("failed to commit\n");
6591 case MM_PLAYER_URI_TYPE_MEM:
6593 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
6595 LOGD("mem src is selected\n");
6597 element = gst_element_factory_make("appsrc", "mem-source");
6599 LOGE("failed to create appsrc element\n");
6603 g_object_set(element, "stream-type", stream_type, NULL);
6604 g_object_set(element, "size", player->profile.input_mem.len, NULL);
6605 g_object_set(element, "blocksize", (guint64)20480, NULL);
6607 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
6608 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
6609 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
6610 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
6613 case MM_PLAYER_URI_TYPE_URL:
6616 case MM_PLAYER_URI_TYPE_TEMP:
6619 case MM_PLAYER_URI_TYPE_NONE:
6624 /* check source element is OK */
6626 LOGE("no source element was created.\n");
6630 /* take source element */
6631 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6632 mainbin[MMPLAYER_M_SRC].gst = element;
6633 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
6635 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
6636 player->streamer = __mm_player_streaming_create();
6637 __mm_player_streaming_initialize(player->streamer);
6640 if (MMPLAYER_IS_HTTP_PD(player)) {
6641 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
6643 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
6644 element = gst_element_factory_make("queue2", "queue2");
6646 LOGE("failed to create http streaming buffer element\n");
6651 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6652 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
6653 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
6655 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
6657 player->streamer->is_pd_mode = TRUE;
6659 __mm_player_streaming_set_queue2(player->streamer,
6662 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
6665 player->ini.http_buffering_limit,
6666 MUXED_BUFFER_TYPE_MEM_QUEUE,
6670 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6671 if (player->v_stream_caps) {
6672 es_video_queue = gst_element_factory_make("queue2", "video_queue");
6673 if (!es_video_queue) {
6674 LOGE("create es_video_queue for es player failed\n");
6677 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
6678 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
6679 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
6680 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
6682 /* Adding audio appsrc to bucket */
6683 if (player->a_stream_caps && elem_src_audio) {
6684 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
6685 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
6686 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
6688 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6689 if (!es_audio_queue) {
6690 LOGE("create es_audio_queue for es player failed\n");
6693 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
6695 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6696 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6697 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6699 } else if (player->a_stream_caps) {
6700 /* Only audio stream, no video */
6701 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
6702 if (!es_audio_queue) {
6703 LOGE("create es_audio_queue for es player failed\n");
6706 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
6707 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
6708 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
6711 if (player->s_stream_caps && elem_src_subtitle) {
6712 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
6713 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
6714 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
6716 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
6717 if (!es_subtitle_queue) {
6718 LOGE("create es_subtitle_queue for es player failed\n");
6721 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
6722 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
6723 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
6727 /* create autoplugging element if src element is not a rtsp src */
6728 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
6729 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
6731 enum MainElementID elemId = MMPLAYER_M_NUM;
6733 if (((MMPLAYER_IS_HTTP_PD(player)) ||
6734 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
6735 elemId = MMPLAYER_M_AUTOPLUG;
6736 element = __mmplayer_create_decodebin(player);
6738 /* default size of mq in decodebin is 2M
6739 * but it can cause blocking issue during seeking depends on content. */
6740 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
6742 need_state_holder = FALSE;
6744 elemId = MMPLAYER_M_TYPEFIND;
6745 element = gst_element_factory_make("typefind", "typefinder");
6746 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
6747 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6751 /* check autoplug element is OK */
6753 LOGE("can not create element(%d)\n", elemId);
6757 mainbin[elemId].id = elemId;
6758 mainbin[elemId].gst = element;
6760 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
6763 /* add elements to pipeline */
6764 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
6765 LOGE("Failed to add elements to pipeline\n");
6770 /* linking elements in the bucket by added order. */
6771 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
6772 LOGE("Failed to link some elements\n");
6777 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
6778 if (need_state_holder) {
6780 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
6781 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
6783 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
6784 LOGE("fakesink element could not be created\n");
6787 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
6789 /* take ownership of fakesink. we are reusing it */
6790 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
6793 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
6794 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
6795 LOGE("failed to add fakesink to bin\n");
6800 /* now we have completed mainbin. take it */
6801 player->pipeline->mainbin = mainbin;
6803 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6804 GstPad *srcpad = NULL;
6806 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
6807 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
6809 __mmplayer_gst_create_decoder(player,
6810 MM_PLAYER_TRACK_TYPE_VIDEO,
6812 MMPLAYER_M_AUTOPLUG_V_DEC,
6815 gst_object_unref(GST_OBJECT(srcpad));
6820 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
6821 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
6823 __mmplayer_gst_create_decoder(player,
6824 MM_PLAYER_TRACK_TYPE_AUDIO,
6826 MMPLAYER_M_AUTOPLUG_A_DEC,
6829 gst_object_unref(GST_OBJECT(srcpad));
6834 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
6835 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
6838 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
6839 if (__mmplayer_check_subtitle(player)) {
6840 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
6841 LOGE("fail to create text pipeline");
6844 /* connect bus callback */
6845 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6847 LOGE("cannot get bus from pipeline.\n");
6851 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
6853 player->context.thread_default = g_main_context_get_thread_default();
6855 if (player->context.thread_default == NULL) {
6856 player->context.thread_default = g_main_context_default();
6857 LOGD("thread-default context is the global default context");
6859 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
6861 /* set sync handler to get tag synchronously */
6862 gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
6865 gst_object_unref(GST_OBJECT(bus));
6866 g_list_free(element_bucket);
6868 /* create gst bus_msb_cb thread */
6869 g_mutex_init(&player->bus_msg_thread_mutex);
6870 g_cond_init(&player->bus_msg_thread_cond);
6871 player->bus_msg_thread_exit = FALSE;
6872 player->bus_msg_timeout = PLAYER_BUS_MSG_DEFAULT_TIMEOUT;
6873 player->bus_msg_thread =
6874 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
6875 if (!player->bus_msg_thread) {
6876 LOGE("failed to create gst BUS msg thread");
6877 g_mutex_clear(&player->bus_msg_thread_mutex);
6878 g_cond_clear(&player->bus_msg_thread_cond);
6884 return MM_ERROR_NONE;
6887 __mmplayer_gst_destroy_pipeline(player);
6888 g_list_free(element_bucket);
6891 /* release element which are not added to bin */
6892 for (i = 1; i < MMPLAYER_M_NUM; i++) {
6893 /* NOTE : skip pipeline */
6894 if (mainbin[i].gst) {
6895 GstObject* parent = NULL;
6896 parent = gst_element_get_parent(mainbin[i].gst);
6899 gst_object_unref(GST_OBJECT(mainbin[i].gst));
6900 mainbin[i].gst = NULL;
6902 gst_object_unref(GST_OBJECT(parent));
6906 /* release pipeline with it's childs */
6907 if (mainbin[MMPLAYER_M_PIPE].gst)
6908 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
6910 MMPLAYER_FREEIF(mainbin);
6913 MMPLAYER_FREEIF(player->pipeline);
6914 return MM_ERROR_PLAYER_INTERNAL;
6918 __mmplayer_reset_gapless_state(mm_player_t* player)
6921 MMPLAYER_RETURN_IF_FAIL(player
6923 && player->pipeline->audiobin
6924 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
6926 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
6933 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
6936 int ret = MM_ERROR_NONE;
6940 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
6942 /* cleanup stuffs */
6943 MMPLAYER_FREEIF(player->type);
6944 player->have_dynamic_pad = FALSE;
6945 player->no_more_pad = FALSE;
6946 player->num_dynamic_pad = 0;
6947 player->demux_pad_index = 0;
6948 player->use_deinterleave = FALSE;
6949 player->max_audio_channels = 0;
6950 player->video_share_api_delta = 0;
6951 player->video_share_clock_delta = 0;
6952 player->video_hub_download_mode = 0;
6954 MMPLAYER_SUBTITLE_INFO_LOCK(player);
6955 player->subtitle_language_list = NULL;
6956 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
6958 __mmplayer_reset_gapless_state(player);
6960 if (player->streamer) {
6961 __mm_player_streaming_deinitialize(player->streamer);
6962 __mm_player_streaming_destroy(player->streamer);
6963 player->streamer = NULL;
6966 /* cleanup unlinked mime type */
6967 MMPLAYER_FREEIF(player->unlinked_audio_mime);
6968 MMPLAYER_FREEIF(player->unlinked_video_mime);
6969 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
6971 /* cleanup running stuffs */
6972 __mmplayer_cancel_eos_timer(player);
6974 /* cleanup gst stuffs */
6975 if (player->pipeline) {
6976 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
6977 GstTagList* tag_list = player->pipeline->tag_list;
6979 /* first we need to disconnect all signal hander */
6980 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
6982 if (player->bus_watcher)
6983 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
6984 player->bus_watcher = 0;
6987 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
6988 MMPlayerGstElement* videobin = player->pipeline->videobin;
6989 MMPlayerGstElement* textbin = player->pipeline->textbin;
6990 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
6991 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
6992 gst_object_unref(bus);
6994 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6995 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
6996 if (ret != MM_ERROR_NONE) {
6997 LOGE("fail to change state to NULL\n");
6998 return MM_ERROR_PLAYER_INTERNAL;
7001 LOGW("succeeded in chaning state to NULL\n");
7003 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
7006 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
7007 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
7009 /* free avsysaudiosink
7010 avsysaudiosink should be unref when destory pipeline just after start play with BT.
7011 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
7013 MMPLAYER_FREEIF(audiobin);
7014 MMPLAYER_FREEIF(videobin);
7015 MMPLAYER_FREEIF(textbin);
7016 MMPLAYER_FREEIF(mainbin);
7020 gst_tag_list_free(tag_list);
7022 MMPLAYER_FREEIF(player->pipeline);
7024 MMPLAYER_FREEIF(player->album_art);
7026 if (player->v_stream_caps) {
7027 gst_caps_unref(player->v_stream_caps);
7028 player->v_stream_caps = NULL;
7030 if (player->a_stream_caps) {
7031 gst_caps_unref(player->a_stream_caps);
7032 player->a_stream_caps = NULL;
7035 if (player->s_stream_caps) {
7036 gst_caps_unref(player->s_stream_caps);
7037 player->s_stream_caps = NULL;
7039 _mmplayer_track_destroy(player);
7041 if (player->sink_elements)
7042 g_list_free(player->sink_elements);
7043 player->sink_elements = NULL;
7045 if (player->bufmgr) {
7046 tbm_bufmgr_deinit(player->bufmgr);
7047 player->bufmgr = NULL;
7050 LOGW("finished destroy pipeline\n");
7057 static int __gst_realize(mm_player_t* player)
7060 int ret = MM_ERROR_NONE;
7064 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7066 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7068 ret = __mmplayer_gst_create_pipeline(player);
7070 LOGE("failed to create pipeline\n");
7074 /* set pipeline state to READY */
7075 /* NOTE : state change to READY must be performed sync. */
7076 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7077 ret = __mmplayer_gst_set_state(player,
7078 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
7080 if (ret != MM_ERROR_NONE) {
7081 /* return error if failed to set state */
7082 LOGE("failed to set READY state");
7086 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7088 /* create dot before error-return. for debugging */
7089 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
7096 static int __gst_unrealize(mm_player_t* player)
7098 int ret = MM_ERROR_NONE;
7102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7104 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
7105 MMPLAYER_PRINT_STATE(player);
7107 /* release miscellaneous information */
7108 __mmplayer_release_misc(player);
7110 /* destroy pipeline */
7111 ret = __mmplayer_gst_destroy_pipeline(player);
7112 if (ret != MM_ERROR_NONE) {
7113 LOGE("failed to destory pipeline\n");
7117 /* release miscellaneous information.
7118 these info needs to be released after pipeline is destroyed. */
7119 __mmplayer_release_misc_post(player);
7121 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
7128 static int __gst_pending_seek(mm_player_t* player)
7130 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7131 int ret = MM_ERROR_NONE;
7135 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7137 if (!player->pending_seek.is_pending) {
7138 LOGD("pending seek is not reserved. nothing to do.\n");
7142 /* check player state if player could pending seek or not. */
7143 current_state = MMPLAYER_CURRENT_STATE(player);
7145 if (current_state != MM_PLAYER_STATE_PAUSED && current_state != MM_PLAYER_STATE_PLAYING) {
7146 LOGW("try to pending seek in %s state, try next time. \n",
7147 MMPLAYER_STATE_GET_NAME(current_state));
7151 LOGD("trying to play from(%"G_GINT64_FORMAT") pending position\n", player->pending_seek.pos);
7153 ret = __gst_set_position(player, player->pending_seek.format, player->pending_seek.pos, FALSE);
7155 if (MM_ERROR_NONE != ret)
7156 LOGE("failed to seek pending postion. just keep staying current position.\n");
7158 player->pending_seek.is_pending = FALSE;
7165 static int __gst_start(mm_player_t* player)
7167 gboolean sound_extraction = 0;
7168 int ret = MM_ERROR_NONE;
7169 gboolean async = FALSE;
7173 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7175 /* get sound_extraction property */
7176 mm_attrs_get_int_by_name(player->attrs, "pcm_extraction", &sound_extraction);
7178 /* NOTE : if SetPosition was called before Start. do it now */
7179 /* streaming doesn't support it. so it should be always sync */
7180 /* !!create one more api to check if there is pending seek rather than checking variables */
7181 if ((player->pending_seek.is_pending || sound_extraction) && !MMPLAYER_IS_STREAMING(player)) {
7182 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
7183 ret = __gst_pause(player, FALSE);
7184 if (ret != MM_ERROR_NONE) {
7185 LOGE("failed to set state to PAUSED for pending seek\n");
7189 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
7191 if (sound_extraction) {
7192 LOGD("setting pcm extraction\n");
7194 ret = __mmplayer_set_pcm_extraction(player);
7195 if (MM_ERROR_NONE != ret) {
7196 LOGW("failed to set pcm extraction\n");
7200 if (MM_ERROR_NONE != __gst_pending_seek(player))
7201 LOGW("failed to seek pending postion. starting from the begin of content.\n");
7205 LOGD("current state before doing transition");
7206 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7207 MMPLAYER_PRINT_STATE(player);
7209 /* set pipeline state to PLAYING */
7210 if (player->es_player_push_mode)
7212 /* set pipeline state to PLAYING */
7213 ret = __mmplayer_gst_set_state(player,
7214 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7216 if (ret == MM_ERROR_NONE) {
7217 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7219 LOGE("failed to set state to PLAYING");
7223 /* generating debug info before returning error */
7224 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-start");
7231 static int __gst_stop(mm_player_t* player)
7233 GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS;
7234 MMHandleType attrs = 0;
7235 gboolean rewind = FALSE;
7237 int ret = MM_ERROR_NONE;
7238 gboolean async = FALSE;
7242 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7243 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7245 LOGD("current state before doing transition");
7246 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
7247 MMPLAYER_PRINT_STATE(player);
7249 attrs = MMPLAYER_GET_ATTRS(player);
7251 LOGE("cannot get content attribute\n");
7252 return MM_ERROR_PLAYER_INTERNAL;
7255 /* Just set state to PAUESED and the rewind. it's usual player behavior. */
7256 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7258 if ((!MMPLAYER_IS_STREAMING(player) && !MMPLAYER_IS_MS_BUFF_SRC(player)) ||
7259 (player->streaming_type == STREAMING_SERVICE_VOD && player->videodec_linked))
7262 if (player->es_player_push_mode)
7265 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, timeout);
7267 /* return if set_state has failed */
7268 if (ret != MM_ERROR_NONE) {
7269 LOGE("failed to set state.\n");
7275 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7276 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0,
7277 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
7278 LOGW("failed to rewind\n");
7279 ret = MM_ERROR_PLAYER_SEEK;
7284 player->sent_bos = FALSE;
7286 if (player->es_player_push_mode) //for cloudgame
7289 /* wait for seek to complete */
7290 change_ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL, NULL, timeout * GST_SECOND);
7291 if (change_ret == GST_STATE_CHANGE_SUCCESS || change_ret == GST_STATE_CHANGE_NO_PREROLL) {
7292 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
7294 LOGE("fail to stop player.\n");
7295 ret = MM_ERROR_PLAYER_INTERNAL;
7296 __mmplayer_dump_pipeline_state(player);
7299 /* generate dot file if enabled */
7300 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-stop");
7307 int __gst_pause(mm_player_t* player, gboolean async)
7309 int ret = MM_ERROR_NONE;
7313 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7314 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7316 LOGD("current state before doing transition");
7317 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PAUSED;
7318 MMPLAYER_PRINT_STATE(player);
7320 /* set pipeline status to PAUSED */
7321 ret = __mmplayer_gst_set_state(player,
7322 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7324 if (FALSE == async) {
7325 if (ret != MM_ERROR_NONE) {
7326 GstMessage *msg = NULL;
7327 GTimer *timer = NULL;
7328 gdouble MAX_TIMEOUT_SEC = 3;
7330 LOGE("failed to set state to PAUSED");
7332 if (player->msg_posted) {
7333 LOGE("error msg is already posted.");
7337 timer = g_timer_new();
7338 g_timer_start(timer);
7340 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7343 msg = gst_bus_timed_pop(bus, 100 * GST_MSECOND);
7345 if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
7346 GError *error = NULL;
7348 /* parse error code */
7349 gst_message_parse_error(msg, &error, NULL);
7351 if (gst_structure_has_name(gst_message_get_structure(msg), "streaming_error")) {
7352 /* Note : the streaming error from the streaming source is handled
7353 * using __mmplayer_handle_streaming_error.
7355 __mmplayer_handle_streaming_error(player, msg);
7358 LOGE("paring error posted from bus, domain : %s, code : %d", g_quark_to_string(error->domain), error->code);
7360 if (error->domain == GST_STREAM_ERROR)
7361 ret = __gst_handle_stream_error(player, error, msg);
7362 else if (error->domain == GST_RESOURCE_ERROR)
7363 ret = __gst_handle_resource_error(player, error->code, NULL);
7364 else if (error->domain == GST_LIBRARY_ERROR)
7365 ret = __gst_handle_library_error(player, error->code);
7366 else if (error->domain == GST_CORE_ERROR)
7367 ret = __gst_handle_core_error(player, error->code);
7369 g_error_free(error);
7371 player->msg_posted = TRUE;
7373 gst_message_unref(msg);
7375 } while (!player->msg_posted && (g_timer_elapsed(timer, NULL) < MAX_TIMEOUT_SEC));
7377 gst_object_unref(bus);
7378 g_timer_stop(timer);
7379 g_timer_destroy(timer);
7383 } else if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_stream_cb) &&
7384 (!player->pipeline->videobin) && (!player->pipeline->audiobin)) {
7386 return MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7388 } else if (ret == MM_ERROR_NONE) {
7390 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED);
7394 /* generate dot file before returning error */
7395 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-pause");
7402 int __gst_resume(mm_player_t* player, gboolean async)
7404 int ret = MM_ERROR_NONE;
7409 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline,
7410 MM_ERROR_PLAYER_NOT_INITIALIZED);
7412 LOGD("current state before doing transition");
7413 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_PLAYING;
7414 MMPLAYER_PRINT_STATE(player);
7416 /* generate dot file before returning error */
7417 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7420 LOGD("do async state transition to PLAYING.\n");
7422 /* set pipeline state to PLAYING */
7423 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7425 ret = __mmplayer_gst_set_state(player,
7426 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout);
7427 if (ret != MM_ERROR_NONE) {
7428 LOGE("failed to set state to PLAYING\n");
7431 if (async == FALSE) {
7432 // MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PLAYING);
7433 LOGD("update state machine to %d\n", MM_PLAYER_STATE_PLAYING);
7434 ret = __mmplayer_set_state(player, MM_PLAYER_STATE_PLAYING);
7438 /* generate dot file before returning error */
7439 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-resume");
7447 __gst_set_position(mm_player_t* player, int format, gint64 position, gboolean internal_called)
7449 gint64 dur_nsec = 0;
7450 gint64 pos_nsec = 0;
7451 gboolean ret = TRUE;
7452 gboolean accurated = FALSE;
7453 GstSeekFlags seek_flags = GST_SEEK_FLAG_FLUSH;
7456 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7457 MMPLAYER_RETURN_VAL_IF_FAIL(!MMPLAYER_IS_LIVE_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
7459 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING
7460 && MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED)
7463 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7464 /* check duration */
7465 /* NOTE : duration cannot be zero except live streaming.
7466 * Since some element could have some timing problemn with quering duration, try again.
7468 if (player->duration == 0) {
7469 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec)) {
7470 /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly.
7471 * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */
7472 if ((MMPLAYER_IS_RTSP_STREAMING(player)) && (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7473 player->pending_seek.is_pending = TRUE;
7474 player->pending_seek.format = format;
7475 player->pending_seek.pos = position;
7476 player->doing_seek = FALSE;
7477 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7478 return MM_ERROR_NONE;
7483 player->duration = dur_nsec;
7486 LOGD("playback rate: %f\n", player->playback_rate);
7488 mm_attrs_get_int_by_name(player->attrs, "accurate_seek", &accurated);
7490 seek_flags |= GST_SEEK_FLAG_ACCURATE;
7492 seek_flags |= GST_SEEK_FLAG_KEY_UNIT;
7496 case MM_PLAYER_POS_FORMAT_TIME:
7498 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
7499 GstQuery *query = NULL;
7500 gboolean seekable = FALSE;
7502 /* check position is valid or not */
7503 if (position > player->duration)
7506 query = gst_query_new_seeking(GST_FORMAT_TIME);
7507 if (gst_element_query(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, query)) {
7508 gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
7509 gst_query_unref(query);
7512 LOGW("non-seekable content");
7513 player->doing_seek = FALSE;
7514 return MM_ERROR_PLAYER_NO_OP;
7517 LOGW("failed to get seeking query");
7518 gst_query_unref(query); /* keep seeking operation */
7521 LOGD("seeking to(%"G_GINT64_FORMAT") nsec, duration is %"G_GINT64_FORMAT" nsec\n", position, player->duration);
7523 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7524 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7525 This causes problem is position calculation during normal pause resume scenarios also.
7526 Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */
7527 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7528 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7529 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7530 LOGW("getting current position failed in seek\n");
7532 player->last_position = pos_nsec;
7533 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7536 if (player->doing_seek) {
7537 LOGD("not completed seek");
7538 return MM_ERROR_PLAYER_DOING_SEEK;
7542 if (!internal_called)
7543 player->doing_seek = TRUE;
7545 if ((MMPLAYER_IS_HTTP_STREAMING(player)) && (!player->videodec_linked)) {
7546 gint64 cur_time = 0;
7548 /* get current position */
7549 gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &cur_time);
7552 GstEvent *event = gst_event_new_seek(1.0,
7554 (GstSeekFlags)GST_SEEK_FLAG_FLUSH,
7555 GST_SEEK_TYPE_SET, cur_time,
7556 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7558 __gst_send_event_to_sink(player, event);
7560 if (!MMPLAYER_IS_RTSP_STREAMING(player))
7561 __gst_pause(player, FALSE);
7564 pos_nsec = position;
7566 /* rtsp streaming case, there is no sink after READY TO PAUSE state(no preroll state change).
7567 that's why set position through property. */
7568 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7569 (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) &&
7570 (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY) &&
7571 (!player->videodec_linked) && (!player->audiodec_linked)) {
7573 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "pending-start-position", pos_nsec, NULL);
7574 LOGD("[%s] set position =%"GST_TIME_FORMAT,
7575 GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_SRC].gst), GST_TIME_ARGS(pos_nsec));
7576 player->doing_seek = FALSE;
7577 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
7579 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7580 GST_FORMAT_TIME, seek_flags,
7581 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7585 LOGE("failed to set position.");
7591 case MM_PLAYER_POS_FORMAT_PERCENT:
7593 LOGD("seeking to %"G_GINT64_FORMAT"%%", position);
7595 if (player->doing_seek) {
7596 LOGD("not completed seek");
7597 return MM_ERROR_PLAYER_DOING_SEEK;
7600 if (!internal_called)
7601 player->doing_seek = TRUE;
7603 /* FIXIT : why don't we use 'GST_FORMAT_PERCENT' */
7604 pos_nsec = (gint64)((position * player->duration) / 100);
7605 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate,
7606 GST_FORMAT_TIME, seek_flags,
7607 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
7609 LOGE("failed to set position. pos[%"G_GINT64_FORMAT"] dur[%"G_GINT64_FORMAT"] ", pos_nsec, player->duration);
7619 /* NOTE : store last seeking point to overcome some bad operation
7620 * (returning zero when getting current position) of some elements
7622 player->last_position = pos_nsec;
7624 /* MSL should guarante playback rate when seek is selected during trick play of fast forward. */
7625 if (player->playback_rate > 1.0)
7626 _mmplayer_set_playspeed((MMHandleType)player, player->playback_rate, FALSE);
7629 return MM_ERROR_NONE;
7632 player->pending_seek.is_pending = TRUE;
7633 player->pending_seek.format = format;
7634 player->pending_seek.pos = position;
7636 LOGW("player current-state : %s, pending-state : %s, just preserve pending position(%"G_GINT64_FORMAT").\n",
7637 MMPLAYER_STATE_GET_NAME(MMPLAYER_CURRENT_STATE(player)),
7638 MMPLAYER_STATE_GET_NAME(MMPLAYER_PENDING_STATE(player)),
7639 player->pending_seek.pos);
7641 return MM_ERROR_NONE;
7644 LOGE("invalid arguments, position: %"G_GINT64_FORMAT" dur : %"G_GINT64_FORMAT" format : %d \n", position, player->duration, format);
7645 return MM_ERROR_INVALID_ARGUMENT;
7648 player->doing_seek = FALSE;
7649 return MM_ERROR_PLAYER_SEEK;
7652 #define TRICKPLAY_OFFSET GST_MSECOND
7655 __gst_get_position(mm_player_t* player, int format, gint64* position)
7657 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7658 gint64 pos_nsec = 0;
7659 gboolean ret = TRUE;
7661 MMPLAYER_RETURN_VAL_IF_FAIL(player && position && player->pipeline && player->pipeline->mainbin,
7662 MM_ERROR_PLAYER_NOT_INITIALIZED);
7664 current_state = MMPLAYER_CURRENT_STATE(player);
7666 /* NOTE : query position except paused state to overcome some bad operation
7667 * please refer to below comments in details
7669 if (current_state != MM_PLAYER_STATE_PAUSED)
7670 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7672 /* NOTE : get last point to overcome some bad operation of some elements
7673 *(returning zero when getting current position in paused state
7674 * and when failed to get postion during seeking
7676 if ((current_state == MM_PLAYER_STATE_PAUSED) || (!ret)) {
7677 LOGD("pos_nsec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7679 if (player->playback_rate < 0.0)
7680 pos_nsec = player->last_position - TRICKPLAY_OFFSET;
7682 pos_nsec = player->last_position;
7685 pos_nsec = player->last_position;
7687 player->last_position = pos_nsec;
7689 LOGD("returning last point : %"GST_TIME_FORMAT, GST_TIME_ARGS(pos_nsec));
7692 if (player->duration > 0 && pos_nsec > player->duration)
7693 pos_nsec = player->duration;
7695 player->last_position = pos_nsec;
7699 case MM_PLAYER_POS_FORMAT_TIME:
7700 *position = pos_nsec;
7703 case MM_PLAYER_POS_FORMAT_PERCENT:
7705 if (player->duration <= 0) {
7706 LOGD("duration is [%"G_GINT64_FORMAT"], so returning position 0\n", player->duration);
7709 LOGD("position is [%"G_GINT64_FORMAT"] nsec , duration is [%"G_GINT64_FORMAT"] nsec", pos_nsec, player->duration);
7710 *position = (gint64)(pos_nsec * 100 / player->duration);
7715 return MM_ERROR_PLAYER_INTERNAL;
7718 return MM_ERROR_NONE;
7722 static int __gst_get_buffer_position(mm_player_t* player, int format, unsigned long* start_pos, unsigned long* stop_pos)
7724 #define STREAMING_IS_FINISHED 0
7725 #define BUFFERING_MAX_PER 100
7726 #define DEFAULT_PER_VALUE -1
7727 #define CHECK_PERCENT_VALUE(a, min, max)(((a) > (min)) ? (((a) < (max)) ? (a) : (max)) : (min))
7729 MMPlayerGstElement *mainbin = NULL;
7730 gint start_per = DEFAULT_PER_VALUE, stop_per = DEFAULT_PER_VALUE;
7731 gint64 buffered_total = 0;
7732 gint64 position = 0;
7733 gint buffered_sec = -1;
7734 GstBufferingMode mode = GST_BUFFERING_STREAM;
7735 gint64 content_size_time = player->duration;
7736 guint64 content_size_bytes = player->http_content_size;
7738 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7740 player->pipeline->mainbin,
7741 MM_ERROR_PLAYER_NOT_INITIALIZED);
7743 MMPLAYER_RETURN_VAL_IF_FAIL(start_pos && stop_pos, MM_ERROR_INVALID_ARGUMENT);
7748 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7749 /* and rtsp is not ready yet. */
7750 LOGW("it's only used for http streaming case.\n");
7751 return MM_ERROR_PLAYER_NO_OP;
7754 if (format != MM_PLAYER_POS_FORMAT_PERCENT) {
7755 LOGW("Time format is not supported yet.\n");
7756 return MM_ERROR_INVALID_ARGUMENT;
7759 if (content_size_time <= 0 || content_size_bytes <= 0) {
7760 LOGW("there is no content size.");
7761 return MM_ERROR_NONE;
7764 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position) != MM_ERROR_NONE) {
7765 LOGW("fail to get current position.");
7766 return MM_ERROR_NONE;
7769 LOGD("pos %"G_GINT64_FORMAT" msec, dur %d sec, len %"G_GUINT64_FORMAT" bytes",
7770 GST_TIME_AS_MSECONDS(position), (guint)GST_TIME_AS_SECONDS(content_size_time), content_size_bytes);
7772 mainbin = player->pipeline->mainbin;
7773 start_per = (gint)(floor(100 *(gdouble)position / (gdouble)content_size_time));
7775 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7776 GstQuery *query = NULL;
7777 gint byte_in_rate = 0, byte_out_rate = 0;
7778 gint64 estimated_total = 0;
7780 query = gst_query_new_buffering(GST_FORMAT_BYTES);
7781 if (!query || !gst_element_query(mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, query)) {
7782 LOGW("fail to get buffering query from queue2");
7784 gst_query_unref(query);
7785 return MM_ERROR_NONE;
7788 gst_query_parse_buffering_stats(query, &mode, &byte_in_rate, &byte_out_rate, NULL);
7789 LOGD("mode %d, in_rate %d, out_rate %d", mode, byte_in_rate, byte_out_rate);
7791 if (mode == GST_BUFFERING_STREAM) {
7792 /* using only queue in case of push mode(ts / mp3) */
7793 if (gst_element_query_position(mainbin[MMPLAYER_M_SRC].gst,
7794 GST_FORMAT_BYTES, &buffered_total)) {
7795 LOGD("buffered_total %"G_GINT64_FORMAT, buffered_total);
7796 stop_per = 100 * buffered_total / content_size_bytes;
7799 /* GST_BUFFERING_TIMESHIFT or GST_BUFFERING_DOWNLOAD */
7801 guint num_of_ranges = 0;
7802 gint64 start_byte = 0, stop_byte = 0;
7804 gst_query_parse_buffering_range(query, NULL, NULL, NULL, &estimated_total);
7805 if (estimated_total != STREAMING_IS_FINISHED) {
7806 /* buffered size info from queue2 */
7807 num_of_ranges = gst_query_get_n_buffering_ranges(query);
7808 for (idx = 0; idx < num_of_ranges; idx++) {
7809 gst_query_parse_nth_buffering_range(query, idx, &start_byte, &stop_byte);
7810 LOGD("range %d, %"G_GINT64_FORMAT" ~ %"G_GUINT64_FORMAT, idx, start_byte, stop_byte);
7812 buffered_total += (stop_byte - start_byte);
7815 stop_per = BUFFERING_MAX_PER;
7817 gst_query_unref(query);
7820 if (stop_per == DEFAULT_PER_VALUE) {
7821 guint dur_sec = (guint)(content_size_time/GST_SECOND);
7823 guint avg_byterate = (guint)(content_size_bytes/dur_sec);
7825 /* buffered size info from multiqueue */
7826 if (mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) {
7827 guint curr_size_bytes = 0;
7828 g_object_get(G_OBJECT(mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst),
7829 "curr-size-bytes", &curr_size_bytes, NULL);
7830 LOGD("curr_size_bytes of multiqueue = %d", curr_size_bytes);
7831 buffered_total += curr_size_bytes;
7834 if (avg_byterate > 0)
7835 buffered_sec = (gint)(ceil((gdouble)buffered_total/(gdouble)avg_byterate));
7836 else if (player->total_maximum_bitrate > 0)
7837 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_maximum_bitrate));
7838 else if (player->total_bitrate > 0)
7839 buffered_sec = (gint)(ceil((gdouble)GET_BIT_FROM_BYTE(buffered_total)/(gdouble)player->total_bitrate));
7841 if (buffered_sec >= 0)
7842 stop_per = start_per +(gint)(ceil)(100*(gdouble)buffered_sec/(gdouble)dur_sec);
7846 *start_pos = CHECK_PERCENT_VALUE(start_per, 0, 100);
7847 *stop_pos = CHECK_PERCENT_VALUE(stop_per, *start_pos, 100);
7849 LOGD("buffered info: %"G_GINT64_FORMAT" bytes, %d sec, per %lu~%lu\n",
7850 buffered_total, buffered_sec, *start_pos, *stop_pos);
7852 return MM_ERROR_NONE;
7856 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
7861 LOGW("set_message_callback is called with invalid player handle\n");
7862 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7865 player->msg_cb = callback;
7866 player->msg_cb_param = user_param;
7868 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
7872 return MM_ERROR_NONE;
7875 static int __mmfplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
7877 int ret = MM_ERROR_PLAYER_INVALID_URI;
7882 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
7883 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
7884 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
7886 memset(data, 0, sizeof(MMPlayerParseProfile));
7888 if ((path = strstr(uri, "es_buff://"))) {
7890 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7891 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
7892 ret = MM_ERROR_NONE;
7894 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
7896 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7897 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7898 ret = MM_ERROR_NONE;
7900 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
7903 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7904 tmp = g_ascii_strdown(uri, strlen(uri));
7906 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
7907 data->uri_type = MM_PLAYER_URI_TYPE_SS;
7909 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
7911 ret = MM_ERROR_NONE;
7914 } else if ((path = strstr(uri, "rtspu://"))) {
7916 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7917 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7918 ret = MM_ERROR_NONE;
7920 } else if ((path = strstr(uri, "rtspr://"))) {
7921 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
7922 char *separater = strstr(path, "*");
7926 char *urgent = separater + strlen("*");
7928 if ((urgent_len = strlen(urgent))) {
7929 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
7930 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
7931 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
7932 ret = MM_ERROR_NONE;
7935 } else if ((path = strstr(uri, "mms://"))) {
7937 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
7938 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
7939 ret = MM_ERROR_NONE;
7941 } else if ((path = strstr(uri, "mem://"))) {
7944 char *buffer = NULL;
7945 char *seperator = strchr(path, ',');
7946 char ext[100] = {0,}, size[100] = {0,};
7949 if ((buffer = strstr(path, "ext="))) {
7950 buffer += strlen("ext=");
7952 if (strlen(buffer)) {
7953 strncpy(ext, buffer, 99);
7955 if ((seperator = strchr(ext, ','))
7956 || (seperator = strchr(ext, ' '))
7957 || (seperator = strchr(ext, '\0'))) {
7958 seperator[0] = '\0';
7963 if ((buffer = strstr(path, "size="))) {
7964 buffer += strlen("size=");
7966 if (strlen(buffer) > 0) {
7967 strncpy(size, buffer, 99);
7969 if ((seperator = strchr(size, ','))
7970 || (seperator = strchr(size, ' '))
7971 || (seperator = strchr(size, '\0'))) {
7972 seperator[0] = '\0';
7975 mem_size = atoi(size);
7980 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
7981 if (mem_size && param) {
7982 if (data->input_mem.buf)
7983 free(data->input_mem.buf);
7984 data->input_mem.buf = malloc(mem_size);
7986 if (data->input_mem.buf) {
7987 memcpy(data->input_mem.buf, param, mem_size);
7988 data->input_mem.len = mem_size;
7989 ret = MM_ERROR_NONE;
7991 LOGE("failed to alloc mem %d", mem_size);
7992 ret = MM_ERROR_PLAYER_INTERNAL;
7995 data->input_mem.offset = 0;
7996 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8000 gchar *location = NULL;
8003 if ((path = strstr(uri, "file://"))) {
8005 location = g_filename_from_uri(uri, NULL, &err);
8007 if (!location || (err != NULL)) {
8008 LOGE("Invalid URI '%s' for filesrc: %s", path,
8009 (err != NULL) ? err->message : "unknown error");
8011 if (err) g_error_free(err);
8012 if (location) g_free(location);
8014 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8018 LOGD("path from uri: %s", location);
8021 path = (location != NULL) ? (location) : ((char*)uri);
8022 int file_stat = MM_ERROR_NONE;
8024 file_stat = util_exist_file_path(path);
8026 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8027 if (file_stat == MM_ERROR_NONE) {
8028 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8030 if (util_is_sdp_file(path)) {
8031 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
8032 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8034 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8036 ret = MM_ERROR_NONE;
8037 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8038 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8040 LOGE("invalid uri, could not play..\n");
8041 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8044 if (location) g_free(location);
8048 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
8049 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
8050 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
8051 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
8053 /* dump parse result */
8054 SECURE_LOGW("incomming uri : %s\n", uri);
8055 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
8056 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
8064 __mmplayer_can_do_interrupt(mm_player_t *player)
8066 if (!player || !player->pipeline || !player->attrs) {
8067 LOGW("not initialized");
8071 if (player->set_mode.pcm_extraction) {
8072 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
8076 /* check if seeking */
8077 if (player->doing_seek) {
8078 MMMessageParamType msg_param;
8079 memset(&msg_param, 0, sizeof(MMMessageParamType));
8080 msg_param.code = MM_ERROR_PLAYER_SEEK;
8081 player->doing_seek = FALSE;
8082 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8086 /* check other thread */
8087 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8088 LOGW("locked already, cmd state : %d", player->cmd);
8090 /* check application command */
8091 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
8092 LOGW("playing.. should wait cmd lock then, will be interrupted");
8094 /* lock will be released at mrp_resource_release_cb() */
8095 MMPLAYER_CMD_LOCK(player);
8098 LOGW("nothing to do");
8101 LOGW("can interrupt immediately");
8105 FAILED: /* with CMD UNLOCKED */
8108 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
8113 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
8116 mm_player_t *player = NULL;
8120 if (user_data == NULL) {
8121 LOGE("- user_data is null\n");
8124 player = (mm_player_t *)user_data;
8126 /* do something to release resource here.
8127 * player stop and interrupt forwarding */
8128 if (!__mmplayer_can_do_interrupt(player)) {
8129 LOGW("no need to interrupt, so leave");
8131 MMMessageParamType msg = {0, };
8134 player->interrupted_by_resource = TRUE;
8136 /* get last play position */
8137 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
8138 LOGW("failed to get play position.");
8140 msg.union_type = MM_MSG_UNION_TIME;
8141 msg.time.elapsed = pos;
8142 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
8144 LOGD("video resource conflict so, resource will be freed by unrealizing");
8145 if (_mmplayer_unrealize((MMHandleType)player))
8146 LOGW("failed to unrealize");
8148 /* lock is called in __mmplayer_can_do_interrupt() */
8149 MMPLAYER_CMD_UNLOCK(player);
8152 if (res == player->video_overlay_resource)
8153 player->video_overlay_resource = FALSE;
8155 player->video_decoder_resource = FALSE;
8163 _mmplayer_create_player(MMHandleType handle)
8165 int ret = MM_ERROR_PLAYER_INTERNAL;
8166 bool enabled = false;
8168 mm_player_t* player = MM_PLAYER_CAST(handle);
8172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8174 /* initialize player state */
8175 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
8176 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
8177 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
8178 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
8180 /* check current state */
8181 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
8183 /* construct attributes */
8184 player->attrs = _mmplayer_construct_attribute(handle);
8186 if (!player->attrs) {
8187 LOGE("Failed to construct attributes\n");
8191 /* initialize gstreamer with configured parameter */
8192 if (!__mmplayer_init_gstreamer(player)) {
8193 LOGE("Initializing gstreamer failed\n");
8194 _mmplayer_deconstruct_attribute(handle);
8198 /* create lock. note that g_tread_init() has already called in gst_init() */
8199 g_mutex_init(&player->fsink_lock);
8201 /* create update tag lock */
8202 g_mutex_init(&player->update_tag_lock);
8204 /* create next play mutex */
8205 g_mutex_init(&player->next_play_thread_mutex);
8207 /* create next play cond */
8208 g_cond_init(&player->next_play_thread_cond);
8210 /* create next play thread */
8211 player->next_play_thread =
8212 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
8213 if (!player->next_play_thread) {
8214 LOGE("failed to create next play thread");
8215 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8216 g_mutex_clear(&player->next_play_thread_mutex);
8217 g_cond_clear(&player->next_play_thread_cond);
8221 player->bus_msg_q = g_queue_new();
8222 if (!player->bus_msg_q) {
8223 LOGE("failed to create queue for bus_msg");
8224 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
8228 ret = _mmplayer_initialize_video_capture(player);
8229 if (ret != MM_ERROR_NONE) {
8230 LOGE("failed to initialize video capture\n");
8234 /* initialize resource manager */
8235 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
8236 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
8237 &player->resource_manager)) {
8238 LOGE("failed to initialize resource manager\n");
8242 if (MMPLAYER_IS_HTTP_PD(player)) {
8243 player->pd_downloader = NULL;
8244 player->pd_file_save_path = NULL;
8247 /* create video bo lock and cond */
8248 g_mutex_init(&player->video_bo_mutex);
8249 g_cond_init(&player->video_bo_cond);
8251 /* create media stream callback mutex */
8252 g_mutex_init(&player->media_stream_cb_lock);
8254 /* create subtitle info lock and cond */
8255 g_mutex_init(&player->subtitle_info_mutex);
8256 g_cond_init(&player->subtitle_info_cond);
8258 player->streaming_type = STREAMING_SERVICE_NONE;
8260 /* give default value of audio effect setting */
8261 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
8262 player->sound.rg_enable = false;
8263 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8265 player->play_subtitle = FALSE;
8266 player->use_deinterleave = FALSE;
8267 player->max_audio_channels = 0;
8268 player->video_share_api_delta = 0;
8269 player->video_share_clock_delta = 0;
8270 player->has_closed_caption = FALSE;
8271 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8272 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
8273 player->pending_resume = FALSE;
8274 if (player->ini.dump_element_keyword[0][0] == '\0')
8275 player->ini.set_dump_element_flag = FALSE;
8277 player->ini.set_dump_element_flag = TRUE;
8279 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8280 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8281 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8283 /* Set video360 settings to their defaults for just-created player.
8286 player->is_360_feature_enabled = FALSE;
8287 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
8288 LOGI("spherical feature info: %d", enabled);
8290 player->is_360_feature_enabled = TRUE;
8292 LOGE("failed to get spherical feature info");
8295 player->is_content_spherical = FALSE;
8296 player->is_video360_enabled = TRUE;
8297 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8298 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8299 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8300 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8301 player->video360_zoom = 1.0f;
8302 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8303 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8305 /* set player state to null */
8306 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8307 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
8309 return MM_ERROR_NONE;
8313 g_mutex_clear(&player->fsink_lock);
8315 /* free update tag lock */
8316 g_mutex_clear(&player->update_tag_lock);
8318 g_queue_free(player->bus_msg_q);
8320 /* free next play thread */
8321 if (player->next_play_thread) {
8322 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8323 player->next_play_thread_exit = TRUE;
8324 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8325 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8327 g_thread_join(player->next_play_thread);
8328 player->next_play_thread = NULL;
8330 g_mutex_clear(&player->next_play_thread_mutex);
8331 g_cond_clear(&player->next_play_thread_cond);
8334 /* release attributes */
8335 _mmplayer_deconstruct_attribute(handle);
8343 __mmplayer_init_gstreamer(mm_player_t* player)
8345 static gboolean initialized = FALSE;
8346 static const int max_argc = 50;
8348 gchar** argv = NULL;
8349 gchar** argv2 = NULL;
8355 LOGD("gstreamer already initialized.\n");
8360 argc = malloc(sizeof(int));
8361 argv = malloc(sizeof(gchar*) * max_argc);
8362 argv2 = malloc(sizeof(gchar*) * max_argc);
8364 if (!argc || !argv || !argv2)
8367 memset(argv, 0, sizeof(gchar*) * max_argc);
8368 memset(argv2, 0, sizeof(gchar*) * max_argc);
8372 argv[0] = g_strdup("mmplayer");
8375 for (i = 0; i < 5; i++) {
8376 /* FIXIT : num of param is now fixed to 5. make it dynamic */
8377 if (strlen(player->ini.gst_param[i]) > 0) {
8378 argv[*argc] = g_strdup(player->ini.gst_param[i]);
8383 /* we would not do fork for scanning plugins */
8384 argv[*argc] = g_strdup("--gst-disable-registry-fork");
8387 /* check disable registry scan */
8388 if (player->ini.skip_rescan) {
8389 argv[*argc] = g_strdup("--gst-disable-registry-update");
8393 /* check disable segtrap */
8394 if (player->ini.disable_segtrap) {
8395 argv[*argc] = g_strdup("--gst-disable-segtrap");
8399 LOGD("initializing gstreamer with following parameter\n");
8400 LOGD("argc : %d\n", *argc);
8403 for (i = 0; i < arg_count; i++) {
8405 LOGD("argv[%d] : %s\n", i, argv2[i]);
8408 /* initializing gstreamer */
8409 if (!gst_init_check(argc, &argv, &err)) {
8410 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
8417 for (i = 0; i < arg_count; i++) {
8418 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
8419 MMPLAYER_FREEIF(argv2[i]);
8422 MMPLAYER_FREEIF(argv);
8423 MMPLAYER_FREEIF(argv2);
8424 MMPLAYER_FREEIF(argc);
8434 for (i = 0; i < arg_count; i++) {
8435 LOGD("free[%d] : %s\n", i, argv2[i]);
8436 MMPLAYER_FREEIF(argv2[i]);
8439 MMPLAYER_FREEIF(argv);
8440 MMPLAYER_FREEIF(argv2);
8441 MMPLAYER_FREEIF(argc);
8447 __mmplayer_destroy_streaming_ext(mm_player_t* player)
8449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8451 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
8452 _mmplayer_destroy_pd_downloader((MMHandleType)player);
8453 MMPLAYER_FREEIF(player->pd_file_save_path);
8456 return MM_ERROR_NONE;
8460 __mmplayer_check_async_state_transition(mm_player_t* player)
8462 GstState element_state = GST_STATE_VOID_PENDING;
8463 GstState element_pending_state = GST_STATE_VOID_PENDING;
8464 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8465 GstElement * element = NULL;
8466 gboolean async = FALSE;
8468 /* check player handle */
8469 MMPLAYER_RETURN_IF_FAIL(player &&
8471 player->pipeline->mainbin &&
8472 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8475 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
8477 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
8478 LOGD("don't need to check the pipeline state");
8482 MMPLAYER_PRINT_STATE(player);
8484 /* wait for state transition */
8485 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
8486 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
8488 if (ret == GST_STATE_CHANGE_FAILURE) {
8489 LOGE(" [%s] state : %s pending : %s \n",
8490 GST_ELEMENT_NAME(element),
8491 gst_element_state_get_name(element_state),
8492 gst_element_state_get_name(element_pending_state));
8494 /* dump state of all element */
8495 __mmplayer_dump_pipeline_state(player);
8500 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
8505 _mmplayer_destroy(MMHandleType handle)
8507 mm_player_t* player = MM_PLAYER_CAST(handle);
8511 /* check player handle */
8512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8514 /* destroy can called at anytime */
8515 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
8517 /* check async state transition */
8518 __mmplayer_check_async_state_transition(player);
8520 __mmplayer_destroy_streaming_ext(player);
8522 /* release next play thread */
8523 if (player->next_play_thread) {
8524 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
8525 player->next_play_thread_exit = TRUE;
8526 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8527 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
8529 LOGD("waitting for next play thread exit\n");
8530 g_thread_join(player->next_play_thread);
8531 g_mutex_clear(&player->next_play_thread_mutex);
8532 g_cond_clear(&player->next_play_thread_cond);
8533 LOGD("next play thread released\n");
8536 _mmplayer_release_video_capture(player);
8538 /* de-initialize resource manager */
8539 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
8540 player->resource_manager))
8541 LOGE("failed to deinitialize resource manager\n");
8543 /* release pipeline */
8544 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
8545 LOGE("failed to destory pipeline\n");
8546 return MM_ERROR_PLAYER_INTERNAL;
8549 g_queue_free(player->bus_msg_q);
8551 /* release subtitle info lock and cond */
8552 g_mutex_clear(&player->subtitle_info_mutex);
8553 g_cond_clear(&player->subtitle_info_cond);
8555 __mmplayer_release_dump_list(player->dump_list);
8557 /* release miscellaneous information */
8558 __mmplayer_release_misc(player);
8560 /* release miscellaneous information.
8561 these info needs to be released after pipeline is destroyed. */
8562 __mmplayer_release_misc_post(player);
8564 /* release attributes */
8565 _mmplayer_deconstruct_attribute(handle);
8568 g_mutex_clear(&player->fsink_lock);
8571 g_mutex_clear(&player->update_tag_lock);
8573 /* release video bo lock and cond */
8574 g_mutex_clear(&player->video_bo_mutex);
8575 g_cond_clear(&player->video_bo_cond);
8577 /* release media stream callback lock */
8578 g_mutex_clear(&player->media_stream_cb_lock);
8582 return MM_ERROR_NONE;
8586 __mmplayer_realize_streaming_ext(mm_player_t* player)
8588 int ret = MM_ERROR_NONE;
8591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8593 if (MMPLAYER_IS_HTTP_PD(player)) {
8594 gboolean bret = FALSE;
8596 player->pd_downloader = _mmplayer_create_pd_downloader();
8597 if (!player->pd_downloader) {
8598 LOGE("Unable to create PD Downloader...");
8599 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
8602 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
8604 if (FALSE == bret) {
8605 LOGE("Unable to create PD Downloader...");
8606 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
8615 _mmplayer_realize(MMHandleType hplayer)
8617 mm_player_t* player = (mm_player_t*)hplayer;
8620 MMHandleType attrs = 0;
8621 int ret = MM_ERROR_NONE;
8625 /* check player handle */
8626 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
8628 /* check current state */
8629 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
8631 attrs = MMPLAYER_GET_ATTRS(player);
8633 LOGE("fail to get attributes.\n");
8634 return MM_ERROR_PLAYER_INTERNAL;
8636 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8637 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
8639 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
8640 ret = __mmfplayer_parse_profile((const char*)uri, param, &player->profile);
8642 if (ret != MM_ERROR_NONE) {
8643 LOGE("failed to parse profile\n");
8648 if (uri && (strstr(uri, "es_buff://"))) {
8649 if (strstr(uri, "es_buff://push_mode"))
8650 player->es_player_push_mode = TRUE;
8652 player->es_player_push_mode = FALSE;
8655 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
8656 LOGW("mms protocol is not supported format.\n");
8657 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
8660 if (MMPLAYER_IS_STREAMING(player))
8661 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
8663 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
8665 player->smooth_streaming = FALSE;
8666 player->videodec_linked = 0;
8667 player->videosink_linked = 0;
8668 player->audiodec_linked = 0;
8669 player->audiosink_linked = 0;
8670 player->textsink_linked = 0;
8671 player->is_external_subtitle_present = FALSE;
8672 player->is_external_subtitle_added_now = FALSE;
8673 /* set the subtitle ON default */
8674 player->is_subtitle_off = FALSE;
8676 /* realize pipeline */
8677 ret = __gst_realize(player);
8678 if (ret != MM_ERROR_NONE)
8679 LOGE("fail to realize the player.\n");
8681 ret = __mmplayer_realize_streaming_ext(player);
8683 player->bus_msg_timeout = PLAYER_BUS_MSG_PREPARE_TIMEOUT;
8684 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8692 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
8695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8697 /* destroy can called at anytime */
8698 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
8699 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
8702 return MM_ERROR_NONE;
8706 _mmplayer_unrealize(MMHandleType hplayer)
8708 mm_player_t* player = (mm_player_t*)hplayer;
8709 int ret = MM_ERROR_NONE;
8713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8715 MMPLAYER_CMD_UNLOCK(player);
8716 /* destroy the gst bus msg thread which is created during realize.
8717 this funct have to be called before getting cmd lock. */
8718 _mmplayer_bus_msg_thread_destroy(player);
8719 MMPLAYER_CMD_LOCK(player);
8721 /* check current state */
8722 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
8724 /* check async state transition */
8725 __mmplayer_check_async_state_transition(player);
8727 __mmplayer_unrealize_streaming_ext(player);
8729 /* unrealize pipeline */
8730 ret = __gst_unrealize(player);
8732 /* set asm stop if success */
8733 if (MM_ERROR_NONE == ret) {
8734 if (!player->interrupted_by_resource) {
8735 if (player->video_decoder_resource != NULL) {
8736 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8737 player->video_decoder_resource);
8738 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8739 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
8741 player->video_decoder_resource = NULL;
8744 if (player->video_overlay_resource != NULL) {
8745 ret = mm_resource_manager_mark_for_release(player->resource_manager,
8746 player->video_overlay_resource);
8747 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8748 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
8750 player->video_overlay_resource = NULL;
8753 ret = mm_resource_manager_commit(player->resource_manager);
8754 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
8755 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
8758 LOGE("failed and don't change asm state to stop");
8766 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
8768 mm_player_t* player = (mm_player_t*)hplayer;
8770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8772 return __gst_set_message_callback(player, callback, user_param);
8776 _mmplayer_get_state(MMHandleType hplayer, int* state)
8778 mm_player_t *player = (mm_player_t*)hplayer;
8780 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
8782 *state = MMPLAYER_CURRENT_STATE(player);
8784 return MM_ERROR_NONE;
8789 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
8791 mm_player_t* player = (mm_player_t*) hplayer;
8792 GstElement* vol_element = NULL;
8797 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8799 LOGD("volume [L]=%f:[R]=%f\n",
8800 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
8802 /* invalid factor range or not */
8803 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
8804 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
8805 LOGE("Invalid factor!(valid factor:0~1.0)\n");
8806 return MM_ERROR_INVALID_ARGUMENT;
8810 /* not support to set other value into each channel */
8811 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
8812 return MM_ERROR_INVALID_ARGUMENT;
8814 /* Save volume to handle. Currently the first array element will be saved. */
8815 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
8817 /* check pipeline handle */
8818 if (!player->pipeline || !player->pipeline->audiobin) {
8819 LOGD("audiobin is not created yet\n");
8820 LOGD("but, current stored volume will be set when it's created.\n");
8822 /* NOTE : stored volume will be used in create_audiobin
8823 * returning MM_ERROR_NONE here makes application to able to
8824 * set volume at anytime.
8826 return MM_ERROR_NONE;
8829 /* setting volume to volume element */
8830 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8833 LOGD("volume is set [%f]\n", player->sound.volume);
8834 g_object_set(vol_element, "volume", player->sound.volume, NULL);
8839 return MM_ERROR_NONE;
8844 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
8846 mm_player_t* player = (mm_player_t*) hplayer;
8851 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8852 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
8854 /* returning stored volume */
8855 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
8856 volume->level[i] = player->sound.volume;
8860 return MM_ERROR_NONE;
8864 _mmplayer_set_mute(MMHandleType hplayer, int mute)
8866 mm_player_t* player = (mm_player_t*) hplayer;
8867 GstElement* vol_element = NULL;
8871 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8873 /* mute value shoud 0 or 1 */
8874 if (mute != 0 && mute != 1) {
8875 LOGE("bad mute value\n");
8877 /* FIXIT : definitly, we need _BAD_PARAM error code */
8878 return MM_ERROR_INVALID_ARGUMENT;
8881 player->sound.mute = mute;
8883 /* just hold mute value if pipeline is not ready */
8884 if (!player->pipeline || !player->pipeline->audiobin) {
8885 LOGD("pipeline is not ready. holding mute value\n");
8886 return MM_ERROR_NONE;
8889 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
8891 /* NOTE : volume will only created when the bt is enabled */
8893 LOGD("mute : %d\n", mute);
8894 g_object_set(vol_element, "mute", mute, NULL);
8896 LOGD("volume elemnet is not created. using volume in audiosink\n");
8900 return MM_ERROR_NONE;
8904 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
8906 mm_player_t* player = (mm_player_t*) hplayer;
8910 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8911 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
8913 /* just hold mute value if pipeline is not ready */
8914 if (!player->pipeline || !player->pipeline->audiobin) {
8915 LOGD("pipeline is not ready. returning stored value\n");
8916 *pmute = player->sound.mute;
8917 return MM_ERROR_NONE;
8920 *pmute = player->sound.mute;
8924 return MM_ERROR_NONE;
8928 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8930 mm_player_t* player = (mm_player_t*) hplayer;
8934 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8936 player->video_stream_changed_cb = callback;
8937 player->video_stream_changed_cb_user_param = user_param;
8938 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
8942 return MM_ERROR_NONE;
8946 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
8948 mm_player_t* player = (mm_player_t*) hplayer;
8952 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8954 player->audio_stream_changed_cb = callback;
8955 player->audio_stream_changed_cb_user_param = user_param;
8956 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
8960 return MM_ERROR_NONE;
8964 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
8966 mm_player_t* player = (mm_player_t*) hplayer;
8970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8972 player->audio_stream_render_cb_ex = callback;
8973 player->audio_stream_cb_user_param = user_param;
8974 player->audio_stream_sink_sync = sync;
8975 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);
8979 return MM_ERROR_NONE;
8983 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
8985 mm_player_t* player = (mm_player_t*) hplayer;
8989 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8991 if (callback && !player->bufmgr)
8992 player->bufmgr = tbm_bufmgr_init(-1);
8994 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
8995 player->video_stream_cb = callback;
8996 player->video_stream_cb_user_param = user_param;
8998 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
9002 return MM_ERROR_NONE;
9006 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
9008 mm_player_t* player = (mm_player_t*) hplayer;
9012 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9014 player->audio_stream_cb = callback;
9015 player->audio_stream_cb_user_param = user_param;
9016 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
9020 return MM_ERROR_NONE;
9024 __mmplayer_start_streaming_ext(mm_player_t *player)
9026 gint ret = MM_ERROR_NONE;
9029 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9031 if (MMPLAYER_IS_HTTP_PD(player)) {
9032 if (!player->pd_downloader) {
9033 ret = __mmplayer_realize_streaming_ext(player);
9035 if (ret != MM_ERROR_NONE) {
9036 LOGE("failed to realize streaming ext\n");
9041 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
9042 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
9044 LOGE("ERROR while starting PD...\n");
9045 return MM_ERROR_PLAYER_NOT_INITIALIZED;
9047 ret = MM_ERROR_NONE;
9056 _mmplayer_start(MMHandleType hplayer)
9058 mm_player_t* player = (mm_player_t*) hplayer;
9059 gint ret = MM_ERROR_NONE;
9063 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9065 /* check current state */
9066 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
9068 /* NOTE : we should check and create pipeline again if not created as we destroy
9069 * whole pipeline when stopping in streamming playback
9071 if (!player->pipeline) {
9072 ret = __gst_realize(player);
9073 if (MM_ERROR_NONE != ret) {
9074 LOGE("failed to realize before starting. only in streamming\n");
9080 ret = __mmplayer_start_streaming_ext(player);
9081 if (ret != MM_ERROR_NONE) {
9082 LOGE("failed to start streaming ext 0x%X", ret);
9086 /* start pipeline */
9087 ret = __gst_start(player);
9088 if (ret != MM_ERROR_NONE)
9089 LOGE("failed to start player.\n");
9096 /* NOTE: post "not supported codec message" to application
9097 * when one codec is not found during AUTOPLUGGING in MSL.
9098 * So, it's separated with error of __mmplayer_gst_callback().
9099 * And, if any codec is not found, don't send message here.
9100 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
9103 __mmplayer_handle_missed_plugin(mm_player_t* player)
9105 MMMessageParamType msg_param;
9106 memset(&msg_param, 0, sizeof(MMMessageParamType));
9107 gboolean post_msg_direct = FALSE;
9111 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9113 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
9114 player->not_supported_codec, player->can_support_codec);
9116 if (player->not_found_demuxer) {
9117 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9118 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
9120 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9121 MMPLAYER_FREEIF(msg_param.data);
9123 return MM_ERROR_NONE;
9126 if (player->not_supported_codec) {
9127 if (player->can_support_codec) {
9128 // There is one codec to play
9129 post_msg_direct = TRUE;
9131 if (player->pipeline->audiobin) // Some content has only PCM data in container.
9132 post_msg_direct = TRUE;
9135 if (post_msg_direct) {
9136 MMMessageParamType msg_param;
9137 memset(&msg_param, 0, sizeof(MMMessageParamType));
9139 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9140 LOGW("not found AUDIO codec, posting error code to application.\n");
9142 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9143 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9144 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
9145 LOGW("not found VIDEO codec, posting error code to application.\n");
9147 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
9148 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
9151 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9153 MMPLAYER_FREEIF(msg_param.data);
9155 return MM_ERROR_NONE;
9157 // no any supported codec case
9158 LOGW("not found any codec, posting error code to application.\n");
9160 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
9161 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
9162 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
9164 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
9165 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
9168 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9170 MMPLAYER_FREEIF(msg_param.data);
9176 return MM_ERROR_NONE;
9179 static void __mmplayer_check_pipeline(mm_player_t* player)
9181 GstState element_state = GST_STATE_VOID_PENDING;
9182 GstState element_pending_state = GST_STATE_VOID_PENDING;
9184 int ret = MM_ERROR_NONE;
9186 if (player->gapless.reconfigure) {
9187 LOGW("pipeline is under construction.\n");
9189 MMPLAYER_PLAYBACK_LOCK(player);
9190 MMPLAYER_PLAYBACK_UNLOCK(player);
9192 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
9194 /* wait for state transition */
9195 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
9197 if (ret == GST_STATE_CHANGE_FAILURE)
9198 LOGE("failed to change pipeline state within %d sec\n", timeout);
9202 /* NOTE : it should be able to call 'stop' anytime*/
9204 _mmplayer_stop(MMHandleType hplayer)
9206 mm_player_t* player = (mm_player_t*)hplayer;
9207 int ret = MM_ERROR_NONE;
9211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9213 /* check current state */
9214 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
9216 /* check pipline building state */
9217 __mmplayer_check_pipeline(player);
9218 __mmplayer_reset_gapless_state(player);
9220 /* NOTE : application should not wait for EOS after calling STOP */
9221 __mmplayer_cancel_eos_timer(player);
9223 __mmplayer_unrealize_streaming_ext(player);
9226 player->doing_seek = FALSE;
9229 ret = __gst_stop(player);
9231 if (ret != MM_ERROR_NONE)
9232 LOGE("failed to stop player.\n");
9240 _mmplayer_pause(MMHandleType hplayer)
9242 mm_player_t* player = (mm_player_t*)hplayer;
9243 gint64 pos_nsec = 0;
9244 gboolean async = FALSE;
9245 gint ret = MM_ERROR_NONE;
9249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9251 /* check current state */
9252 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
9254 /* check pipline building state */
9255 __mmplayer_check_pipeline(player);
9257 switch (MMPLAYER_CURRENT_STATE(player)) {
9258 case MM_PLAYER_STATE_READY:
9260 /* check prepare async or not.
9261 * In the case of streaming playback, it's recommned to avoid blocking wait.
9263 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9264 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
9266 /* Changing back sync of rtspsrc to async */
9267 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9268 LOGD("async prepare working mode for rtsp");
9274 case MM_PLAYER_STATE_PLAYING:
9276 /* NOTE : store current point to overcome some bad operation
9277 *(returning zero when getting current position in paused state) of some
9280 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
9281 LOGW("getting current position failed in paused\n");
9283 player->last_position = pos_nsec;
9285 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
9286 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
9287 This causes problem is position calculation during normal pause resume scenarios also.
9288 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
9289 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
9290 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
9291 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
9297 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
9298 LOGD("doing async pause in case of ms buff src");
9302 /* pause pipeline */
9303 ret = __gst_pause(player, async);
9305 if (ret != MM_ERROR_NONE)
9306 LOGE("failed to pause player. ret : 0x%x\n", ret);
9308 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
9309 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
9310 LOGE("failed to update display_rotation");
9319 _mmplayer_resume(MMHandleType hplayer)
9321 mm_player_t* player = (mm_player_t*)hplayer;
9322 int ret = MM_ERROR_NONE;
9323 gboolean async = FALSE;
9327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9329 /* Changing back sync mode rtspsrc to async */
9330 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
9331 LOGD("async resume for rtsp case");
9335 /* check current state */
9336 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
9338 ret = __gst_resume(player, async);
9340 if (ret != MM_ERROR_NONE)
9341 LOGE("failed to resume player.\n");
9349 __mmplayer_set_pcm_extraction(mm_player_t* player)
9351 gint64 start_nsec = 0;
9352 gint64 end_nsec = 0;
9353 gint64 dur_nsec = 0;
9354 gint64 dur_msec = 0;
9355 int required_start = 0;
9356 int required_end = 0;
9361 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9363 mm_attrs_multiple_get(player->attrs,
9365 "pcm_extraction_start_msec", &required_start,
9366 "pcm_extraction_end_msec", &required_end,
9369 LOGD("pcm extraction required position is from [%d] to [%d](msec)\n", required_start, required_end);
9371 if (required_start == 0 && required_end == 0) {
9372 LOGD("extracting entire stream");
9373 return MM_ERROR_NONE;
9374 } else if (required_start < 0 || required_start > required_end || required_end < 0) {
9375 LOGD("invalid range for pcm extraction");
9376 return MM_ERROR_INVALID_ARGUMENT;
9380 ret = gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec);
9382 LOGE("failed to get duration");
9383 return MM_ERROR_PLAYER_INTERNAL;
9385 dur_msec = GST_TIME_AS_MSECONDS(dur_nsec);
9387 if (dur_msec < required_end) {
9389 LOGD("invalid end pos for pcm extraction");
9390 return MM_ERROR_INVALID_ARGUMENT;
9393 start_nsec = required_start * G_GINT64_CONSTANT(1000000);
9394 end_nsec = required_end * G_GINT64_CONSTANT(1000000);
9396 if ((!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9399 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9400 GST_SEEK_TYPE_SET, start_nsec,
9401 GST_SEEK_TYPE_SET, end_nsec))) {
9402 LOGE("failed to seek for pcm extraction\n");
9404 return MM_ERROR_PLAYER_SEEK;
9407 LOGD("succeeded to set up segment extraction from [%llu] to [%llu](nsec)\n", start_nsec, end_nsec);
9411 return MM_ERROR_NONE;
9415 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
9417 mm_player_t* player = (mm_player_t*)hplayer;
9418 gint64 pos_nsec = 0;
9419 int ret = MM_ERROR_NONE;
9421 signed long long start = 0, stop = 0;
9422 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9425 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9426 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
9428 /* The sound of video is not supported under 0.0 and over 2.0. */
9429 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
9430 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
9433 _mmplayer_set_mute(hplayer, mute);
9435 if (player->playback_rate == rate)
9436 return MM_ERROR_NONE;
9438 /* If the position is reached at start potion during fast backward, EOS is posted.
9439 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
9441 player->playback_rate = rate;
9443 current_state = MMPLAYER_CURRENT_STATE(player);
9445 if (current_state != MM_PLAYER_STATE_PAUSED)
9446 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
9448 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
9450 if ((current_state == MM_PLAYER_STATE_PAUSED)
9451 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
9452 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
9453 pos_nsec = player->last_position;
9458 stop = GST_CLOCK_TIME_NONE;
9460 start = GST_CLOCK_TIME_NONE;
9464 if (!__gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
9465 player->playback_rate,
9467 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
9468 GST_SEEK_TYPE_SET, start,
9469 GST_SEEK_TYPE_SET, stop)) {
9470 LOGE("failed to set speed playback\n");
9471 return MM_ERROR_PLAYER_SEEK;
9474 LOGD("succeeded to set speed playback as %0.1f\n", rate);
9478 return MM_ERROR_NONE;;
9482 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
9484 mm_player_t* player = (mm_player_t*)hplayer;
9485 int ret = MM_ERROR_NONE;
9489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9491 /* check pipline building state */
9492 __mmplayer_check_pipeline(player);
9494 ret = __gst_set_position(player, format, position, FALSE);
9502 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
9504 mm_player_t* player = (mm_player_t*)hplayer;
9505 int ret = MM_ERROR_NONE;
9507 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9509 ret = __gst_get_position(player, format, position);
9515 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
9517 mm_player_t* player = (mm_player_t*)hplayer;
9518 int ret = MM_ERROR_NONE;
9520 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9521 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
9523 *duration = player->duration;
9528 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
9530 mm_player_t* player = (mm_player_t*)hplayer;
9531 int ret = MM_ERROR_NONE;
9533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9535 ret = __gst_get_buffer_position(player, format, start_pos, stop_pos);
9541 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
9543 mm_player_t* player = (mm_player_t*)hplayer;
9544 int ret = MM_ERROR_NONE;
9548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9550 ret = __gst_adjust_subtitle_position(player, format, position);
9558 __mmplayer_is_midi_type(gchar* str_caps)
9560 if ((g_strrstr(str_caps, "audio/midi")) ||
9561 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
9562 (g_strrstr(str_caps, "application/x-smaf")) ||
9563 (g_strrstr(str_caps, "audio/x-imelody")) ||
9564 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
9565 (g_strrstr(str_caps, "audio/xmf")) ||
9566 (g_strrstr(str_caps, "audio/mxmf"))) {
9575 __mmplayer_is_only_mp3_type(gchar *str_caps)
9577 if (g_strrstr(str_caps, "application/x-id3") ||
9578 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
9584 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
9586 GstStructure* caps_structure = NULL;
9587 gint samplerate = 0;
9591 MMPLAYER_RETURN_IF_FAIL(player && caps);
9593 caps_structure = gst_caps_get_structure(caps, 0);
9595 /* set stream information */
9596 gst_structure_get_int(caps_structure, "rate", &samplerate);
9597 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
9599 gst_structure_get_int(caps_structure, "channels", &channels);
9600 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
9602 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
9606 __mmplayer_update_content_type_info(mm_player_t* player)
9609 MMPLAYER_RETURN_IF_FAIL(player && player->type);
9611 if (__mmplayer_is_midi_type(player->type)) {
9612 player->bypass_audio_effect = TRUE;
9613 } else if (g_strrstr(player->type, "application/x-hls")) {
9614 /* If it can't know exact type when it parses uri because of redirection case,
9615 * it will be fixed by typefinder or when doing autoplugging.
9617 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
9618 if (player->streamer) {
9619 player->streamer->is_adaptive_streaming = TRUE;
9620 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
9621 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
9623 } else if (g_strrstr(player->type, "application/dash+xml")) {
9624 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
9631 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
9632 GstCaps *caps, gpointer data)
9634 mm_player_t* player = (mm_player_t*)data;
9639 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
9641 /* store type string */
9642 MMPLAYER_FREEIF(player->type);
9643 player->type = gst_caps_to_string(caps);
9645 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
9646 player, player->type, probability, gst_caps_get_size(caps));
9649 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
9650 (g_strrstr(player->type, "audio/x-raw-int"))) {
9651 LOGE("not support media format\n");
9653 if (player->msg_posted == FALSE) {
9654 MMMessageParamType msg_param;
9655 memset(&msg_param, 0, sizeof(MMMessageParamType));
9657 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
9658 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9660 /* don't post more if one was sent already */
9661 player->msg_posted = TRUE;
9666 __mmplayer_update_content_type_info(player);
9668 pad = gst_element_get_static_pad(tf, "src");
9670 LOGE("fail to get typefind src pad.\n");
9674 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
9675 gboolean async = FALSE;
9676 LOGE("failed to autoplug %s\n", player->type);
9678 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
9680 if (async && player->msg_posted == FALSE)
9681 __mmplayer_handle_missed_plugin(player);
9687 gst_object_unref(GST_OBJECT(pad));
9695 __mmplayer_create_decodebin(mm_player_t* player)
9697 GstElement *decodebin = NULL;
9701 /* create decodebin */
9702 decodebin = gst_element_factory_make("decodebin", NULL);
9705 LOGE("fail to create decodebin\n");
9709 /* raw pad handling signal */
9710 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
9711 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
9713 /* no-more-pad pad handling signal */
9714 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
9715 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
9717 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
9718 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
9720 /* This signal is emitted when a pad for which there is no further possible
9721 decoding is added to the decodebin.*/
9722 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
9723 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
9725 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9726 before looking for any elements that can handle that stream.*/
9727 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
9728 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
9730 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
9731 before looking for any elements that can handle that stream.*/
9732 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
9733 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
9735 /* This signal is emitted once decodebin has finished decoding all the data.*/
9736 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
9737 G_CALLBACK(__mmplayer_gst_decode_drained), player);
9739 /* This signal is emitted when a element is added to the bin.*/
9740 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
9741 G_CALLBACK(__mmplayer_gst_element_added), player);
9748 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
9750 MMPlayerGstElement* mainbin = NULL;
9751 GstElement* decodebin = NULL;
9752 GstElement* queue2 = NULL;
9753 GstPad* sinkpad = NULL;
9754 GstPad* qsrcpad = NULL;
9755 gint64 dur_bytes = 0L;
9757 guint max_buffer_size_bytes = 0;
9758 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
9761 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
9763 mainbin = player->pipeline->mainbin;
9765 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
9766 (MMPLAYER_IS_HTTP_STREAMING(player))) {
9767 LOGD("creating http streaming buffering queue(queue2)\n");
9769 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
9770 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
9772 queue2 = gst_element_factory_make("queue2", "queue2");
9774 LOGE("failed to create buffering queue element\n");
9778 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
9779 LOGE("failed to add buffering queue\n");
9783 sinkpad = gst_element_get_static_pad(queue2, "sink");
9784 qsrcpad = gst_element_get_static_pad(queue2, "src");
9786 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9787 LOGE("failed to link buffering queue");
9791 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
9792 LOGE("fail to get duration");
9794 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
9796 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
9798 if (dur_bytes > 0) {
9799 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
9800 type = MUXED_BUFFER_TYPE_FILE;
9802 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
9803 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
9809 /* NOTE : we cannot get any duration info from ts container in case of streaming */
9810 // if (!g_strrstr(GST_ELEMENT_NAME(sinkelement), "mpegtsdemux"))
9811 if (!g_strrstr(player->type, "video/mpegts")) {
9812 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
9813 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
9815 /* FIXME : pass ini setting directly. is this ok? */
9816 __mm_player_streaming_set_queue2(player->streamer,
9819 max_buffer_size_bytes,
9820 player->ini.http_buffering_time,
9822 player->ini.http_buffering_limit, // no meaning
9824 player->http_file_buffering_path,
9825 (guint64)dur_bytes);
9828 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
9829 LOGE("failed to sync queue2 state with parent\n");
9835 gst_object_unref(GST_OBJECT(sinkpad));
9837 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
9838 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
9842 /* create decodebin */
9843 decodebin = __mmplayer_create_decodebin(player);
9846 LOGE("can not create autoplug element\n");
9850 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
9851 LOGE("failed to add decodebin\n");
9855 /* to force caps on the decodebin element and avoid reparsing stuff by
9856 * typefind. It also avoids a deadlock in the way typefind activates pads in
9857 * the state change */
9858 g_object_set(decodebin, "sink-caps", caps, NULL);
9860 sinkpad = gst_element_get_static_pad(decodebin, "sink");
9862 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
9863 LOGE("failed to link decodebin\n");
9867 gst_object_unref(GST_OBJECT(sinkpad));
9869 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
9870 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
9872 /* set decodebin property about buffer in streaming playback. *
9873 * in case of HLS/DASH, it does not need to have big buffer *
9874 * because it is kind of adaptive streaming. */
9875 if (!MMPLAYER_IS_HTTP_PD(player) && MMPLAYER_IS_HTTP_STREAMING(player)) {
9876 guint max_size_bytes = MAX_DECODEBIN_BUFFER_BYTES;
9877 guint64 max_size_time = MAX_DECODEBIN_BUFFER_TIME;
9878 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
9880 if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)
9881 || MMPLAYER_IS_DASH_STREAMING(player)) {
9882 max_size_bytes = MAX_DECODEBIN_ADAPTIVE_BUFFER_BYTES;
9883 max_size_time = MAX_DECODEBIN_ADAPTIVE_BUFFER_TIME;
9886 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
9887 "high-percent", (gint)player->ini.http_buffering_limit,
9888 "low-percent", 1, // 1%
9889 "max-size-bytes", max_size_bytes,
9890 "max-size-time", (guint64)(max_size_time * GST_SECOND),
9891 "max-size-buffers", 0, NULL); // disable or automatic
9894 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
9895 LOGE("failed to sync decodebin state with parent\n");
9906 gst_object_unref(GST_OBJECT(sinkpad));
9909 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9910 * You need to explicitly set elements to the NULL state before
9911 * dropping the final reference, to allow them to clean up.
9913 gst_element_set_state(queue2, GST_STATE_NULL);
9915 /* And, it still has a parent "player".
9916 * You need to let the parent manage the object instead of unreffing the object directly.
9918 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
9919 gst_object_unref(queue2);
9924 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
9925 * You need to explicitly set elements to the NULL state before
9926 * dropping the final reference, to allow them to clean up.
9928 gst_element_set_state(decodebin, GST_STATE_NULL);
9930 /* And, it still has a parent "player".
9931 * You need to let the parent manage the object instead of unreffing the object directly.
9934 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
9935 gst_object_unref(decodebin);
9943 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
9947 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9948 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
9950 LOGD("class : %s, mime : %s \n", factory_class, mime);
9952 /* add missing plugin */
9953 /* NOTE : msl should check missing plugin for image mime type.
9954 * Some motion jpeg clips can have playable audio track.
9955 * So, msl have to play audio after displaying popup written video format not supported.
9957 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
9958 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
9959 LOGD("not found demuxer\n");
9960 player->not_found_demuxer = TRUE;
9961 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
9967 if (!g_strrstr(factory_class, "Demuxer")) {
9968 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
9969 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
9970 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
9972 /* check that clip have multi tracks or not */
9973 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
9974 LOGD("video plugin is already linked\n");
9976 LOGW("add VIDEO to missing plugin\n");
9977 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
9978 player->unlinked_video_mime = g_strdup_printf("%s", mime);
9980 } else if (g_str_has_prefix(mime, "audio")) {
9981 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
9982 LOGD("audio plugin is already linked\n");
9984 LOGW("add AUDIO to missing plugin\n");
9985 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
9986 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
9994 return MM_ERROR_NONE;
9999 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
10001 mm_player_t* player = (mm_player_t*)data;
10005 MMPLAYER_RETURN_IF_FAIL(player);
10007 /* remove fakesink. */
10008 if (!__mmplayer_gst_remove_fakesink(player,
10009 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
10010 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
10011 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
10012 * source element are not same. To overcome this situation, this function will called
10013 * several places and several times. Therefore, this is not an error case.
10018 LOGD("[handle: %p] pipeline has completely constructed", player);
10020 if ((player->ini.async_start) &&
10021 (player->msg_posted == FALSE) &&
10022 (player->cmd >= MMPLAYER_COMMAND_START))
10023 __mmplayer_handle_missed_plugin(player);
10025 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
10029 __mmplayer_verify_next_play_path(mm_player_t *player)
10031 MMHandleType attrs = 0;
10032 MMPlayerParseProfile profile;
10033 gint uri_idx = 0, check_cnt = 0;
10035 gint mode = MM_PLAYER_PD_MODE_NONE;
10039 guint num_of_list = 0;
10040 static int profile_tv = -1;
10044 LOGD("checking for gapless play");
10046 if (player->pipeline->textbin) {
10047 LOGE("subtitle path is enabled. gapless play is not supported.\n");
10051 attrs = MMPLAYER_GET_ATTRS(player);
10053 LOGE("fail to get attributes.\n");
10057 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
10059 if (__builtin_expect(profile_tv == -1, 0)) {
10061 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
10062 switch (*profileName) {
10072 /* gapless playback is not supported in case of video at TV profile. */
10073 if (profile_tv && video) {
10074 LOGW("not support video gapless playback");
10078 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
10079 if (mode == TRUE) {
10085 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
10086 LOGE("can not get play count\n");
10088 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
10089 LOGE("can not get gapless mode\n");
10091 if (video && !gapless) {
10092 LOGW("not enabled video gapless playback");
10096 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
10100 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
10104 num_of_list = g_list_length(player->uri_info.uri_list);
10106 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
10108 if (num_of_list == 0) {
10109 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
10110 LOGE("can not get profile_uri\n");
10115 LOGE("uri list is empty.\n");
10119 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10120 LOGD("add original path : %s ", uri);
10126 uri_idx = player->uri_info.uri_idx;
10131 if (check_cnt > num_of_list) {
10132 LOGE("there is no valid uri.");
10136 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
10138 if (uri_idx < num_of_list-1) {
10141 if ((count <= 1) && (count != -1)) {
10142 LOGD("no repeat.");
10144 } else if (count > 1) {
10145 /* decrease play count */
10146 /* we succeeded to rewind. update play count and then wait for next EOS */
10149 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
10151 /* commit attribute */
10152 if (mmf_attrs_commit(attrs))
10153 LOGE("failed to commit attribute\n");
10156 /* count < 0 : repeat continually */
10160 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10161 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
10164 LOGW("next uri does not exist\n");
10168 if (__mmfplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
10169 LOGE("failed to parse profile\n");
10173 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
10174 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
10175 LOGW("uri type is not supported(%d).", profile.uri_type);
10182 player->uri_info.uri_idx = uri_idx;
10183 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10185 if (mmf_attrs_commit(player->attrs)) {
10186 LOGE("failed to commit.\n");
10190 LOGD("next uri %s(%d)\n", uri, uri_idx);
10196 LOGE("unable to play next path. EOS will be posted soon.\n");
10201 __mmplayer_initialize_next_play(mm_player_t *player)
10207 player->smooth_streaming = FALSE;
10208 player->videodec_linked = 0;
10209 player->audiodec_linked = 0;
10210 player->videosink_linked = 0;
10211 player->audiosink_linked = 0;
10212 player->textsink_linked = 0;
10213 player->is_external_subtitle_present = FALSE;
10214 player->is_external_subtitle_added_now = FALSE;
10215 player->not_supported_codec = MISSING_PLUGIN_NONE;
10216 player->can_support_codec = FOUND_PLUGIN_NONE;
10217 player->pending_seek.is_pending = FALSE;
10218 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
10219 player->pending_seek.pos = 0;
10220 player->msg_posted = FALSE;
10221 player->has_many_types = FALSE;
10222 player->no_more_pad = FALSE;
10223 player->not_found_demuxer = 0;
10224 player->doing_seek = FALSE;
10225 player->max_audio_channels = 0;
10226 player->is_subtitle_force_drop = FALSE;
10227 player->play_subtitle = FALSE;
10228 player->adjust_subtitle_pos = 0;
10230 player->total_bitrate = 0;
10231 player->total_maximum_bitrate = 0;
10233 _mmplayer_track_initialize(player);
10234 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
10236 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
10237 player->bitrate[i] = 0;
10238 player->maximum_bitrate[i] = 0;
10241 if (player->v_stream_caps) {
10242 gst_caps_unref(player->v_stream_caps);
10243 player->v_stream_caps = NULL;
10246 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
10248 /* clean found parsers */
10249 if (player->parsers) {
10250 GList *parsers = player->parsers;
10251 for (; parsers; parsers = g_list_next(parsers)) {
10252 gchar *name = parsers->data;
10253 MMPLAYER_FREEIF(name);
10255 g_list_free(player->parsers);
10256 player->parsers = NULL;
10259 /* clean found audio decoders */
10260 if (player->audio_decoders) {
10261 GList *a_dec = player->audio_decoders;
10262 for (; a_dec; a_dec = g_list_next(a_dec)) {
10263 gchar *name = a_dec->data;
10264 MMPLAYER_FREEIF(name);
10266 g_list_free(player->audio_decoders);
10267 player->audio_decoders = NULL;
10274 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
10276 MMPlayerGstElement *mainbin = NULL;
10277 MMMessageParamType msg_param = {0,};
10278 GstElement *element = NULL;
10279 MMHandleType attrs = 0;
10281 enum MainElementID elemId = MMPLAYER_M_NUM;
10285 if ((player == NULL) ||
10286 (player->pipeline == NULL) ||
10287 (player->pipeline->mainbin == NULL)) {
10288 LOGE("player is null.\n");
10292 mainbin = player->pipeline->mainbin;
10293 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
10295 attrs = MMPLAYER_GET_ATTRS(player);
10297 LOGE("fail to get attributes.\n");
10301 /* Initialize Player values */
10302 __mmplayer_initialize_next_play(player);
10304 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
10306 if (__mmfplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
10307 LOGE("failed to parse profile\n");
10308 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10312 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
10313 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
10314 LOGE("it's dash or hls. not support.");
10315 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
10320 switch (player->profile.uri_type) {
10322 case MM_PLAYER_URI_TYPE_FILE:
10324 LOGD("using filesrc for 'file://' handler.\n");
10325 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
10326 LOGE("failed to get storage info");
10330 element = gst_element_factory_make("filesrc", "source");
10333 LOGE("failed to create filesrc\n");
10337 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
10340 case MM_PLAYER_URI_TYPE_URL_HTTP:
10342 gchar *user_agent, *cookies, **cookie_list;
10343 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
10344 user_agent = cookies = NULL;
10345 cookie_list = NULL;
10347 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
10349 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
10352 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
10354 /* get attribute */
10355 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
10356 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
10358 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
10359 LOGD("get timeout from ini\n");
10360 http_timeout = player->ini.http_timeout;
10363 /* get attribute */
10364 SECURE_LOGD("location : %s\n", player->profile.uri);
10365 SECURE_LOGD("cookies : %s\n", cookies);
10366 SECURE_LOGD("user_agent : %s\n", user_agent);
10367 LOGD("timeout : %d\n", http_timeout);
10369 /* setting property to streaming source */
10370 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
10371 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
10372 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
10374 /* parsing cookies */
10375 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
10376 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
10378 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
10382 LOGE("not support uri type %d\n", player->profile.uri_type);
10387 LOGE("no source element was created.\n");
10391 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10392 LOGE("failed to add source element to pipeline\n");
10393 gst_object_unref(GST_OBJECT(element));
10398 /* take source element */
10399 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
10400 mainbin[MMPLAYER_M_SRC].gst = element;
10404 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
10405 if (player->streamer == NULL) {
10406 player->streamer = __mm_player_streaming_create();
10407 __mm_player_streaming_initialize(player->streamer);
10410 elemId = MMPLAYER_M_TYPEFIND;
10411 element = gst_element_factory_make("typefind", "typefinder");
10412 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
10413 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
10415 elemId = MMPLAYER_M_AUTOPLUG;
10416 element = __mmplayer_create_decodebin(player);
10419 /* check autoplug element is OK */
10421 LOGE("can not create element(%d)\n", elemId);
10425 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
10426 LOGE("failed to add sinkbin to pipeline\n");
10427 gst_object_unref(GST_OBJECT(element));
10432 mainbin[elemId].id = elemId;
10433 mainbin[elemId].gst = element;
10435 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
10436 LOGE("Failed to link src - autoplug(or typefind)\n");
10440 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
10441 LOGE("Failed to change state of src element\n");
10445 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
10446 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
10447 LOGE("Failed to change state of decodebin\n");
10451 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
10452 LOGE("Failed to change state of src element\n");
10457 player->gapless.stream_changed = TRUE;
10458 player->gapless.running = TRUE;
10464 MMPLAYER_PLAYBACK_UNLOCK(player);
10466 if (!player->msg_posted) {
10467 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10468 player->msg_posted = TRUE;
10475 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
10477 mm_player_selector_t *selector = &player->selector[type];
10478 MMPlayerGstElement *sinkbin = NULL;
10479 enum MainElementID selectorId = MMPLAYER_M_NUM;
10480 enum MainElementID sinkId = MMPLAYER_M_NUM;
10481 GstPad *srcpad = NULL;
10482 GstPad *sinkpad = NULL;
10483 gboolean send_notice = FALSE;
10486 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10488 LOGD("type %d", type);
10491 case MM_PLAYER_TRACK_TYPE_AUDIO:
10492 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
10493 sinkId = MMPLAYER_A_BIN;
10494 sinkbin = player->pipeline->audiobin;
10496 case MM_PLAYER_TRACK_TYPE_VIDEO:
10497 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
10498 sinkId = MMPLAYER_V_BIN;
10499 sinkbin = player->pipeline->videobin;
10500 send_notice = TRUE;
10502 case MM_PLAYER_TRACK_TYPE_TEXT:
10503 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
10504 sinkId = MMPLAYER_T_BIN;
10505 sinkbin = player->pipeline->textbin;
10508 LOGE("requested type is not supportable");
10513 if (player->pipeline->mainbin[selectorId].gst) {
10516 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
10518 if (selector->event_probe_id != 0)
10519 gst_pad_remove_probe(srcpad, selector->event_probe_id);
10520 selector->event_probe_id = 0;
10522 if ((sinkbin) && (sinkbin[sinkId].gst)) {
10523 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
10525 if (srcpad && sinkpad) {
10526 /* after getting drained signal there is no data flows, so no need to do pad_block */
10527 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
10528 gst_pad_unlink(srcpad, sinkpad);
10530 /* send custom event to sink pad to handle it at video sink */
10532 LOGD("send custom event to sinkpad");
10533 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
10534 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
10535 gst_pad_send_event(sinkpad, event);
10539 gst_object_unref(sinkpad);
10542 gst_object_unref(srcpad);
10545 LOGD("selector release");
10547 /* release and unref requests pad from the selector */
10548 for (n = 0; n < selector->channels->len; n++) {
10549 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
10550 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
10552 g_ptr_array_set_size(selector->channels, 0);
10554 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
10555 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
10557 player->pipeline->mainbin[selectorId].gst = NULL;
10565 __mmplayer_deactivate_old_path(mm_player_t *player)
10568 MMPLAYER_RETURN_IF_FAIL(player);
10570 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
10571 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
10572 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
10573 LOGE("deactivate selector error");
10577 _mmplayer_track_destroy(player);
10578 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
10580 if (player->streamer) {
10581 __mm_player_streaming_deinitialize(player->streamer);
10582 __mm_player_streaming_destroy(player->streamer);
10583 player->streamer = NULL;
10586 MMPLAYER_PLAYBACK_LOCK(player);
10587 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
10594 if (!player->msg_posted) {
10595 MMMessageParamType msg = {0,};
10598 msg.code = MM_ERROR_PLAYER_INTERNAL;
10599 LOGE("next_uri_play> deactivate error");
10601 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
10602 player->msg_posted = TRUE;
10607 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
10609 int result = MM_ERROR_NONE;
10610 mm_player_t* player = (mm_player_t*) hplayer;
10613 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10616 player->http_file_buffering_path = (gchar*)file_path;
10617 LOGD("temp file path: %s\n", player->http_file_buffering_path);
10623 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
10625 int result = MM_ERROR_NONE;
10626 mm_player_t* player = (mm_player_t*) hplayer;
10629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10631 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
10632 if (mmf_attrs_commit(player->attrs)) {
10633 LOGE("failed to commit the original uri.\n");
10634 result = MM_ERROR_PLAYER_INTERNAL;
10636 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
10637 LOGE("failed to add the original uri in the uri list.\n");
10644 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
10646 mm_player_t* player = (mm_player_t*) hplayer;
10647 guint num_of_list = 0;
10651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10652 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
10654 if (player->pipeline && player->pipeline->textbin) {
10655 LOGE("subtitle path is enabled.\n");
10656 return MM_ERROR_PLAYER_INVALID_STATE;
10659 num_of_list = g_list_length(player->uri_info.uri_list);
10661 if (is_first_path == TRUE) {
10662 if (num_of_list == 0) {
10663 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10664 LOGD("add original path : %s", uri);
10666 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
10667 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
10669 LOGD("change original path : %s", uri);
10672 MMHandleType attrs = 0;
10673 attrs = MMPLAYER_GET_ATTRS(player);
10675 if (num_of_list == 0) {
10676 char *original_uri = NULL;
10679 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
10681 if (!original_uri) {
10682 LOGE("there is no original uri.");
10683 return MM_ERROR_PLAYER_INVALID_STATE;
10686 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
10687 player->uri_info.uri_idx = 0;
10689 LOGD("add original path at first : %s(%d)", original_uri);
10693 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
10694 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
10698 return MM_ERROR_NONE;
10701 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
10703 mm_player_t* player = (mm_player_t*) hplayer;
10704 char *next_uri = NULL;
10705 guint num_of_list = 0;
10708 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10710 num_of_list = g_list_length(player->uri_info.uri_list);
10712 if (num_of_list > 0) {
10713 gint uri_idx = player->uri_info.uri_idx;
10715 if (uri_idx < num_of_list-1)
10720 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
10721 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
10723 *uri = g_strdup(next_uri);
10727 return MM_ERROR_NONE;
10731 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
10732 GstCaps *caps, gpointer data)
10734 mm_player_t* player = (mm_player_t*)data;
10735 const gchar* klass = NULL;
10736 const gchar* mime = NULL;
10737 gchar* caps_str = NULL;
10739 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
10740 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10741 caps_str = gst_caps_to_string(caps);
10743 LOGW("unknown type of caps : %s from %s",
10744 caps_str, GST_ELEMENT_NAME(elem));
10746 MMPLAYER_FREEIF(caps_str);
10748 /* There is no available codec. */
10749 __mmplayer_check_not_supported_codec(player, klass, mime);
10753 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
10754 GstCaps * caps, gpointer data)
10756 mm_player_t* player = (mm_player_t*)data;
10757 const char* mime = NULL;
10758 gboolean ret = TRUE;
10760 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10761 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
10763 if (g_str_has_prefix(mime, "audio")) {
10764 GstStructure* caps_structure = NULL;
10765 gint samplerate = 0;
10767 gchar *caps_str = NULL;
10769 caps_structure = gst_caps_get_structure(caps, 0);
10770 gst_structure_get_int(caps_structure, "rate", &samplerate);
10771 gst_structure_get_int(caps_structure, "channels", &channels);
10773 if ((channels > 0 && samplerate == 0)) {
10774 LOGD("exclude audio...");
10778 caps_str = gst_caps_to_string(caps);
10779 /* set it directly because not sent by TAG */
10780 if (g_strrstr(caps_str, "mobile-xmf"))
10781 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
10782 MMPLAYER_FREEIF(caps_str);
10783 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
10784 MMMessageParamType msg_param;
10785 memset(&msg_param, 0, sizeof(MMMessageParamType));
10786 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
10787 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
10788 LOGD("video file is not supported on this device");
10790 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
10791 LOGD("already video linked");
10794 LOGD("found new stream");
10801 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
10803 int ret = MM_ERROR_NONE;
10805 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
10807 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
10808 GstStructure* str = NULL;
10810 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
10812 LOGD("audio codec type: %d", codec_type);
10813 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10814 /* sw codec will be skipped */
10815 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
10816 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
10817 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
10818 ret = MM_ERROR_PLAYER_INTERNAL;
10822 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10823 /* hw codec will be skipped */
10824 if (strcmp(player->ini.audiocodec_element_hw, "") &&
10825 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
10826 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
10827 ret = MM_ERROR_PLAYER_INTERNAL;
10832 str = gst_caps_get_structure(caps, 0);
10834 gst_structure_get_int(str, "channels", &channels);
10836 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
10837 if (player->max_audio_channels < channels)
10838 player->max_audio_channels = channels;
10840 /* set stream information */
10841 if (!player->audiodec_linked)
10842 __mmplayer_set_audio_attrs(player, caps);
10844 /* update codec info */
10845 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
10846 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
10847 player->audiodec_linked = 1;
10849 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
10851 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
10853 LOGD("video codec type: %d", codec_type);
10854 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
10855 /* sw codec is skipped */
10856 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
10857 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
10858 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
10859 ret = MM_ERROR_PLAYER_INTERNAL;
10863 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
10864 /* hw codec is skipped */
10865 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
10866 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
10867 ret = MM_ERROR_PLAYER_INTERNAL;
10872 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
10873 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
10875 /* mark video decoder for acquire */
10876 if (player->video_decoder_resource == NULL) {
10877 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
10878 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
10879 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
10880 &player->video_decoder_resource)
10881 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10882 LOGE("could not mark video_decoder resource for acquire");
10883 ret = MM_ERROR_PLAYER_INTERNAL;
10887 LOGW("video decoder resource is already acquired, skip it.");
10888 ret = MM_ERROR_PLAYER_INTERNAL;
10892 player->interrupted_by_resource = FALSE;
10893 /* acquire resources for video playing */
10894 if (mm_resource_manager_commit(player->resource_manager)
10895 != MM_RESOURCE_MANAGER_ERROR_NONE) {
10896 LOGE("could not acquire resources for video decoding\n");
10897 ret = MM_ERROR_PLAYER_INTERNAL;
10902 /* update codec info */
10903 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
10904 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
10905 player->videodec_linked = 1;
10913 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
10914 GstCaps* caps, GstElementFactory* factory, gpointer data)
10916 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
10917 We are defining our own and will be removed when it actually exposed */
10919 GST_AUTOPLUG_SELECT_TRY,
10920 GST_AUTOPLUG_SELECT_EXPOSE,
10921 GST_AUTOPLUG_SELECT_SKIP
10922 } GstAutoplugSelectResult;
10924 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
10925 mm_player_t* player = (mm_player_t*)data;
10927 gchar* factory_name = NULL;
10928 gchar* caps_str = NULL;
10929 const gchar* klass = NULL;
10932 factory_name = GST_OBJECT_NAME(factory);
10933 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
10934 caps_str = gst_caps_to_string(caps);
10936 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
10938 /* store type string */
10939 if (player->type == NULL) {
10940 player->type = gst_caps_to_string(caps);
10941 __mmplayer_update_content_type_info(player);
10944 /* filtering exclude keyword */
10945 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
10946 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
10947 LOGW("skipping [%s] by exculde keyword [%s]\n",
10948 factory_name, player->ini.exclude_element_keyword[idx]);
10950 result = GST_AUTOPLUG_SELECT_SKIP;
10955 /* exclude webm format */
10956 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
10957 * because webm format is not supportable.
10958 * If webm is disabled in "autoplug-continue", there is no state change
10959 * failure or error because the decodebin will expose the pad directly.
10960 * It make MSL invoke _prepare_async_callback.
10961 * So, we need to disable webm format in "autoplug-select" */
10962 if (caps_str && strstr(caps_str, "webm")) {
10963 LOGW("webm is not supported");
10964 result = GST_AUTOPLUG_SELECT_SKIP;
10968 /* check factory class for filtering */
10969 /* NOTE : msl don't need to use image plugins.
10970 * So, those plugins should be skipped for error handling.
10972 if (g_strrstr(klass, "Codec/Decoder/Image")) {
10973 LOGD("skipping [%s] by not required\n", factory_name);
10974 result = GST_AUTOPLUG_SELECT_SKIP;
10978 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
10979 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
10980 // TO CHECK : subtitle if needed, add subparse exception.
10981 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
10982 result = GST_AUTOPLUG_SELECT_SKIP;
10986 if (g_strrstr(factory_name, "mpegpsdemux")) {
10987 LOGD("skipping PS container - not support\n");
10988 result = GST_AUTOPLUG_SELECT_SKIP;
10992 if (g_strrstr(factory_name, "mssdemux"))
10993 player->smooth_streaming = TRUE;
10995 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
10996 (g_strrstr(klass, "Codec/Decoder/Video"))) {
10999 GstStructure *str = NULL;
11000 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
11002 /* don't make video because of not required */
11003 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
11004 (player->set_mode.media_packet_video_stream == FALSE)) {
11005 LOGD("no video because it's not required. -> return expose");
11006 result = GST_AUTOPLUG_SELECT_EXPOSE;
11010 /* get w/h for omx state-tune */
11011 /* FIXME: deprecated? */
11012 str = gst_caps_get_structure(caps, 0);
11013 gst_structure_get_int(str, "width", &width);
11016 if (player->v_stream_caps) {
11017 gst_caps_unref(player->v_stream_caps);
11018 player->v_stream_caps = NULL;
11021 player->v_stream_caps = gst_caps_copy(caps);
11022 LOGD("take caps for video state tune");
11023 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
11027 if (g_strrstr(klass, "Codec/Decoder")) {
11028 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
11029 LOGD("skipping %s codec", factory_name);
11030 result = GST_AUTOPLUG_SELECT_SKIP;
11036 MMPLAYER_FREEIF(caps_str);
11042 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
11045 //mm_player_t* player = (mm_player_t*)data;
11046 GstCaps* caps = NULL;
11048 LOGD("[Decodebin2] pad-removed signal\n");
11050 caps = gst_pad_query_caps(new_pad, NULL);
11052 gchar* caps_str = NULL;
11053 caps_str = gst_caps_to_string(caps);
11055 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
11057 MMPLAYER_FREEIF(caps_str);
11058 gst_caps_unref(caps);
11063 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
11065 mm_player_t* player = (mm_player_t*)data;
11066 GstIterator *iter = NULL;
11067 GValue item = { 0, };
11068 GstPad *pad = NULL;
11069 gboolean done = FALSE;
11070 gboolean is_all_drained = TRUE;
11073 MMPLAYER_RETURN_IF_FAIL(player);
11075 LOGD("__mmplayer_gst_decode_drained");
11077 if (player->use_deinterleave == TRUE) {
11078 LOGD("group playing mode.");
11082 if (!MMPLAYER_CMD_TRYLOCK(player)) {
11083 LOGW("Fail to get cmd lock");
11087 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
11088 !__mmplayer_verify_next_play_path(player)) {
11089 LOGD("decoding is finished.");
11090 __mmplayer_reset_gapless_state(player);
11091 MMPLAYER_CMD_UNLOCK(player);
11095 player->gapless.reconfigure = TRUE;
11097 /* check decodebin src pads whether they received EOS or not */
11098 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11101 switch (gst_iterator_next(iter, &item)) {
11102 case GST_ITERATOR_OK:
11103 pad = g_value_get_object(&item);
11104 if (pad && !GST_PAD_IS_EOS(pad)) {
11105 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
11106 is_all_drained = FALSE;
11109 g_value_reset(&item);
11111 case GST_ITERATOR_RESYNC:
11112 gst_iterator_resync(iter);
11114 case GST_ITERATOR_ERROR:
11115 case GST_ITERATOR_DONE:
11120 g_value_unset(&item);
11121 gst_iterator_free(iter);
11123 if (!is_all_drained) {
11124 LOGD("Wait util the all pads get EOS.");
11125 MMPLAYER_CMD_UNLOCK(player);
11130 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
11131 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
11133 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
11134 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
11135 __mmplayer_deactivate_old_path(player);
11136 MMPLAYER_CMD_UNLOCK(player);
11142 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
11144 mm_player_t* player = (mm_player_t*)data;
11145 const gchar* klass = NULL;
11146 gchar* factory_name = NULL;
11148 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
11149 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
11151 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
11153 if (__mmplayer_add_dump_buffer_probe(player, element))
11154 LOGD("add buffer probe");
11157 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
11158 gchar* selected = NULL;
11159 selected = g_strdup(GST_ELEMENT_NAME(element));
11160 player->audio_decoders = g_list_append(player->audio_decoders, selected);
11164 if (g_strrstr(klass, "Parser")) {
11165 gchar* selected = NULL;
11167 selected = g_strdup(factory_name);
11168 player->parsers = g_list_append(player->parsers, selected);
11171 if (g_strrstr(klass, "Demuxer/Adaptive")) {
11172 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
11173 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
11175 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
11176 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
11178 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11179 "max-bandwidth", player->adaptive_info.limit.bandwidth,
11180 "max-video-width", player->adaptive_info.limit.width,
11181 "max-video-height", player->adaptive_info.limit.height, NULL);
11183 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
11184 /* FIXIT : first value will be overwritten if there's more
11185 * than 1 demuxer/parser
11188 //LOGD("plugged element is demuxer. take it\n");
11189 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
11190 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
11192 /*Added for multi audio support */ // Q. del?
11193 if (g_strrstr(klass, "Demux")) {
11194 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
11195 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
11199 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
11200 int surface_type = 0;
11202 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
11205 // to support trust-zone only
11206 if (g_strrstr(factory_name, "asfdemux")) {
11207 LOGD("set file-location %s\n", player->profile.uri);
11208 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
11210 if (player->video_hub_download_mode == TRUE)
11211 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
11212 } else if (g_strrstr(factory_name, "legacyh264parse")) {
11213 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
11214 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
11215 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
11216 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
11217 (__mmplayer_is_only_mp3_type(player->type))) {
11218 LOGD("[mpegaudioparse] set streaming pull mode.");
11219 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
11221 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
11222 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
11225 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
11226 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
11227 LOGD("plugged element is multiqueue. take it\n");
11229 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
11230 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
11232 if (!MMPLAYER_IS_HTTP_PD(player) &&
11233 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
11234 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)))) {
11235 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
11236 __mm_player_streaming_set_multiqueue(player->streamer,
11239 player->ini.http_buffering_time,
11241 player->ini.http_buffering_limit);
11243 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
11250 static gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
11253 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11255 if (MMPLAYER_IS_STREAMING(player))
11258 /* This callback can be set to music player only. */
11259 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
11260 LOGW("audio callback is not supported for video");
11264 if (player->audio_stream_cb) {
11265 GstPad *pad = NULL;
11267 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
11270 LOGE("failed to get sink pad from audiosink to probe data\n");
11273 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
11274 __mmplayer_audio_stream_probe, player, NULL);
11276 gst_object_unref(pad);
11280 LOGE("There is no audio callback to configure.\n");
11290 __mmplayer_release_misc(mm_player_t* player)
11293 bool cur_mode = player->set_mode.rich_audio;
11296 MMPLAYER_RETURN_IF_FAIL(player);
11298 player->video_stream_cb = NULL;
11299 player->video_stream_cb_user_param = NULL;
11300 player->video_stream_prerolled = FALSE;
11302 player->audio_stream_cb = NULL;
11303 player->audio_stream_render_cb_ex = NULL;
11304 player->audio_stream_cb_user_param = NULL;
11305 player->audio_stream_sink_sync = false;
11307 player->video_stream_changed_cb = NULL;
11308 player->video_stream_changed_cb_user_param = NULL;
11310 player->audio_stream_changed_cb = NULL;
11311 player->audio_stream_changed_cb_user_param = NULL;
11313 player->sent_bos = FALSE;
11314 player->playback_rate = DEFAULT_PLAYBACK_RATE;
11316 player->doing_seek = FALSE;
11318 player->total_bitrate = 0;
11319 player->total_maximum_bitrate = 0;
11321 player->not_found_demuxer = 0;
11323 player->last_position = 0;
11324 player->duration = 0;
11325 player->http_content_size = 0;
11326 player->not_supported_codec = MISSING_PLUGIN_NONE;
11327 player->can_support_codec = FOUND_PLUGIN_NONE;
11328 player->pending_seek.is_pending = FALSE;
11329 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
11330 player->pending_seek.pos = 0;
11331 player->msg_posted = FALSE;
11332 player->has_many_types = FALSE;
11333 player->max_audio_channels = 0;
11334 player->video_share_api_delta = 0;
11335 player->video_share_clock_delta = 0;
11336 player->is_subtitle_force_drop = FALSE;
11337 player->play_subtitle = FALSE;
11338 player->adjust_subtitle_pos = 0;
11339 player->last_multiwin_status = FALSE;
11340 player->has_closed_caption = FALSE;
11341 player->set_mode.media_packet_video_stream = FALSE;
11342 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
11343 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
11345 player->set_mode.rich_audio = cur_mode;
11347 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
11348 player->bitrate[i] = 0;
11349 player->maximum_bitrate[i] = 0;
11352 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11354 /* remove media stream cb(appsrc cb) */
11355 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
11356 player->media_stream_buffer_status_cb[i] = NULL;
11357 player->media_stream_seek_data_cb[i] = NULL;
11358 player->buffer_cb_user_param[i] = NULL;
11359 player->seek_cb_user_param[i] = NULL;
11361 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11363 /* free memory related to audio effect */
11364 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
11366 if (player->adaptive_info.var_list) {
11367 g_list_free_full(player->adaptive_info.var_list, g_free);
11368 player->adaptive_info.var_list = NULL;
11371 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11372 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11373 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
11375 /* Reset video360 settings to their defaults in case if the pipeline is to be
11378 player->video360_metadata.is_spherical = -1;
11379 player->is_openal_plugin_used = FALSE;
11381 player->is_content_spherical = FALSE;
11382 player->is_video360_enabled = TRUE;
11383 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
11384 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
11385 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
11386 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
11387 player->video360_zoom = 1.0f;
11388 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
11389 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
11391 player->sound.rg_enable = false;
11397 __mmplayer_release_misc_post(mm_player_t* player)
11399 char *original_uri = NULL;
11402 /* player->pipeline is already released before. */
11404 MMPLAYER_RETURN_IF_FAIL(player);
11406 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
11408 /* clean found parsers */
11409 if (player->parsers) {
11410 GList *parsers = player->parsers;
11411 for (; parsers; parsers = g_list_next(parsers)) {
11412 gchar *name = parsers->data;
11413 MMPLAYER_FREEIF(name);
11415 g_list_free(player->parsers);
11416 player->parsers = NULL;
11419 /* clean found audio decoders */
11420 if (player->audio_decoders) {
11421 GList *a_dec = player->audio_decoders;
11422 for (; a_dec; a_dec = g_list_next(a_dec)) {
11423 gchar *name = a_dec->data;
11424 MMPLAYER_FREEIF(name);
11426 g_list_free(player->audio_decoders);
11427 player->audio_decoders = NULL;
11430 /* clean the uri list except original uri */
11431 if (player->uri_info.uri_list) {
11432 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
11434 if (player->attrs) {
11435 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
11436 LOGD("restore original uri = %s\n", original_uri);
11438 if (mmf_attrs_commit(player->attrs))
11439 LOGE("failed to commit the original uri.\n");
11442 GList *uri_list = player->uri_info.uri_list;
11443 for (; uri_list; uri_list = g_list_next(uri_list)) {
11444 gchar *uri = uri_list->data;
11445 MMPLAYER_FREEIF(uri);
11447 g_list_free(player->uri_info.uri_list);
11448 player->uri_info.uri_list = NULL;
11451 /* clear the audio stream buffer list */
11452 __mmplayer_audio_stream_clear_buffer(player, FALSE);
11454 /* clear the video stream bo list */
11455 __mmplayer_video_stream_destroy_bo_list(player);
11456 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
11458 if (player->profile.input_mem.buf) {
11459 free(player->profile.input_mem.buf);
11460 player->profile.input_mem.buf = NULL;
11462 player->profile.input_mem.len = 0;
11463 player->profile.input_mem.offset = 0;
11465 player->uri_info.uri_idx = 0;
11469 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
11471 GstElement *element = NULL;
11474 LOGD("creating %s to plug\n", name);
11476 element = gst_element_factory_make(name, NULL);
11478 LOGE("failed to create queue\n");
11482 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
11483 LOGE("failed to set state READY to %s\n", name);
11484 gst_object_unref(element);
11488 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
11489 LOGE("failed to add %s\n", name);
11490 gst_object_unref(element);
11494 sinkpad = gst_element_get_static_pad(element, "sink");
11496 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
11497 LOGE("failed to link %s\n", name);
11498 gst_object_unref(sinkpad);
11499 gst_object_unref(element);
11503 LOGD("linked %s to pipeline successfully\n", name);
11505 gst_object_unref(sinkpad);
11511 __mmplayer_check_subtitle(mm_player_t* player)
11513 MMHandleType attrs = 0;
11514 char *subtitle_uri = NULL;
11518 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11520 /* get subtitle attribute */
11521 attrs = MMPLAYER_GET_ATTRS(player);
11525 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
11526 if (!subtitle_uri || !strlen(subtitle_uri))
11529 LOGD("subtite uri is %s[%d]\n", subtitle_uri, strlen(subtitle_uri));
11530 player->is_external_subtitle_present = TRUE;
11538 __mmplayer_can_extract_pcm(mm_player_t* player)
11540 MMHandleType attrs = 0;
11541 gboolean sound_extraction = FALSE;
11543 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11545 attrs = MMPLAYER_GET_ATTRS(player);
11547 LOGE("fail to get attributes.");
11551 /* get sound_extraction property */
11552 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
11554 if (!sound_extraction) {
11555 LOGD("checking pcm extraction mode : %d ", sound_extraction);
11563 __mmplayer_handle_streaming_error(mm_player_t* player, GstMessage * message)
11566 MMMessageParamType msg_param;
11567 gchar *msg_src_element = NULL;
11568 GstStructure *s = NULL;
11569 guint error_id = 0;
11570 gchar *error_string = NULL;
11574 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11575 MMPLAYER_RETURN_VAL_IF_FAIL(message, FALSE);
11577 s = gst_structure_copy(gst_message_get_structure(message));
11580 if (!gst_structure_get_uint(s, "error_id", &error_id))
11581 error_id = MMPLAYER_STREAMING_ERROR_NONE;
11583 switch (error_id) {
11584 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_AUDIO:
11585 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_AUDIO;
11587 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_VIDEO:
11588 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_VIDEO;
11590 case MMPLAYER_STREAMING_ERROR_CONNECTION_FAIL:
11591 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONNECTION_FAIL;
11593 case MMPLAYER_STREAMING_ERROR_DNS_FAIL:
11594 msg_param.code = MM_ERROR_PLAYER_STREAMING_DNS_FAIL;
11596 case MMPLAYER_STREAMING_ERROR_SERVER_DISCONNECTED:
11597 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_DISCONNECTED;
11599 case MMPLAYER_STREAMING_ERROR_BAD_SERVER:
11600 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_SERVER;
11602 case MMPLAYER_STREAMING_ERROR_INVALID_PROTOCOL:
11603 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_PROTOCOL;
11605 case MMPLAYER_STREAMING_ERROR_INVALID_URL:
11606 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_URL;
11608 case MMPLAYER_STREAMING_ERROR_UNEXPECTED_MSG:
11609 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNEXPECTED_MSG;
11611 case MMPLAYER_STREAMING_ERROR_OUT_OF_MEMORIES:
11612 msg_param.code = MM_ERROR_PLAYER_STREAMING_OUT_OF_MEMORIES;
11614 case MMPLAYER_STREAMING_ERROR_RTSP_TIMEOUT:
11615 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_TIMEOUT;
11617 case MMPLAYER_STREAMING_ERROR_BAD_REQUEST:
11618 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_REQUEST;
11620 case MMPLAYER_STREAMING_ERROR_NOT_AUTHORIZED:
11621 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_AUTHORIZED;
11623 case MMPLAYER_STREAMING_ERROR_PAYMENT_REQUIRED:
11624 msg_param.code = MM_ERROR_PLAYER_STREAMING_PAYMENT_REQUIRED;
11626 case MMPLAYER_STREAMING_ERROR_FORBIDDEN:
11627 msg_param.code = MM_ERROR_PLAYER_STREAMING_FORBIDDEN;
11629 case MMPLAYER_STREAMING_ERROR_CONTENT_NOT_FOUND:
11630 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONTENT_NOT_FOUND;
11632 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_ALLOWED:
11633 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_ALLOWED;
11635 case MMPLAYER_STREAMING_ERROR_NOT_ACCEPTABLE:
11636 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ACCEPTABLE;
11638 case MMPLAYER_STREAMING_ERROR_PROXY_AUTHENTICATION_REQUIRED:
11639 msg_param.code = MM_ERROR_PLAYER_STREAMING_PROXY_AUTHENTICATION_REQUIRED;
11641 case MMPLAYER_STREAMING_ERROR_SERVER_TIMEOUT:
11642 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVER_TIMEOUT;
11644 case MMPLAYER_STREAMING_ERROR_GONE:
11645 msg_param.code = MM_ERROR_PLAYER_STREAMING_GONE;
11647 case MMPLAYER_STREAMING_ERROR_LENGTH_REQUIRED:
11648 msg_param.code = MM_ERROR_PLAYER_STREAMING_LENGTH_REQUIRED;
11650 case MMPLAYER_STREAMING_ERROR_PRECONDITION_FAILED:
11651 msg_param.code = MM_ERROR_PLAYER_STREAMING_PRECONDITION_FAILED;
11653 case MMPLAYER_STREAMING_ERROR_REQUEST_ENTITY_TOO_LARGE:
11654 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_ENTITY_TOO_LARGE;
11656 case MMPLAYER_STREAMING_ERROR_REQUEST_URI_TOO_LARGE:
11657 msg_param.code = MM_ERROR_PLAYER_STREAMING_REQUEST_URI_TOO_LARGE;
11659 case MMPLAYER_STREAMING_ERROR_UNSUPPORTED_MEDIA_TYPE:
11660 msg_param.code = MM_ERROR_PLAYER_STREAMING_UNSUPPORTED_MEDIA_TYPE;
11662 case MMPLAYER_STREAMING_ERROR_PARAMETER_NOT_UNDERSTOOD:
11663 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_NOT_UNDERSTOOD;
11665 case MMPLAYER_STREAMING_ERROR_CONFERENCE_NOT_FOUND:
11666 msg_param.code = MM_ERROR_PLAYER_STREAMING_CONFERENCE_NOT_FOUND;
11668 case MMPLAYER_STREAMING_ERROR_NOT_ENOUGH_BANDWIDTH:
11669 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_ENOUGH_BANDWIDTH;
11671 case MMPLAYER_STREAMING_ERROR_NO_SESSION_ID:
11672 msg_param.code = MM_ERROR_PLAYER_STREAMING_NO_SESSION_ID;
11674 case MMPLAYER_STREAMING_ERROR_METHOD_NOT_VALID_IN_THIS_STATE:
11675 msg_param.code = MM_ERROR_PLAYER_STREAMING_METHOD_NOT_VALID_IN_THIS_STATE;
11677 case MMPLAYER_STREAMING_ERROR_HEADER_FIELD_NOT_VALID_FOR_SOURCE:
11678 msg_param.code = MM_ERROR_PLAYER_STREAMING_HEADER_FIELD_NOT_VALID_FOR_SOURCE;
11680 case MMPLAYER_STREAMING_ERROR_INVALID_RANGE:
11681 msg_param.code = MM_ERROR_PLAYER_STREAMING_INVALID_RANGE;
11683 case MMPLAYER_STREAMING_ERROR_PARAMETER_IS_READONLY:
11684 msg_param.code = MM_ERROR_PLAYER_STREAMING_PARAMETER_IS_READONLY;
11686 case MMPLAYER_STREAMING_ERROR_AGGREGATE_OP_NOT_ALLOWED:
11687 msg_param.code = MM_ERROR_PLAYER_STREAMING_AGGREGATE_OP_NOT_ALLOWED;
11689 case MMPLAYER_STREAMING_ERROR_ONLY_AGGREGATE_OP_ALLOWED:
11690 msg_param.code = MM_ERROR_PLAYER_STREAMING_ONLY_AGGREGATE_OP_ALLOWED;
11692 case MMPLAYER_STREAMING_ERROR_BAD_TRANSPORT:
11693 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_TRANSPORT;
11695 case MMPLAYER_STREAMING_ERROR_DESTINATION_UNREACHABLE:
11696 msg_param.code = MM_ERROR_PLAYER_STREAMING_DESTINATION_UNREACHABLE;
11698 case MMPLAYER_STREAMING_ERROR_INTERNAL_SERVER_ERROR:
11699 msg_param.code = MM_ERROR_PLAYER_STREAMING_INTERNAL_SERVER_ERROR;
11701 case MMPLAYER_STREAMING_ERROR_NOT_IMPLEMENTED:
11702 msg_param.code = MM_ERROR_PLAYER_STREAMING_NOT_IMPLEMENTED;
11704 case MMPLAYER_STREAMING_ERROR_BAD_GATEWAY:
11705 msg_param.code = MM_ERROR_PLAYER_STREAMING_BAD_GATEWAY;
11707 case MMPLAYER_STREAMING_ERROR_SERVICE_UNAVAILABLE:
11708 msg_param.code = MM_ERROR_PLAYER_STREAMING_SERVICE_UNAVAILABLE;
11710 case MMPLAYER_STREAMING_ERROR_GATEWAY_TIME_OUT:
11711 msg_param.code = MM_ERROR_PLAYER_STREAMING_GATEWAY_TIME_OUT;
11713 case MMPLAYER_STREAMING_ERROR_RTSP_VERSION_NOT_SUPPORTED:
11714 msg_param.code = MM_ERROR_PLAYER_STREAMING_RTSP_VERSION_NOT_SUPPORTED;
11716 case MMPLAYER_STREAMING_ERROR_OPTION_NOT_SUPPORTED:
11717 msg_param.code = MM_ERROR_PLAYER_STREAMING_OPTION_NOT_SUPPORTED;
11721 gst_structure_free(s);
11722 return MM_ERROR_PLAYER_STREAMING_FAIL;
11726 error_string = g_strdup(gst_structure_get_string(s, "error_string"));
11728 msg_param.data = (void *) error_string;
11730 if (message->src) {
11731 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
11733 LOGE("-Msg src : [%s] Code : [%x] Error : [%s] \n",
11734 msg_src_element, msg_param.code, (char*)msg_param.data);
11737 /* post error to application */
11738 if (!player->msg_posted) {
11739 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11741 /* don't post more if one was sent already */
11742 player->msg_posted = TRUE;
11744 LOGD("skip error post because it's sent already.\n");
11746 gst_structure_free(s);
11748 g_free(error_string);
11755 __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
11757 MMPLAYER_RETURN_IF_FAIL(player);
11759 /* post now if delay is zero */
11760 if (delay_in_ms == 0 || player->set_mode.pcm_extraction) {
11761 LOGD("eos delay is zero. posting EOS now\n");
11762 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11764 if (player->set_mode.pcm_extraction)
11765 __mmplayer_cancel_eos_timer(player);
11770 /* cancel if existing */
11771 __mmplayer_cancel_eos_timer(player);
11773 /* init new timeout */
11774 /* NOTE : consider give high priority to this timer */
11775 LOGD("posting EOS message after [%d] msec\n", delay_in_ms);
11777 player->eos_timer = g_timeout_add(delay_in_ms,
11778 __mmplayer_eos_timer_cb, player);
11780 player->context.global_default = g_main_context_default();
11781 LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
11783 /* check timer is valid. if not, send EOS now */
11784 if (player->eos_timer == 0) {
11785 LOGW("creating timer for delayed EOS has failed. sending EOS now\n");
11786 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11791 __mmplayer_cancel_eos_timer(mm_player_t* player)
11793 MMPLAYER_RETURN_IF_FAIL(player);
11795 if (player->eos_timer) {
11796 LOGD("cancel eos timer");
11797 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
11798 player->eos_timer = 0;
11805 __mmplayer_eos_timer_cb(gpointer u_data)
11807 mm_player_t* player = NULL;
11808 MMHandleType attrs = 0;
11811 MMPLAYER_RETURN_VAL_IF_FAIL(u_data, FALSE);
11813 player = (mm_player_t*) u_data;
11814 attrs = MMPLAYER_GET_ATTRS(player);
11816 mm_attrs_get_int_by_name(attrs, "profile_play_count", &count);
11819 gint ret_value = 0;
11820 ret_value = __gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, 0, TRUE);
11821 if (ret_value != MM_ERROR_NONE)
11822 LOGE("seeking to 0 failed in repeat play");
11825 MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL);
11828 /* we are returning FALSE as we need only one posting */
11832 /* sending event to one of sinkelements */
11834 __gst_send_event_to_sink(mm_player_t* player, GstEvent* event)
11836 GstEvent * event2 = NULL;
11837 GList *sinks = NULL;
11838 gboolean res = FALSE;
11841 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11842 MMPLAYER_RETURN_VAL_IF_FAIL(event, FALSE);
11844 /* While adding subtitles in live feeds seek is getting called.
11845 Adding defensive check in framework layer.*/
11846 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11847 if (MMPLAYER_IS_LIVE_STREAMING(player)) {
11848 LOGE("Should not send seek event during live playback");
11853 if (player->play_subtitle)
11854 event2 = gst_event_copy((const GstEvent *)event);
11856 sinks = player->sink_elements;
11858 GstElement *sink = GST_ELEMENT_CAST(sinks->data);
11860 if (GST_IS_ELEMENT(sink)) {
11861 /* keep ref to the event */
11862 gst_event_ref(event);
11864 if ((res = gst_element_send_event(sink, event))) {
11865 LOGD("sending event[%s] to sink element [%s] success!\n",
11866 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11868 /* rtsp case, asyn_done is not called after seek during pause state */
11869 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
11870 if (GST_EVENT_TYPE(event) == GST_EVENT_SEEK) {
11871 if (MMPLAYER_TARGET_STATE(player) == MM_PLAYER_STATE_PAUSED) {
11872 LOGD("RTSP seek completed, after pause state..\n");
11873 player->doing_seek = FALSE;
11874 MMPLAYER_POST_MSG(player, MM_MESSAGE_SEEK_COMPLETED, NULL);
11880 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
11881 sinks = g_list_next(sinks);
11888 LOGD("sending event[%s] to sink element [%s] failed. try with next one.\n",
11889 GST_EVENT_TYPE_NAME(event), GST_ELEMENT_NAME(sink));
11892 sinks = g_list_next(sinks);
11895 /* Note : Textbin is not linked to the video or audio bin.
11896 * It needs to send the event to the text sink seperatelly.
11898 if (player->play_subtitle && player->pipeline) {
11899 GstElement *text_sink = GST_ELEMENT_CAST(player->pipeline->textbin[MMPLAYER_T_FAKE_SINK].gst);
11901 if (GST_IS_ELEMENT(text_sink)) {
11902 /* keep ref to the event */
11903 gst_event_ref(event2);
11905 if ((res = gst_element_send_event(text_sink, event2)))
11906 LOGD("sending event[%s] to subtitle sink element [%s] success!\n",
11907 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11909 LOGE("sending event[%s] to subtitle sink element [%s] failed!\n",
11910 GST_EVENT_TYPE_NAME(event2), GST_ELEMENT_NAME(text_sink));
11912 gst_event_unref(event2);
11916 gst_event_unref(event);
11924 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
11928 MMPLAYER_RETURN_IF_FAIL(player);
11929 MMPLAYER_RETURN_IF_FAIL(sink);
11931 player->sink_elements =
11932 g_list_append(player->sink_elements, sink);
11938 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
11942 MMPLAYER_RETURN_IF_FAIL(player);
11943 MMPLAYER_RETURN_IF_FAIL(sink);
11945 player->sink_elements =
11946 g_list_remove(player->sink_elements, sink);
11952 __gst_seek(mm_player_t* player, GstElement * element, gdouble rate,
11953 GstFormat format, GstSeekFlags flags, GstSeekType cur_type,
11954 gint64 cur, GstSeekType stop_type, gint64 stop)
11956 GstEvent* event = NULL;
11957 gboolean result = FALSE;
11961 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11963 if (player->pipeline && player->pipeline->textbin)
11964 __mmplayer_drop_subtitle(player, FALSE);
11966 event = gst_event_new_seek(rate, format, flags, cur_type,
11967 cur, stop_type, stop);
11969 result = __gst_send_event_to_sink(player, event);
11976 /* NOTE : be careful with calling this api. please refer to below glib comment
11977 * glib comment : Note that there is a bug in GObject that makes this function much
11978 * less useful than it might seem otherwise. Once gobject is disposed, the callback
11979 * will no longer be called, but, the signal handler is not currently disconnected.
11980 * If the instance is itself being freed at the same time than this doesn't matter,
11981 * since the signal will automatically be removed, but if instance persists,
11982 * then the signal handler will leak. You should not remove the signal yourself
11983 * because in a future versions of GObject, the handler will automatically be
11986 * It's possible to work around this problem in a way that will continue to work
11987 * with future versions of GObject by checking that the signal handler is still
11988 * connected before disconnected it:
11990 * if (g_signal_handler_is_connected(instance, id))
11991 * g_signal_handler_disconnect(instance, id);
11994 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
11996 GList* sig_list = NULL;
11997 MMPlayerSignalItem* item = NULL;
12001 MMPLAYER_RETURN_IF_FAIL(player);
12003 LOGD("release signals type : %d", type);
12005 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
12006 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
12007 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
12008 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
12009 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12010 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
12014 sig_list = player->signals[type];
12016 for (; sig_list; sig_list = sig_list->next) {
12017 item = sig_list->data;
12019 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
12020 if (g_signal_handler_is_connected(item->obj, item->sig))
12021 g_signal_handler_disconnect(item->obj, item->sig);
12024 MMPLAYER_FREEIF(item);
12027 g_list_free(player->signals[type]);
12028 player->signals[type] = NULL;
12035 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
12037 mm_player_t* player = 0;
12038 int prev_display_surface_type = 0;
12039 void *prev_display_overlay = NULL;
12040 const gchar *klass = NULL;
12041 gchar *cur_videosink_name = NULL;
12044 int num_of_dec = 2; /* DEC1, DEC2 */
12048 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
12049 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12051 player = MM_PLAYER_CAST(handle);
12053 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
12054 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
12056 return MM_ERROR_INVALID_ARGUMENT;
12059 /* load previous attributes */
12060 if (player->attrs) {
12061 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
12062 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
12063 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
12064 if (prev_display_surface_type == surface_type) {
12065 LOGD("incoming display surface type is same as previous one, do nothing..");
12067 return MM_ERROR_NONE;
12070 LOGE("failed to load attributes");
12072 return MM_ERROR_PLAYER_INTERNAL;
12075 /* check videosink element is created */
12076 if (!player->pipeline || !player->pipeline->videobin ||
12077 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12078 LOGD("videosink element is not yet ready");
12080 /* videobin is not created yet, so we just set attributes related to display surface */
12081 LOGD("store display attribute for given surface type(%d)", surface_type);
12082 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12083 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12084 if (mmf_attrs_commit(player->attrs)) {
12085 LOGE("failed to commit attribute");
12087 return MM_ERROR_PLAYER_INTERNAL;
12090 return MM_ERROR_NONE;
12092 /* get player command status */
12093 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
12094 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
12096 return MM_ERROR_PLAYER_INVALID_STATE;
12099 /* surface change */
12100 for (i = 0 ; i < num_of_dec ; i++) {
12101 if (player->pipeline->mainbin &&
12102 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
12103 GstElementFactory *decfactory;
12104 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
12106 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
12107 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
12108 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
12109 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
12113 LOGW("success to changing display surface(%d)", surface_type);
12115 return MM_ERROR_NONE;
12117 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
12118 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
12122 LOGW("success to changing display surface(%d)", surface_type);
12124 return MM_ERROR_NONE;
12127 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
12128 ret = MM_ERROR_PLAYER_INTERNAL;
12137 /* rollback to previous attributes */
12138 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
12139 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
12140 if (mmf_attrs_commit(player->attrs)) {
12141 LOGE("failed to commit attributes to rollback");
12143 return MM_ERROR_PLAYER_INTERNAL;
12149 /* NOTE : It does not support some use cases, eg using colorspace converter */
12151 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
12153 GstPad *src_pad_dec = NULL;
12154 GstPad *sink_pad_videosink = NULL;
12155 GstPad *sink_pad_videobin = NULL;
12156 GstClock *clock = NULL;
12157 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
12158 int ret = MM_ERROR_NONE;
12159 gboolean is_audiobin_created = TRUE;
12163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
12164 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
12165 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
12167 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
12168 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
12170 /* get information whether if audiobin is created */
12171 if (!player->pipeline->audiobin ||
12172 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
12173 LOGW("audiobin is null, this video content may not have audio data");
12174 is_audiobin_created = FALSE;
12177 /* get current state of player */
12178 previous_state = MMPLAYER_CURRENT_STATE(player);
12179 LOGD("previous state(%d)", previous_state);
12182 /* get src pad of decoder and block it */
12183 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
12184 if (!src_pad_dec) {
12185 LOGE("failed to get src pad from decode in mainbin");
12186 return MM_ERROR_PLAYER_INTERNAL;
12189 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12190 LOGW("trying to block pad(video)");
12191 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
12192 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
12195 LOGE("failed to set block pad(video)");
12196 return MM_ERROR_PLAYER_INTERNAL;
12198 LOGW("pad is blocked(video)");
12200 /* no data flows, so no need to do pad_block */
12201 if (player->doing_seek)
12202 LOGW("not completed seek(%d), do nothing", player->doing_seek);
12204 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
12208 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
12209 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
12210 LOGE("failed to remove previous ghost_pad for videobin");
12211 return MM_ERROR_PLAYER_INTERNAL;
12214 /* change state of videobin to NULL */
12215 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
12216 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
12217 if (ret != GST_STATE_CHANGE_SUCCESS) {
12218 LOGE("failed to change state of videobin to NULL");
12219 return MM_ERROR_PLAYER_INTERNAL;
12222 /* unlink between decoder and videobin and remove previous videosink from videobin */
12223 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
12224 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
12225 LOGE("failed to remove former videosink from videobin");
12226 return MM_ERROR_PLAYER_INTERNAL;
12229 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12231 /* create a new videosink and add it to videobin */
12232 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
12233 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
12234 LOGE("failed to create videosink element\n");
12236 return MM_ERROR_PLAYER_INTERNAL;
12238 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
12239 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12240 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
12242 /* save attributes */
12243 if (player->attrs) {
12244 /* set a new display surface type */
12245 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
12246 /* set a new diplay overlay */
12247 switch (surface_type) {
12248 case MM_DISPLAY_SURFACE_OVERLAY:
12249 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
12250 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
12253 LOGE("invalid type(%d) for changing display surface", surface_type);
12255 return MM_ERROR_INVALID_ARGUMENT;
12257 if (mmf_attrs_commit(player->attrs)) {
12258 LOGE("failed to commit");
12260 return MM_ERROR_PLAYER_INTERNAL;
12263 LOGE("player->attrs is null, failed to save attributes");
12265 return MM_ERROR_PLAYER_INTERNAL;
12268 /* update video param */
12269 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
12270 LOGE("failed to update video param");
12271 return MM_ERROR_PLAYER_INTERNAL;
12274 /* change state of videobin to READY */
12275 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
12276 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
12277 if (ret != GST_STATE_CHANGE_SUCCESS) {
12278 LOGE("failed to change state of videobin to READY");
12279 return MM_ERROR_PLAYER_INTERNAL;
12282 /* change ghostpad */
12283 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
12284 if (!sink_pad_videosink) {
12285 LOGE("failed to get sink pad from videosink element");
12286 return MM_ERROR_PLAYER_INTERNAL;
12288 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
12289 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
12290 LOGE("failed to set active to ghost_pad");
12291 return MM_ERROR_PLAYER_INTERNAL;
12293 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
12294 LOGE("failed to change ghostpad for videobin");
12295 return MM_ERROR_PLAYER_INTERNAL;
12297 gst_object_unref(sink_pad_videosink);
12299 /* link decoder with videobin */
12300 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
12301 if (!sink_pad_videobin) {
12302 LOGE("failed to get sink pad from videobin");
12303 return MM_ERROR_PLAYER_INTERNAL;
12305 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
12306 LOGE("failed to link");
12307 return MM_ERROR_PLAYER_INTERNAL;
12309 gst_object_unref(sink_pad_videobin);
12311 /* clock setting for a new videosink plugin */
12312 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
12313 so we set it from audiosink plugin or pipeline(system clock) */
12314 if (!is_audiobin_created) {
12315 LOGW("audiobin is not created, get clock from pipeline..");
12316 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12318 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
12322 GstClockTime base_time;
12323 LOGD("set the clock to videosink");
12324 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
12325 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
12327 LOGD("got clock of videosink");
12328 now = gst_clock_get_time(clock);
12329 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
12330 LOGD("at time %" GST_TIME_FORMAT ", base %"
12331 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
12333 LOGE("failed to get clock of videosink after setting clock");
12334 return MM_ERROR_PLAYER_INTERNAL;
12337 LOGW("failed to get clock, maybe it is the time before first playing");
12339 if (!player->doing_seek && previous_state == MM_PLAYER_STATE_PLAYING) {
12340 /* change state of videobin to PAUSED */
12341 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
12342 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
12343 if (ret != GST_STATE_CHANGE_FAILURE) {
12344 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
12346 LOGE("failed to change state of videobin to PLAYING");
12347 return MM_ERROR_PLAYER_INTERNAL;
12350 /* release blocked and unref src pad of video decoder */
12352 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
12353 LOGE("failed to set pad blocked FALSE(video)");
12354 return MM_ERROR_PLAYER_INTERNAL;
12357 LOGW("pad is unblocked(video)");
12359 if (player->doing_seek)
12360 LOGW("not completed seek(%d)", player->doing_seek);
12361 /* change state of videobin to PAUSED */
12362 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
12363 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
12364 if (ret != GST_STATE_CHANGE_FAILURE) {
12365 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
12367 LOGE("failed to change state of videobin to PLAYING");
12368 return MM_ERROR_PLAYER_INTERNAL;
12371 /* already skipped pad block */
12372 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
12375 /* do get/set position for new videosink plugin */
12377 gint64 position = 0;
12379 LOGD("do get/set position for new videosink plugin");
12380 if (__gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
12381 LOGE("failed to get position");
12382 return MM_ERROR_PLAYER_INTERNAL;
12384 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
12385 /* accurate seek */
12386 if (__gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
12387 LOGE("failed to set position");
12388 return MM_ERROR_PLAYER_INTERNAL;
12391 /* key unit seek */
12392 ret = __gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
12393 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
12394 GST_SEEK_TYPE_SET, position,
12395 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
12397 LOGE("failed to set position");
12398 return MM_ERROR_PLAYER_INTERNAL;
12404 gst_object_unref(src_pad_dec);
12405 LOGD("success to change sink");
12409 return MM_ERROR_NONE;
12413 /* Note : if silent is true, then subtitle would not be displayed. :*/
12414 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
12416 mm_player_t* player = (mm_player_t*) hplayer;
12420 /* check player handle */
12421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12423 player->set_mode.subtitle_off = silent;
12425 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
12429 return MM_ERROR_NONE;
12432 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
12434 MMPlayerGstElement* mainbin = NULL;
12435 MMPlayerGstElement* textbin = NULL;
12436 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12437 GstState current_state = GST_STATE_VOID_PENDING;
12438 GstState element_state = GST_STATE_VOID_PENDING;
12439 GstState element_pending_state = GST_STATE_VOID_PENDING;
12441 GstEvent *event = NULL;
12442 int result = MM_ERROR_NONE;
12444 GstClock *curr_clock = NULL;
12445 GstClockTime base_time, start_time, curr_time;
12450 /* check player handle */
12451 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12452 player->pipeline &&
12453 player->pipeline->mainbin &&
12454 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12456 mainbin = player->pipeline->mainbin;
12457 textbin = player->pipeline->textbin;
12459 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12461 // sync clock with current pipeline
12462 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
12463 curr_time = gst_clock_get_time(curr_clock);
12465 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12466 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
12468 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
12469 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
12471 if (current_state > GST_STATE_READY) {
12472 // sync state with current pipeline
12473 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
12474 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
12475 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
12477 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
12478 if (GST_STATE_CHANGE_FAILURE == ret) {
12479 LOGE("fail to state change.\n");
12480 result = MM_ERROR_PLAYER_INTERNAL;
12485 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
12486 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
12489 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
12490 gst_object_unref(curr_clock);
12493 // seek to current position
12494 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12495 result = MM_ERROR_PLAYER_INVALID_STATE;
12496 LOGE("gst_element_query_position failed, invalid state\n");
12500 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
12501 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);
12503 __gst_send_event_to_sink(player, event);
12505 result = MM_ERROR_PLAYER_INTERNAL;
12506 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
12510 /* sync state with current pipeline */
12511 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
12512 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
12513 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
12515 return MM_ERROR_NONE;
12518 /* release text pipeline resource */
12519 player->textsink_linked = 0;
12521 /* release signal */
12522 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
12524 /* release textbin with it's childs */
12525 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
12526 MMPLAYER_FREEIF(player->pipeline->textbin);
12527 player->pipeline->textbin = NULL;
12529 /* release subtitle elem */
12530 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
12531 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
12537 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
12539 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
12540 GstState current_state = GST_STATE_VOID_PENDING;
12542 MMHandleType attrs = 0;
12543 MMPlayerGstElement* mainbin = NULL;
12544 MMPlayerGstElement* textbin = NULL;
12546 gchar* subtitle_uri = NULL;
12547 int result = MM_ERROR_NONE;
12548 const gchar *charset = NULL;
12552 /* check player handle */
12553 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
12554 player->pipeline &&
12555 player->pipeline->mainbin &&
12556 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12557 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12559 mainbin = player->pipeline->mainbin;
12560 textbin = player->pipeline->textbin;
12562 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12563 if (current_state < GST_STATE_READY) {
12564 result = MM_ERROR_PLAYER_INVALID_STATE;
12565 LOGE("Pipeline is not in proper state\n");
12569 attrs = MMPLAYER_GET_ATTRS(player);
12571 LOGE("cannot get content attribute\n");
12572 result = MM_ERROR_PLAYER_INTERNAL;
12576 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
12577 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
12578 LOGE("subtitle uri is not proper filepath\n");
12579 result = MM_ERROR_PLAYER_INVALID_URI;
12583 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
12584 LOGE("failed to get storage info of subtitle path");
12585 result = MM_ERROR_PLAYER_INVALID_URI;
12589 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
12590 LOGD("new subtitle file path is [%s]\n", filepath);
12592 if (!strcmp(filepath, subtitle_uri)) {
12593 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
12596 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12597 if (mmf_attrs_commit(player->attrs)) {
12598 LOGE("failed to commit.\n");
12603 //gst_pad_set_blocked_async(src-srcpad, TRUE)
12604 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12605 player->subtitle_language_list = NULL;
12606 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12608 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
12609 if (ret != GST_STATE_CHANGE_SUCCESS) {
12610 LOGE("failed to change state of textbin to READY");
12611 result = MM_ERROR_PLAYER_INTERNAL;
12615 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
12616 if (ret != GST_STATE_CHANGE_SUCCESS) {
12617 LOGE("failed to change state of subparse to READY");
12618 result = MM_ERROR_PLAYER_INTERNAL;
12622 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
12623 if (ret != GST_STATE_CHANGE_SUCCESS) {
12624 LOGE("failed to change state of filesrc to READY");
12625 result = MM_ERROR_PLAYER_INTERNAL;
12629 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
12631 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
12633 charset = util_get_charset(filepath);
12635 LOGD("detected charset is %s\n", charset);
12636 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
12639 result = _mmplayer_sync_subtitle_pipeline(player);
12646 /* API to switch between external subtitles */
12647 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
12649 int result = MM_ERROR_NONE;
12650 mm_player_t* player = (mm_player_t*)hplayer;
12655 /* check player handle */
12656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12658 /* filepath can be null in idle state */
12660 /* check file path */
12661 if ((path = strstr(filepath, "file://")))
12662 result = util_exist_file_path(path + 7);
12664 result = util_exist_file_path(filepath);
12666 if (result != MM_ERROR_NONE) {
12667 LOGE("invalid subtitle path 0x%X", result);
12668 return result; /* file not found or permission denied */
12672 if (!player->pipeline) {
12674 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12675 if (mmf_attrs_commit(player->attrs)) {
12676 LOGE("failed to commit"); /* subtitle path will not be created */
12677 return MM_ERROR_PLAYER_INTERNAL;
12680 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
12681 /* check filepath */
12682 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
12684 if (!__mmplayer_check_subtitle(player)) {
12685 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
12686 if (mmf_attrs_commit(player->attrs)) {
12687 LOGE("failed to commit");
12688 return MM_ERROR_PLAYER_INTERNAL;
12691 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
12692 LOGE("fail to create text pipeline");
12693 return MM_ERROR_PLAYER_INTERNAL;
12696 result = _mmplayer_sync_subtitle_pipeline(player);
12698 result = __mmplayer_change_external_subtitle_language(player, filepath);
12701 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
12702 player->is_external_subtitle_added_now = TRUE;
12704 MMPLAYER_SUBTITLE_INFO_LOCK(player);
12705 if (!player->subtitle_language_list) {
12706 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
12707 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
12708 LOGW("subtitle language list is not updated yet");
12710 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
12718 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
12720 int result = MM_ERROR_NONE;
12721 gchar* change_pad_name = NULL;
12722 GstPad* sinkpad = NULL;
12723 MMPlayerGstElement* mainbin = NULL;
12724 enum MainElementID elemId = MMPLAYER_M_NUM;
12725 GstCaps* caps = NULL;
12726 gint total_track_num = 0;
12730 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
12731 MM_ERROR_PLAYER_NOT_INITIALIZED);
12733 LOGD("Change Track(%d) to %d\n", type, index);
12735 mainbin = player->pipeline->mainbin;
12737 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
12738 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
12739 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
12740 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
12742 /* Changing Video Track is not supported. */
12743 LOGE("Track Type Error\n");
12747 if (mainbin[elemId].gst == NULL) {
12748 result = MM_ERROR_PLAYER_NO_OP;
12749 LOGD("Req track doesn't exist\n");
12753 total_track_num = player->selector[type].total_track_num;
12754 if (total_track_num <= 0) {
12755 result = MM_ERROR_PLAYER_NO_OP;
12756 LOGD("Language list is not available \n");
12760 if ((index < 0) || (index >= total_track_num)) {
12761 result = MM_ERROR_INVALID_ARGUMENT;
12762 LOGD("Not a proper index : %d \n", index);
12766 /*To get the new pad from the selector*/
12767 change_pad_name = g_strdup_printf("sink_%u", index);
12768 if (change_pad_name == NULL) {
12769 result = MM_ERROR_PLAYER_INTERNAL;
12770 LOGD("Pad does not exists\n");
12774 LOGD("new active pad name: %s\n", change_pad_name);
12776 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
12777 if (sinkpad == NULL) {
12778 LOGD("sinkpad is NULL");
12779 result = MM_ERROR_PLAYER_INTERNAL;
12783 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
12784 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
12786 caps = gst_pad_get_current_caps(sinkpad);
12787 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
12790 gst_object_unref(sinkpad);
12792 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
12793 __mmplayer_set_audio_attrs(player, caps);
12797 MMPLAYER_FREEIF(change_pad_name);
12801 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
12803 int result = MM_ERROR_NONE;
12804 mm_player_t* player = NULL;
12805 MMPlayerGstElement* mainbin = NULL;
12807 gint current_active_index = 0;
12809 GstState current_state = GST_STATE_VOID_PENDING;
12810 GstEvent* event = NULL;
12815 player = (mm_player_t*)hplayer;
12816 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12818 if (!player->pipeline) {
12819 LOGE("Track %d pre setting -> %d\n", type, index);
12821 player->selector[type].active_pad_index = index;
12825 mainbin = player->pipeline->mainbin;
12827 current_active_index = player->selector[type].active_pad_index;
12829 /*If index is same as running index no need to change the pad*/
12830 if (current_active_index == index)
12833 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
12834 result = MM_ERROR_PLAYER_INVALID_STATE;
12838 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
12839 if (current_state < GST_STATE_PAUSED) {
12840 result = MM_ERROR_PLAYER_INVALID_STATE;
12841 LOGW("Pipeline not in porper state\n");
12845 result = __mmplayer_change_selector_pad(player, type, index);
12846 if (result != MM_ERROR_NONE) {
12847 LOGE("change selector pad error\n");
12851 player->selector[type].active_pad_index = index;
12853 if (current_state == GST_STATE_PLAYING) {
12854 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);
12856 __gst_send_event_to_sink(player, event);
12858 result = MM_ERROR_PLAYER_INTERNAL;
12867 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
12869 mm_player_t* player = (mm_player_t*) hplayer;
12873 /* check player handle */
12874 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12876 *silent = player->set_mode.subtitle_off;
12878 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
12882 return MM_ERROR_NONE;
12886 __is_ms_buff_src(mm_player_t* player)
12888 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12890 return (player->profile.uri_type == MM_PLAYER_URI_TYPE_MS_BUFF) ? TRUE : FALSE;
12894 __has_suffix(mm_player_t* player, const gchar* suffix)
12896 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
12897 MMPLAYER_RETURN_VAL_IF_FAIL(suffix, FALSE);
12899 gboolean ret = FALSE;
12900 gchar* t_url = g_ascii_strdown(player->profile.uri, -1);
12901 gchar* t_suffix = g_ascii_strdown(suffix, -1);
12903 if (g_str_has_suffix(player->profile.uri, suffix))
12906 MMPLAYER_FREEIF(t_url);
12907 MMPLAYER_FREEIF(t_suffix);
12913 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
12915 mm_player_t* player = (mm_player_t*) hplayer;
12917 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12919 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
12920 MMPLAYER_PRINT_STATE(player);
12921 LOGE("wrong-state : can't set the download mode to parse");
12922 return MM_ERROR_PLAYER_INVALID_STATE;
12925 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
12926 player->video_hub_download_mode = mode;
12928 return MM_ERROR_NONE;
12932 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
12934 mm_player_t* player = (mm_player_t*) hplayer;
12936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
12938 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
12939 player->sync_handler = enable;
12941 return MM_ERROR_NONE;
12945 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
12946 gint64 video_time, gint64 media_clock, gint64 audio_time)
12948 mm_player_t* player = (mm_player_t*) hplayer;
12949 MMPlayerGstElement* mainbin = NULL;
12950 GstClockTime start_time_audio = 0, start_time_video = 0;
12951 GstClockTimeDiff base_time = 0, new_base_time = 0;
12952 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
12953 gint64 api_delta = 0;
12954 gint64 position = 0, position_delta = 0;
12955 gint64 adj_base_time = 0;
12956 GstClock *curr_clock = NULL;
12957 GstClockTime curr_time = 0;
12958 gboolean query_ret = TRUE;
12959 int result = MM_ERROR_NONE;
12963 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
12964 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
12965 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
12967 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
12968 clock, clock_delta, video_time, media_clock, audio_time); */
12970 if ((video_time < 0) || (player->doing_seek)) {
12971 LOGD("skip setting master clock. %lld", video_time);
12975 mainbin = player->pipeline->mainbin;
12977 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
12978 curr_time = gst_clock_get_time(curr_clock);
12980 current_state = MMPLAYER_CURRENT_STATE(player);
12982 if (current_state == MM_PLAYER_STATE_PLAYING)
12983 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
12985 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
12987 position = player->last_position;
12988 LOGD("query fail. %"G_GINT64_FORMAT, position);
12991 clock *= GST_USECOND;
12992 clock_delta *= GST_USECOND;
12994 api_delta = clock - curr_time;
12995 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
12996 player->video_share_api_delta = api_delta;
12998 clock_delta += (api_delta - player->video_share_api_delta);
13000 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
13001 player->video_share_clock_delta = (gint64)clock_delta;
13003 position_delta = (position/GST_USECOND) - video_time;
13004 position_delta *= GST_USECOND;
13006 adj_base_time = position_delta;
13007 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
13010 gint64 new_play_time = 0;
13011 gint64 network_delay = 0;
13013 video_time *= GST_USECOND;
13015 network_delay = clock_delta - player->video_share_clock_delta;
13016 new_play_time = video_time + network_delay;
13018 adj_base_time = position - new_play_time;
13020 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
13021 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
13022 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
13025 /* Adjust Current Stream Time with base_time of sink
13026 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
13027 * 2. Set new base time
13028 * if adj_base_time is positive value, the stream time will be decreased.
13029 * 3. If seek event is occurred, the start time will be reset. */
13030 if ((player->pipeline->audiobin) &&
13031 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
13032 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13034 if (start_time_audio != GST_CLOCK_TIME_NONE) {
13035 LOGD("audio sink : gst_element_set_start_time -> NONE");
13036 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
13039 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
13042 if ((player->pipeline->videobin) &&
13043 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
13044 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13046 if (start_time_video != GST_CLOCK_TIME_NONE) {
13047 LOGD("video sink : gst_element_set_start_time -> NONE");
13048 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
13051 // if videobin exist, get base_time from videobin.
13052 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
13055 new_base_time = base_time + adj_base_time;
13057 if ((player->pipeline->audiobin) &&
13058 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
13059 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
13061 if ((player->pipeline->videobin) &&
13062 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
13063 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
13072 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
13074 mm_player_t* player = (mm_player_t*) hplayer;
13075 MMPlayerGstElement* mainbin = NULL;
13076 GstClock *curr_clock = NULL;
13077 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
13078 gint64 position = 0;
13079 gboolean query_ret = TRUE;
13083 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
13084 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
13085 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
13087 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13088 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
13089 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
13091 mainbin = player->pipeline->mainbin;
13093 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
13095 current_state = MMPLAYER_CURRENT_STATE(player);
13097 if (current_state != MM_PLAYER_STATE_PAUSED)
13098 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
13100 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
13102 position = player->last_position;
13104 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
13106 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
13109 gst_object_unref(curr_clock);
13113 return MM_ERROR_NONE;
13117 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
13119 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13120 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
13122 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
13123 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
13127 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
13128 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
13129 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
13130 mm_player_dump_t *dump_s;
13131 dump_s = g_malloc(sizeof(mm_player_dump_t));
13133 if (dump_s == NULL) {
13134 LOGE("malloc fail");
13138 dump_s->dump_element_file = NULL;
13139 dump_s->dump_pad = NULL;
13140 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
13142 if (dump_s->dump_pad) {
13143 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
13144 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]);
13145 dump_s->dump_element_file = fopen(dump_file_name, "w+");
13146 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);
13147 /* add list for removed buffer probe and close FILE */
13148 player->dump_list = g_list_append(player->dump_list, dump_s);
13149 LOGD("%s sink pad added buffer probe for dump", factory_name);
13154 LOGE("failed to get %s sink pad added", factory_name);
13163 static GstPadProbeReturn
13164 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
13166 FILE *dump_data = (FILE *) u_data;
13167 // int written = 0;
13168 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
13169 GstMapInfo probe_info = GST_MAP_INFO_INIT;
13171 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
13173 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
13175 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
13177 fwrite(probe_info.data, 1, probe_info.size , dump_data);
13179 return GST_PAD_PROBE_OK;
13183 __mmplayer_release_dump_list(GList *dump_list)
13186 GList *d_list = dump_list;
13187 for (; d_list; d_list = g_list_next(d_list)) {
13188 mm_player_dump_t *dump_s = d_list->data;
13189 if (dump_s->dump_pad) {
13190 if (dump_s->probe_handle_id)
13191 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
13193 if (dump_s->dump_element_file) {
13194 fclose(dump_s->dump_element_file);
13195 dump_s->dump_element_file = NULL;
13197 MMPLAYER_FREEIF(dump_s);
13199 g_list_free(dump_list);
13205 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
13207 mm_player_t* player = (mm_player_t*) hplayer;
13211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13212 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
13214 *exist = player->has_closed_caption;
13218 return MM_ERROR_NONE;
13221 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
13225 // LOGD("unref internal gst buffer %p", buffer);
13226 gst_buffer_unref((GstBuffer *)buffer);
13233 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
13235 mm_player_t *player = (mm_player_t*)user_data;
13236 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13237 guint64 current_level_bytes = 0;
13239 MMPLAYER_RETURN_IF_FAIL(player);
13241 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13243 LOGI("app-src: feed audio(%llu)\n", current_level_bytes);
13244 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13246 if (player->media_stream_buffer_status_cb[type])
13247 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13248 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13253 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
13255 mm_player_t *player = (mm_player_t*)user_data;
13256 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13257 guint64 current_level_bytes = 0;
13259 MMPLAYER_RETURN_IF_FAIL(player);
13261 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13263 LOGI("app-src: feed video(%llu)\n", current_level_bytes);
13265 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13266 if (player->media_stream_buffer_status_cb[type])
13267 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13268 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13272 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
13274 mm_player_t *player = (mm_player_t*)user_data;
13275 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13276 guint64 current_level_bytes = 0;
13278 MMPLAYER_RETURN_IF_FAIL(player);
13280 LOGI("app-src: feed subtitle\n");
13282 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13284 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13285 if (player->media_stream_buffer_status_cb[type])
13286 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
13288 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13292 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
13294 mm_player_t *player = (mm_player_t*)user_data;
13295 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13296 guint64 current_level_bytes = 0;
13298 MMPLAYER_RETURN_IF_FAIL(player);
13300 LOGI("app-src: audio buffer is full.\n");
13302 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13304 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13306 if (player->media_stream_buffer_status_cb[type])
13307 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13309 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13313 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
13315 mm_player_t *player = (mm_player_t*)user_data;
13316 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13317 guint64 current_level_bytes = 0;
13319 MMPLAYER_RETURN_IF_FAIL(player);
13321 LOGI("app-src: video buffer is full.\n");
13323 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
13325 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13326 if (player->media_stream_buffer_status_cb[type])
13327 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
13329 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13333 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
13335 mm_player_t *player = (mm_player_t*)user_data;
13336 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
13338 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13340 LOGD("app-src: seek audio data %llu\n", position);
13341 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13343 if (player->media_stream_seek_data_cb[type])
13344 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13345 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13351 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
13353 mm_player_t *player = (mm_player_t*)user_data;
13354 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
13356 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13358 LOGD("app-src: seek video data %llu\n", position);
13359 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13360 if (player->media_stream_seek_data_cb[type])
13361 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13362 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13368 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
13370 mm_player_t *player = (mm_player_t*)user_data;
13371 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
13373 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
13375 LOGD("app-src: seek subtitle data\n");
13376 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
13378 if (player->media_stream_seek_data_cb[type])
13379 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
13380 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
13386 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
13388 mm_player_t* player = (mm_player_t*) hplayer;
13392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13394 player->pcm_samplerate = samplerate;
13395 player->pcm_channel = channel;
13398 return MM_ERROR_NONE;
13401 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
13403 mm_player_t* player = (mm_player_t*) hplayer;
13407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13408 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
13410 if (MMPLAYER_IS_STREAMING(player))
13411 *timeout = player->ini.live_state_change_timeout;
13413 *timeout = player->ini.localplayback_state_change_timeout;
13415 LOGD("timeout = %d\n", *timeout);
13418 return MM_ERROR_NONE;
13421 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
13423 mm_player_t* player = (mm_player_t*) hplayer;
13427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13428 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
13430 *num = player->video_num_buffers;
13431 *extra_num = player->video_extra_num_buffers;
13433 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
13436 return MM_ERROR_NONE;
13440 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
13444 MMPLAYER_RETURN_IF_FAIL(player);
13446 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
13448 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
13449 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
13450 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
13451 player->storage_info[i].id = -1;
13452 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
13454 if (path_type != MMPLAYER_PATH_MAX)
13462 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
13464 int ret = MM_ERROR_NONE;
13465 mm_player_t* player = (mm_player_t*)hplayer;
13466 MMMessageParamType msg_param = {0, };
13469 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13471 LOGW("state changed storage %d:%d", id, state);
13473 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
13474 return MM_ERROR_NONE;
13476 /* FIXME: text path should be handled seperately. */
13477 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
13478 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
13479 LOGW("external storage is removed");
13481 if (player->msg_posted == FALSE) {
13482 memset(&msg_param, 0, sizeof(MMMessageParamType));
13483 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
13484 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
13485 player->msg_posted = TRUE;
13488 /* unrealize the player */
13489 ret = _mmplayer_unrealize(hplayer);
13490 if (ret != MM_ERROR_NONE)
13491 LOGE("failed to unrealize");
13498 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
13500 int ret = MM_ERROR_NONE;
13501 mm_player_t* player = (mm_player_t*) hplayer;
13502 int idx = 0, total = 0;
13503 gchar *result = NULL, *tmp = NULL;
13506 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13507 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
13509 total = *num = g_list_length(player->adaptive_info.var_list);
13511 LOGW("There is no stream variant info.");
13515 result = g_strdup("");
13516 for (idx = 0 ; idx < total ; idx++) {
13517 VariantData *v_data = NULL;
13518 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
13521 gchar data[64] = {0};
13522 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
13524 tmp = g_strconcat(result, data, NULL);
13528 LOGW("There is no variant data in %d", idx);
13533 *var_info = (char *)result;
13535 LOGD("variant info %d:%s", *num, *var_info);
13540 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
13542 int ret = MM_ERROR_NONE;
13543 mm_player_t* player = (mm_player_t*) hplayer;
13546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13548 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
13550 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13551 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13552 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
13554 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
13555 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
13556 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
13557 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
13559 /* FIXME: seek to current position for applying new variant limitation */
13567 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
13569 int ret = MM_ERROR_NONE;
13570 mm_player_t* player = (mm_player_t*) hplayer;
13573 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13574 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
13576 *bandwidth = player->adaptive_info.limit.bandwidth;
13577 *width = player->adaptive_info.limit.width;
13578 *height = player->adaptive_info.limit.height;
13580 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
13586 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
13588 int ret = MM_ERROR_NONE;
13589 mm_player_t* player = (mm_player_t*) hplayer;
13592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13594 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
13595 LOGW("buffer_ms will not be applied.");
13598 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
13600 if (player->streamer == NULL) {
13601 player->streamer = __mm_player_streaming_create();
13602 __mm_player_streaming_initialize(player->streamer);
13605 if (buffer_ms >= 0)
13606 player->streamer->buffering_req.prebuffer_time = buffer_ms;
13608 if (rebuffer_ms >= 0)
13609 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
13616 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
13618 int ret = MM_ERROR_NONE;
13619 mm_player_t* player = (mm_player_t*) hplayer;
13622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13623 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
13625 if (player->streamer == NULL) {
13626 player->streamer = __mm_player_streaming_create();
13627 __mm_player_streaming_initialize(player->streamer);
13630 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
13631 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
13633 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
13639 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
13641 #define IDX_FIRST_SW_CODEC 0
13642 mm_player_t* player = (mm_player_t*) hplayer;
13643 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
13644 MMHandleType attrs = 0;
13647 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13649 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
13650 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
13651 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
13653 switch (stream_type) {
13654 case MM_PLAYER_STREAM_TYPE_AUDIO:
13655 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13656 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
13657 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13658 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13659 LOGE("There is no a codec for codec_type %d", codec_type);
13660 return MM_ERROR_PLAYER_NO_OP;
13663 case MM_PLAYER_STREAM_TYPE_VIDEO:
13664 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
13665 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
13666 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
13667 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
13668 LOGE("There is no v codec for codec_type %d", codec_type);
13669 return MM_ERROR_PLAYER_NO_OP;
13674 LOGE("Invalid stream type %d", stream_type);
13675 return MM_ERROR_COMMON_INVALID_ARGUMENT;
13679 LOGD("update %s codec_type to %d", attr_name, codec_type);
13681 attrs = MMPLAYER_GET_ATTRS(player);
13682 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
13684 if (mmf_attrs_commit(player->attrs)) {
13685 LOGE("failed to commit codec_type attributes");
13686 return MM_ERROR_PLAYER_INTERNAL;
13690 return MM_ERROR_NONE;
13694 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
13696 mm_player_t* player = (mm_player_t*) hplayer;
13697 GstElement* rg_vol_element = NULL;
13701 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13703 player->sound.rg_enable = enabled;
13705 /* just hold rgvolume enable value if pipeline is not ready */
13706 if (!player->pipeline || !player->pipeline->audiobin) {
13707 LOGD("pipeline is not ready. holding rgvolume enable value\n");
13708 return MM_ERROR_NONE;
13711 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13713 if (!rg_vol_element) {
13714 LOGD("rgvolume element is not created");
13715 return MM_ERROR_PLAYER_INTERNAL;
13719 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
13721 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
13725 return MM_ERROR_NONE;
13729 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
13731 mm_player_t* player = (mm_player_t*) hplayer;
13732 GstElement* rg_vol_element = NULL;
13733 gboolean enable = FALSE;
13737 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
13738 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
13740 /* just hold enable_rg value if pipeline is not ready */
13741 if (!player->pipeline || !player->pipeline->audiobin) {
13742 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
13743 *enabled = player->sound.rg_enable;
13744 return MM_ERROR_NONE;
13747 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
13749 if (!rg_vol_element) {
13750 LOGD("rgvolume element is not created");
13751 return MM_ERROR_PLAYER_INTERNAL;
13754 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
13759 return MM_ERROR_NONE;