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/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
41 #include <mm_attrs_private.h>
43 #include "mm_player_priv.h"
44 #include "mm_player_ini.h"
45 #include "mm_player_attrs.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
91 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
93 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
94 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
95 (player->ini.http_use_file_buffer) && \
96 (player->http_file_buffering_path) && \
97 (strlen(player->http_file_buffering_path) > 0))
99 #define PLAYER_DISPLAY_MODE_DST_ROI 5
101 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
104 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
105 #define PLAYER_PD_STATE_CHANGE_TIME 20 /* sec */
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 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
117 /*---------------------------------------------------------------------------
118 | LOCAL CONSTANT DEFINITIONS: |
119 ---------------------------------------------------------------------------*/
121 /*---------------------------------------------------------------------------
122 | LOCAL DATA TYPE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
140 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
141 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
142 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
144 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, 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 void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
156 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mm_player_t* player);
158 static void __mmplayer_release_misc_post(mm_player_t* player);
159 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
160 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
161 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
163 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
164 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
166 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
167 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
168 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
169 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
170 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
171 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
172 static gpointer __mmplayer_next_play_thread(gpointer data);
173 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
174 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
175 static void __mmplayer_release_dump_list(GList *dump_list);
176 static int __mmplayer_gst_realize(mm_player_t* player);
177 static int __mmplayer_gst_unrealize(mm_player_t* player);
178 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
179 static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
180 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
183 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
184 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
185 static int __mmplayer_start_streaming_ext(mm_player_t *player);
186 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
187 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
188 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
189 static void __mmplayer_check_pipeline(mm_player_t* player);
190 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
191 static void __mmplayer_deactivate_old_path(mm_player_t *player);
192 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
193 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
194 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
195 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
196 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
197 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
198 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
208 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
212 count = gst_tag_list_get_tag_size(list, tag);
214 LOGD("count = %d", count);
216 for (i = 0; i < count; i++) {
219 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
220 if (!gst_tag_list_get_string_index(list, tag, i, &str))
221 g_assert_not_reached();
223 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
226 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
228 g_print(" : %s\n", str);
235 /* This function should be called after the pipeline goes PAUSED or higher
238 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
240 static gboolean has_duration = FALSE;
241 static gboolean has_video_attrs = FALSE;
242 static gboolean has_audio_attrs = FALSE;
243 static gboolean has_bitrate = FALSE;
244 gboolean missing_only = FALSE;
245 gboolean all = FALSE;
247 GstStructure* p = NULL;
248 MMHandleType attrs = 0;
254 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
256 /* check player state here */
257 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
258 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
259 /* give warning now only */
260 LOGW("be careful. content attributes may not available in this state ");
263 /* get content attribute first */
264 attrs = MMPLAYER_GET_ATTRS(player);
266 LOGE("cannot get content attribute");
270 /* get update flag */
272 if (flag & ATTR_MISSING_ONLY) {
274 LOGD("updating missed attr only");
277 if (flag & ATTR_ALL) {
279 has_duration = FALSE;
280 has_video_attrs = FALSE;
281 has_audio_attrs = FALSE;
284 LOGD("updating all attrs");
287 if (missing_only && all) {
288 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
289 missing_only = FALSE;
292 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
293 LOGD("try to update duration");
294 has_duration = FALSE;
296 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
297 player->duration = dur_nsec;
298 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
302 if (player->duration < 0) {
303 LOGW("duration is Non-Initialized !!!");
304 player->duration = 0;
307 /* update streaming service type */
308 player->streaming_type = __mmplayer_get_stream_service_type(player);
310 /* check duration is OK */
311 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
312 /* FIXIT : find another way to get duration here. */
313 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
317 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
318 /* update audio params
319 NOTE : We need original audio params and it can be only obtained from src pad of audio
320 decoder. Below code only valid when we are not using 'resampler' just before
323 LOGD("try to update audio attrs");
324 has_audio_attrs = FALSE;
326 if (player->pipeline->audiobin &&
327 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
328 GstCaps *caps_a = NULL;
330 gint samplerate = 0, channels = 0;
332 pad = gst_element_get_static_pad(
333 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
336 caps_a = gst_pad_get_current_caps(pad);
339 p = gst_caps_get_structure(caps_a, 0);
341 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
343 gst_structure_get_int(p, "rate", &samplerate);
344 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
346 gst_structure_get_int(p, "channels", &channels);
347 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
349 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
351 gst_caps_unref(caps_a);
354 has_audio_attrs = TRUE;
356 LOGW("not ready to get audio caps");
358 gst_object_unref(pad);
360 LOGW("failed to get pad from audiosink");
364 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
365 LOGD("try to update video attrs");
366 has_video_attrs = FALSE;
368 if (player->pipeline->videobin &&
369 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
370 GstCaps *caps_v = NULL;
375 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
377 caps_v = gst_pad_get_current_caps(pad);
379 /* Use v_stream_caps, if fail to get video_sink sink pad*/
380 if (!caps_v && player->v_stream_caps) {
381 caps_v = player->v_stream_caps;
382 gst_caps_ref(caps_v);
386 p = gst_caps_get_structure(caps_v, 0);
387 gst_structure_get_int(p, "width", &width);
388 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
390 gst_structure_get_int(p, "height", &height);
391 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
393 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
395 SECURE_LOGD("width : %d height : %d", width, height);
397 gst_caps_unref(caps_v);
401 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
402 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
405 has_video_attrs = TRUE;
407 LOGD("no negitiated caps from videosink");
408 gst_object_unref(pad);
411 LOGD("no videosink sink pad");
417 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
420 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
421 if (player->duration) {
422 guint64 data_size = 0;
424 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
425 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
427 if (stat(path, &sb) == 0)
428 data_size = (guint64)sb.st_size;
429 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
430 data_size = player->http_content_size;
432 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
436 guint64 msec_dur = 0;
438 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
440 bitrate = data_size * 8 * 1000 / msec_dur;
441 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
442 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
446 LOGD("player duration is less than 0");
450 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
451 if (player->total_bitrate) {
452 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
460 if (mmf_attrs_commit(attrs)) {
461 LOGE("failed to update attributes\n");
470 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
472 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
476 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
478 player->pipeline->mainbin &&
479 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
480 STREAMING_SERVICE_NONE);
482 /* streaming service type if streaming */
483 if (!MMPLAYER_IS_STREAMING(player))
484 return STREAMING_SERVICE_NONE;
486 streaming_type = (player->duration == 0) ?
487 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
489 switch (streaming_type) {
490 case STREAMING_SERVICE_LIVE:
491 LOGD("it's live streaming");
493 case STREAMING_SERVICE_VOD:
494 LOGD("it's vod streaming");
497 LOGE("should not get here");
503 return streaming_type;
507 /* this function sets the player state and also report
508 * it to applicaton by calling callback function
511 __mmplayer_set_state(mm_player_t* player, int state)
513 MMMessageParamType msg = {0, };
514 gboolean post_bos = FALSE;
516 MMPLAYER_RETURN_IF_FAIL(player);
518 if (MMPLAYER_CURRENT_STATE(player) == state) {
519 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
520 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
524 /* update player states */
525 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
526 MMPLAYER_CURRENT_STATE(player) = state;
528 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
529 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
532 MMPLAYER_PRINT_STATE(player);
534 switch (MMPLAYER_CURRENT_STATE(player)) {
535 case MM_PLAYER_STATE_NULL:
536 case MM_PLAYER_STATE_READY:
539 case MM_PLAYER_STATE_PAUSED:
541 if (!player->sent_bos) {
542 /* rtsp case, get content attrs by GstMessage */
543 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
544 /* it's first time to update all content attrs. */
545 __mmplayer_update_content_attrs(player, ATTR_ALL);
549 /* add audio callback probe if condition is satisfied */
550 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
551 __mmplayer_configure_audio_callback(player);
553 /* FIXIT : handle return value */
557 case MM_PLAYER_STATE_PLAYING:
559 /* try to get content metadata */
560 if (!player->sent_bos) {
561 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
562 * c-api since c-api doesn't use _start() anymore. It may not work propery with
563 * legacy mmfw-player api */
564 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
567 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
568 if (!player->sent_bos)
569 __mmplayer_handle_missed_plugin(player);
572 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
573 /* initialize because auto resume is done well. */
574 player->resumed_by_rewind = FALSE;
575 player->playback_rate = 1.0;
578 if (!player->sent_bos) {
579 /* check audio codec field is set or not
580 * we can get it from typefinder or codec's caps.
582 gchar *audio_codec = NULL;
583 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
585 /* The codec format can't be sent for audio only case like amr, mid etc.
586 * Because, parser don't make related TAG.
587 * So, if it's not set yet, fill it with found data.
590 if (g_strrstr(player->type, "audio/midi"))
591 audio_codec = g_strdup("MIDI");
592 else if (g_strrstr(player->type, "audio/x-amr"))
593 audio_codec = g_strdup("AMR");
594 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
595 audio_codec = g_strdup("AAC");
597 audio_codec = g_strdup("unknown");
598 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
600 MMPLAYER_FREEIF(audio_codec);
601 if (mmf_attrs_commit(player->attrs))
602 LOGE("failed to update attributes\n");
604 LOGD("set audio codec type with caps\n");
612 case MM_PLAYER_STATE_NONE:
614 LOGW("invalid target state, there is nothing to do.\n");
619 /* post message to application */
620 if (MMPLAYER_TARGET_STATE(player) == state) {
621 /* fill the message with state of player */
622 msg.union_type = MM_MSG_UNION_STATE;
623 msg.state.previous = MMPLAYER_PREV_STATE(player);
624 msg.state.current = MMPLAYER_CURRENT_STATE(player);
626 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
628 /* state changed by resource callback */
629 if (player->interrupted_by_resource) {
630 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
631 } else { /* state changed by usecase */
632 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
635 LOGD("intermediate state, do nothing.\n");
636 MMPLAYER_PRINT_STATE(player);
641 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
642 player->sent_bos = TRUE;
649 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
651 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
652 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
654 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
656 //LOGD("incomming command : %d \n", command);
658 current_state = MMPLAYER_CURRENT_STATE(player);
659 pending_state = MMPLAYER_PENDING_STATE(player);
661 MMPLAYER_PRINT_STATE(player);
664 case MMPLAYER_COMMAND_CREATE:
666 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
668 if (current_state == MM_PLAYER_STATE_NULL ||
669 current_state == MM_PLAYER_STATE_READY ||
670 current_state == MM_PLAYER_STATE_PAUSED ||
671 current_state == MM_PLAYER_STATE_PLAYING)
676 case MMPLAYER_COMMAND_DESTROY:
678 /* destroy can called anytime */
680 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
684 case MMPLAYER_COMMAND_REALIZE:
686 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
688 if (pending_state != MM_PLAYER_STATE_NONE) {
691 /* need ready state to realize */
692 if (current_state == MM_PLAYER_STATE_READY)
695 if (current_state != MM_PLAYER_STATE_NULL)
701 case MMPLAYER_COMMAND_UNREALIZE:
703 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
705 if (current_state == MM_PLAYER_STATE_NULL)
710 case MMPLAYER_COMMAND_START:
712 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
714 if (pending_state == MM_PLAYER_STATE_NONE) {
715 if (current_state == MM_PLAYER_STATE_PLAYING)
717 else if (current_state != MM_PLAYER_STATE_READY &&
718 current_state != MM_PLAYER_STATE_PAUSED)
720 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
722 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
723 LOGD("player is going to paused state, just change the pending state as playing");
729 case MMPLAYER_COMMAND_STOP:
731 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
733 if (current_state == MM_PLAYER_STATE_READY)
736 /* need playing/paused state to stop */
737 if (current_state != MM_PLAYER_STATE_PLAYING &&
738 current_state != MM_PLAYER_STATE_PAUSED)
743 case MMPLAYER_COMMAND_PAUSE:
745 if (MMPLAYER_IS_LIVE_STREAMING(player))
748 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
749 goto NOT_COMPLETED_SEEK;
751 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
753 if (pending_state == MM_PLAYER_STATE_NONE) {
754 if (current_state == MM_PLAYER_STATE_PAUSED)
756 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
758 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
760 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
761 if (current_state == MM_PLAYER_STATE_PAUSED)
762 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
769 case MMPLAYER_COMMAND_RESUME:
771 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
772 goto NOT_COMPLETED_SEEK;
774 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
776 if (pending_state == MM_PLAYER_STATE_NONE) {
777 if (current_state == MM_PLAYER_STATE_PLAYING)
779 else if (current_state != MM_PLAYER_STATE_PAUSED)
781 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
783 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
784 LOGD("player is going to paused state, just change the pending state as playing");
793 player->cmd = command;
795 return MM_ERROR_NONE;
798 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
799 MMPLAYER_STATE_GET_NAME(current_state), command);
800 return MM_ERROR_PLAYER_INVALID_STATE;
803 LOGW("not completed seek");
804 return MM_ERROR_PLAYER_DOING_SEEK;
807 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
808 return MM_ERROR_PLAYER_NO_OP;
811 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
812 return MM_ERROR_PLAYER_NO_OP;
815 static gpointer __mmplayer_next_play_thread(gpointer data)
817 mm_player_t* player = (mm_player_t*) data;
818 MMPlayerGstElement *mainbin = NULL;
820 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
822 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
823 while (!player->next_play_thread_exit) {
824 LOGD("next play thread started. waiting for signal.\n");
825 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
827 LOGD("reconfigure pipeline for gapless play.\n");
829 if (player->next_play_thread_exit) {
830 if (player->gapless.reconfigure) {
831 player->gapless.reconfigure = false;
832 MMPLAYER_PLAYBACK_UNLOCK(player);
834 LOGD("exiting gapless play thread\n");
838 mainbin = player->pipeline->mainbin;
840 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
841 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
842 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
843 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
844 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
846 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
848 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
854 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
856 GSource *source = NULL;
860 source = g_main_context_find_source_by_id(context, source_id);
862 if (source != NULL) {
863 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
864 g_source_destroy(source);
870 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
872 mm_player_t* player = (mm_player_t*)hplayer;
873 GstMessage *msg = NULL;
874 GQueue *queue = NULL;
877 MMPLAYER_RETURN_IF_FAIL(player);
879 /* disconnecting bus watch */
880 if (player->bus_watcher)
881 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
882 player->bus_watcher = 0;
884 /* destroy the gst bus msg thread */
885 if (player->bus_msg_thread) {
886 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
887 player->bus_msg_thread_exit = TRUE;
888 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
889 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
891 LOGD("gst bus msg thread exit.");
892 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
893 player->bus_msg_thread = NULL;
895 g_mutex_clear(&player->bus_msg_thread_mutex);
896 g_cond_clear(&player->bus_msg_thread_cond);
899 g_mutex_lock(&player->bus_msg_q_lock);
900 queue = player->bus_msg_q;
901 while (!g_queue_is_empty(queue)) {
902 msg = (GstMessage *)g_queue_pop_head(queue);
907 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
908 gst_message_unref(msg);
910 g_mutex_unlock(&player->bus_msg_q_lock);
916 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
918 GstElement* parent = NULL;
920 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
922 /* if we have no fakesink. this meas we are using decodebin which doesn'
923 t need to add extra fakesink */
924 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
927 MMPLAYER_FSINK_LOCK(player);
932 /* get parent of fakesink */
933 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
935 LOGD("fakesink already removed\n");
939 gst_element_set_locked_state(fakesink->gst, TRUE);
941 /* setting the state to NULL never returns async
942 * so no need to wait for completion of state transiton
944 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
945 LOGE("fakesink state change failure!\n");
946 /* FIXIT : should I return here? or try to proceed to next? */
949 /* remove fakesink from it's parent */
950 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
951 LOGE("failed to remove fakesink\n");
953 gst_object_unref(parent);
958 gst_object_unref(parent);
960 LOGD("state-holder removed\n");
962 gst_element_set_locked_state(fakesink->gst, FALSE);
964 MMPLAYER_FSINK_UNLOCK(player);
969 gst_element_set_locked_state(fakesink->gst, FALSE);
971 MMPLAYER_FSINK_UNLOCK(player);
975 static GstPadProbeReturn
976 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
978 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
979 return GST_PAD_PROBE_OK;
983 __mmplayer_gst_selector_update_start_time(mm_player_t* player, MMPlayerTrackType stream_type)
985 gint64 stop_running_time = 0;
986 gint64 position_running_time = 0;
990 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
991 if ((player->gapless.update_segment[idx] == TRUE) ||
992 !(player->selector[idx].event_probe_id)) {
993 /* LOGW("[%d] skip", idx); */
997 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
999 gst_segment_to_running_time(&player->gapless.segment[idx],
1000 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
1001 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
1003 gst_segment_to_running_time(&player->gapless.segment[idx],
1004 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
1006 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
1008 gst_segment_to_running_time(&player->gapless.segment[idx],
1009 GST_FORMAT_TIME, player->duration);
1012 position_running_time =
1013 gst_segment_to_running_time(&player->gapless.segment[idx],
1014 GST_FORMAT_TIME, player->gapless.segment[idx].position);
1016 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
1017 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
1019 GST_TIME_ARGS(stop_running_time),
1020 GST_TIME_ARGS(position_running_time),
1021 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
1022 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
1024 position_running_time = MAX(position_running_time, stop_running_time);
1025 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
1026 GST_FORMAT_TIME, player->gapless.segment[idx].start);
1027 position_running_time = MAX(0, position_running_time);
1028 position = MAX(position, position_running_time);
1031 if (position != 0) {
1032 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1033 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
1034 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
1036 player->gapless.start_time[stream_type] += position;
1042 static GstPadProbeReturn
1043 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
1045 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1046 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
1047 mm_player_t* player = (mm_player_t*)data;
1048 GstCaps* caps = NULL;
1049 GstStructure* str = NULL;
1050 const gchar* name = NULL;
1051 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1053 if (GST_EVENT_IS_DOWNSTREAM(event) &&
1054 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1055 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1056 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1057 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
1059 } else if (GST_EVENT_IS_UPSTREAM(event) &&
1060 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
1064 caps = gst_pad_query_caps(pad, NULL);
1066 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
1070 str = gst_caps_get_structure(caps, 0);
1072 LOGE("failed to get structure from caps");
1076 name = gst_structure_get_name(str);
1078 LOGE("failed to get name from str");
1082 if (strstr(name, "audio")) {
1083 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1084 } else if (strstr(name, "video")) {
1085 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1087 /* text track is not supportable */
1088 LOGE("invalid name %s", name);
1092 switch (GST_EVENT_TYPE(event)) {
1095 /* in case of gapless, drop eos event not to send it to sink */
1096 if (player->gapless.reconfigure && !player->msg_posted) {
1097 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1098 ret = GST_PAD_PROBE_DROP;
1102 case GST_EVENT_STREAM_START:
1104 __mmplayer_gst_selector_update_start_time(player, stream_type);
1107 case GST_EVENT_FLUSH_STOP:
1109 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1110 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1111 player->gapless.start_time[stream_type] = 0;
1114 case GST_EVENT_SEGMENT:
1119 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1120 gst_event_copy_segment(event, &segment);
1122 if (segment.format != GST_FORMAT_TIME)
1125 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1126 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1127 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1128 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1129 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1130 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1132 /* keep the all the segment ev to cover the seeking */
1133 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1134 player->gapless.update_segment[stream_type] = TRUE;
1136 if (!player->gapless.running)
1139 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1141 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1143 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1144 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1145 gst_event_unref(event);
1146 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1152 gdouble proportion = 0.0;
1153 GstClockTimeDiff diff = 0;
1154 GstClockTime timestamp = 0;
1155 gint64 running_time_diff = -1;
1156 GstQOSType type = 0;
1157 GstEvent *tmpev = NULL;
1159 running_time_diff = player->gapless.segment[stream_type].base;
1161 if (running_time_diff <= 0) /* don't need to adjust */
1164 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1165 gst_event_unref(event);
1167 if (timestamp < running_time_diff) {
1168 LOGW("QOS event from previous group");
1169 ret = GST_PAD_PROBE_DROP;
1173 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1174 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1175 stream_type, GST_TIME_ARGS(timestamp),
1176 GST_TIME_ARGS(running_time_diff),
1177 GST_TIME_ARGS(timestamp - running_time_diff));
1179 timestamp -= running_time_diff;
1181 /* That case is invalid for QoS events */
1182 if (diff < 0 && -diff > timestamp) {
1183 LOGW("QOS event from previous group");
1184 ret = GST_PAD_PROBE_DROP;
1188 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1189 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1199 gst_caps_unref(caps);
1204 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1206 mm_player_t* player = NULL;
1207 GstElement* pipeline = NULL;
1208 GstElement* selector = NULL;
1209 GstElement* fakesink = NULL;
1210 GstCaps* caps = NULL;
1211 GstStructure* str = NULL;
1212 const gchar* name = NULL;
1213 GstPad* sinkpad = NULL;
1214 GstPad* srcpad = NULL;
1215 gboolean first_track = FALSE;
1217 enum MainElementID elemId = MMPLAYER_M_NUM;
1218 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1221 player = (mm_player_t*)data;
1223 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1224 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1226 //LOGD("pad-added signal handling\n");
1228 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1230 /* get mimetype from caps */
1231 caps = gst_pad_query_caps(pad, NULL);
1233 LOGE("cannot get caps from pad.\n");
1237 str = gst_caps_get_structure(caps, 0);
1239 LOGE("cannot get structure from caps.\n");
1243 name = gst_structure_get_name(str);
1245 LOGE("cannot get mimetype from structure.\n");
1249 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1250 //LOGD("detected mimetype : %s\n", name);
1252 if (strstr(name, "video")) {
1255 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1256 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1258 /* don't make video because of not required, and not support multiple track */
1259 if (stype == MM_DISPLAY_SURFACE_NULL) {
1260 LOGD("no video sink by null surface");
1262 gchar *caps_str = gst_caps_to_string(caps);
1263 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1264 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1265 player->set_mode.video_zc = TRUE;
1267 MMPLAYER_FREEIF(caps_str);
1269 if (player->v_stream_caps) {
1270 gst_caps_unref(player->v_stream_caps);
1271 player->v_stream_caps = NULL;
1274 LOGD("create fakesink instead of videobin");
1277 fakesink = gst_element_factory_make("fakesink", NULL);
1278 if (fakesink == NULL) {
1279 LOGE("ERROR : fakesink create error\n");
1283 if (player->ini.set_dump_element_flag)
1284 __mmplayer_add_dump_buffer_probe(player, fakesink);
1286 player->video_fakesink = fakesink;
1288 /* store it as it's sink element */
1289 __mmplayer_add_sink(player, player->video_fakesink);
1291 gst_bin_add(GST_BIN(pipeline), fakesink);
1294 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1296 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1297 LOGW("failed to link fakesink\n");
1298 gst_object_unref(GST_OBJECT(fakesink));
1302 if (player->set_mode.media_packet_video_stream) {
1303 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
1305 __mmplayer_add_signal_connection(player,
1307 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1309 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
1312 __mmplayer_add_signal_connection(player,
1314 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1316 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
1320 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
1321 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1325 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1326 __mmplayer_gst_decode_callback(elem, pad, player);
1330 LOGD("video selector \n");
1331 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
1332 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1334 if (strstr(name, "audio")) {
1335 gint samplerate = 0;
1338 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1339 __mmplayer_gst_decode_callback(elem, pad, player);
1343 LOGD("audio selector \n");
1344 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
1345 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1347 gst_structure_get_int(str, "rate", &samplerate);
1348 gst_structure_get_int(str, "channels", &channels);
1350 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
1352 fakesink = gst_element_factory_make("fakesink", NULL);
1353 if (fakesink == NULL) {
1354 LOGE("ERROR : fakesink create error\n");
1358 gst_bin_add(GST_BIN(pipeline), fakesink);
1361 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1363 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1364 LOGW("failed to link fakesink\n");
1365 gst_object_unref(GST_OBJECT(fakesink));
1369 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1370 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1374 } else if (strstr(name, "text")) {
1375 LOGD("text selector \n");
1376 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
1377 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1379 LOGE("wrong elem id \n");
1384 selector = player->pipeline->mainbin[elemId].gst;
1385 if (selector == NULL) {
1386 selector = gst_element_factory_make("input-selector", NULL);
1387 LOGD("Creating input-selector\n");
1388 if (selector == NULL) {
1389 LOGE("ERROR : input-selector create error\n");
1392 g_object_set(selector, "sync-streams", TRUE, NULL);
1394 player->pipeline->mainbin[elemId].id = elemId;
1395 player->pipeline->mainbin[elemId].gst = selector;
1398 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
1400 srcpad = gst_element_get_static_pad(selector, "src");
1402 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1403 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1404 __mmplayer_gst_selector_blocked, NULL, NULL);
1405 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1406 __mmplayer_gst_selector_event_probe, player, NULL);
1408 gst_element_set_state(selector, GST_STATE_PAUSED);
1409 gst_bin_add(GST_BIN(pipeline), selector);
1411 LOGD("input-selector is already created.\n");
1414 LOGD("Calling request pad with selector %p \n", selector);
1415 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1417 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
1419 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1420 LOGW("failed to link selector\n");
1421 gst_object_unref(GST_OBJECT(selector));
1426 LOGD("this is first track --> active track \n");
1427 g_object_set(selector, "active-pad", sinkpad, NULL);
1430 __mmplayer_track_update_info(player, stream_type, sinkpad);
1437 gst_caps_unref(caps);
1440 gst_object_unref(GST_OBJECT(sinkpad));
1445 gst_object_unref(GST_OBJECT(srcpad));
1452 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
1454 GstPad* srcpad = NULL;
1455 MMHandleType attrs = 0;
1456 gint active_index = 0;
1458 // [link] input-selector :: textbin
1459 srcpad = gst_element_get_static_pad(text_selector, "src");
1461 LOGE("failed to get srcpad from selector\n");
1465 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
1467 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
1468 if ((active_index != DEFAULT_TRACK) &&
1469 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
1470 LOGW("failed to change text track\n");
1471 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
1474 player->no_more_pad = TRUE;
1475 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
1477 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1478 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
1479 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
1480 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
1483 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1485 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1486 player->has_closed_caption = TRUE;
1488 attrs = MMPLAYER_GET_ATTRS(player);
1490 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1491 if (mmf_attrs_commit(attrs))
1492 LOGE("failed to commit.\n");
1494 LOGE("cannot get content attribute");
1497 gst_object_unref(GST_OBJECT(srcpad));
1503 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1505 mm_player_t* player = (mm_player_t*)data;
1506 GstElement* selector = NULL;
1507 GstElement* queue = NULL;
1509 GstPad* srcpad = NULL;
1510 GstPad* sinkpad = NULL;
1511 GstCaps* caps = NULL;
1512 gchar* caps_str = NULL;
1515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1517 caps = gst_pad_get_current_caps(pad);
1518 caps_str = gst_caps_to_string(caps);
1519 LOGD("deinterleave new caps : %s\n", caps_str);
1520 MMPLAYER_FREEIF(caps_str);
1521 gst_caps_unref(caps);
1523 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
1524 LOGE("ERROR : queue create error\n");
1528 g_object_set(G_OBJECT(queue),
1529 "max-size-buffers", 10,
1530 "max-size-bytes", 0,
1531 "max-size-time", (guint64)0,
1534 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1537 LOGE("there is no audio channel selector.\n");
1541 srcpad = gst_element_get_static_pad(queue, "src");
1542 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1544 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
1546 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1547 LOGW("failed to link deinterleave - selector\n");
1551 gst_element_set_state(queue, GST_STATE_PAUSED);
1552 player->audio_mode.total_track_num++;
1557 gst_object_unref(GST_OBJECT(srcpad));
1562 gst_object_unref(GST_OBJECT(sinkpad));
1571 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
1573 mm_player_t* player = NULL;
1574 GstElement* selector = NULL;
1575 GstPad* sinkpad = NULL;
1576 gint active_index = 0;
1577 gchar* change_pad_name = NULL;
1578 GstCaps* caps = NULL; // no need to unref
1579 gint default_audio_ch = 0;
1582 player = (mm_player_t*) data;
1584 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1587 LOGE("there is no audio channel selector.\n");
1591 active_index = player->audio_mode.active_pad_index;
1593 if (active_index != default_audio_ch) {
1594 gint audio_ch = default_audio_ch;
1596 /*To get the new pad from the selector*/
1597 change_pad_name = g_strdup_printf("sink%d", active_index);
1598 if (change_pad_name != NULL) {
1599 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
1600 if (sinkpad != NULL) {
1601 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
1602 g_object_set(selector, "active-pad", sinkpad, NULL);
1604 audio_ch = active_index;
1606 caps = gst_pad_get_current_caps(sinkpad);
1607 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1609 __mmplayer_set_audio_attrs(player, caps);
1610 gst_caps_unref(caps);
1612 MMPLAYER_FREEIF(change_pad_name);
1615 player->audio_mode.active_pad_index = audio_ch;
1616 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
1622 gst_object_unref(sinkpad);
1629 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
1631 mm_player_t* player = NULL;
1632 MMPlayerGstElement *mainbin = NULL;
1634 GstElement* tee = NULL;
1635 GstElement* stereo_queue = NULL;
1636 GstElement* mono_queue = NULL;
1637 GstElement* conv = NULL;
1638 GstElement* filter = NULL;
1639 GstElement* deinterleave = NULL;
1640 GstElement* selector = NULL;
1642 GstPad* srcpad = NULL;
1643 GstPad* selector_srcpad = NULL;
1644 GstPad* sinkpad = NULL;
1645 GstCaps* caps = NULL;
1646 gulong block_id = 0;
1651 player = (mm_player_t*) data;
1653 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1654 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1656 mainbin = player->pipeline->mainbin;
1659 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
1660 LOGE("ERROR : tee create error\n");
1664 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
1665 mainbin[MMPLAYER_M_A_TEE].gst = tee;
1667 gst_element_set_state(tee, GST_STATE_PAUSED);
1670 srcpad = gst_element_get_request_pad(tee, "src_%u");
1671 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1672 LOGE("ERROR : stereo queue create error\n");
1676 g_object_set(G_OBJECT(stereo_queue),
1677 "max-size-buffers", 10,
1678 "max-size-bytes", 0,
1679 "max-size-time", (guint64)0,
1682 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
1683 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
1686 gst_object_unref(GST_OBJECT(srcpad));
1690 srcpad = gst_element_get_request_pad(tee, "src_%u");
1692 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1693 LOGE("ERROR : mono queue create error\n");
1697 g_object_set(G_OBJECT(mono_queue),
1698 "max-size-buffers", 10,
1699 "max-size-bytes", 0,
1700 "max-size-time", (guint64)0,
1703 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
1704 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
1706 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
1707 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
1710 srcpad = gst_element_get_static_pad(mono_queue, "src");
1711 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
1712 LOGE("ERROR : audioconvert create error\n");
1716 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
1717 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
1721 gst_object_unref(GST_OBJECT(srcpad));
1724 srcpad = gst_element_get_static_pad(conv, "src");
1726 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
1727 LOGE("ERROR : capsfilter create error\n");
1731 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
1732 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
1734 caps = gst_caps_from_string("audio/x-raw-int, "
1735 "width = (int) 16, "
1736 "depth = (int) 16, "
1737 "channels = (int) 2");
1739 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
1740 gst_caps_unref(caps);
1742 gst_element_set_state(conv, GST_STATE_PAUSED);
1743 gst_element_set_state(filter, GST_STATE_PAUSED);
1747 gst_object_unref(GST_OBJECT(srcpad));
1750 srcpad = gst_element_get_static_pad(filter, "src");
1752 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
1753 LOGE("ERROR : deinterleave create error\n");
1757 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
1759 __mmplayer_add_signal_connection(player, G_OBJECT(deinterleave), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
1760 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), (gpointer)player);
1762 __mmplayer_add_signal_connection(player, G_OBJECT(deinterleave), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
1763 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), (gpointer)player);
1765 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
1766 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
1769 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
1770 if (selector == NULL) {
1771 LOGE("ERROR : audio-selector create error\n");
1775 g_object_set(selector, "sync-streams", TRUE, NULL);
1776 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
1778 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
1779 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
1781 selector_srcpad = gst_element_get_static_pad(selector, "src");
1783 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
1785 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1786 __mmplayer_gst_selector_blocked, NULL, NULL);
1789 gst_object_unref(GST_OBJECT(srcpad));
1793 srcpad = gst_element_get_static_pad(stereo_queue, "src");
1794 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1796 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1797 LOGW("failed to link queue_stereo - selector\n");
1801 player->audio_mode.total_track_num++;
1803 g_object_set(selector, "active-pad", sinkpad, NULL);
1804 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
1805 gst_element_set_state(selector, GST_STATE_PAUSED);
1807 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
1811 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
1812 if (block_id != 0) {
1813 gst_pad_remove_probe(selector_srcpad, block_id);
1818 gst_object_unref(GST_OBJECT(sinkpad));
1823 gst_object_unref(GST_OBJECT(srcpad));
1827 if (selector_srcpad) {
1828 gst_object_unref(GST_OBJECT(selector_srcpad));
1829 selector_srcpad = NULL;
1837 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1839 mm_player_t* player = NULL;
1840 GstPad* srcpad = NULL;
1841 GstElement* video_selector = NULL;
1842 GstElement* audio_selector = NULL;
1843 GstElement* text_selector = NULL;
1844 MMHandleType attrs = 0;
1845 gint active_index = 0;
1846 gint64 dur_bytes = 0L;
1848 player = (mm_player_t*) data;
1850 LOGD("no-more-pad signal handling\n");
1852 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1853 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1854 LOGW("no need to go more");
1856 if (player->gapless.reconfigure) {
1857 player->gapless.reconfigure = FALSE;
1858 MMPLAYER_PLAYBACK_UNLOCK(player);
1864 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
1865 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
1866 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1867 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1868 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1870 if (NULL == player->streamer) {
1871 LOGW("invalid state for buffering");
1875 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1876 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1878 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1879 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
1881 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1883 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1884 LOGE("fail to get duration.\n");
1886 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1887 * use file information was already set on Q2 when it was created. */
1888 __mm_player_streaming_set_queue2(player->streamer,
1889 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1890 TRUE, /* use_buffering */
1892 init_buffering_time,
1893 1.0, /* low percent */
1894 player->ini.http_buffering_limit, /* high percent */
1895 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1897 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1900 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1901 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1902 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1903 if (video_selector) {
1904 // [link] input-selector :: videobin
1905 srcpad = gst_element_get_static_pad(video_selector, "src");
1907 LOGE("failed to get srcpad from video selector\n");
1911 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
1912 if (!text_selector && !audio_selector)
1913 player->no_more_pad = TRUE;
1915 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
1917 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1918 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
1919 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
1920 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
1924 if (audio_selector) {
1925 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
1926 if ((active_index != DEFAULT_TRACK) &&
1927 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
1928 LOGW("failed to change audio track\n");
1929 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
1932 // [link] input-selector :: audiobin
1933 srcpad = gst_element_get_static_pad(audio_selector, "src");
1935 LOGE("failed to get srcpad from selector\n");
1939 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
1941 player->no_more_pad = TRUE;
1943 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
1944 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1945 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
1946 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
1947 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
1950 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
1952 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
1954 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1955 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
1956 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
1957 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
1961 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
1963 attrs = MMPLAYER_GET_ATTRS(player);
1965 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
1966 if (mmf_attrs_commit(attrs))
1967 LOGE("failed to commit.\n");
1969 LOGE("cannot get content attribute");
1971 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1972 LOGD("There is no audio track : remove audiobin");
1974 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1975 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1977 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1978 MMPLAYER_FREEIF(player->pipeline->audiobin);
1981 if (player->num_dynamic_pad == 0)
1982 __mmplayer_pipeline_complete(NULL, player);
1985 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
1987 __mmplayer_handle_text_decode_path(player, text_selector);
1994 gst_object_unref(GST_OBJECT(srcpad));
1998 if (player->gapless.reconfigure) {
1999 player->gapless.reconfigure = FALSE;
2000 MMPLAYER_PLAYBACK_UNLOCK(player);
2005 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
2007 mm_player_t* player = NULL;
2008 MMHandleType attrs = 0;
2009 GstElement* pipeline = NULL;
2010 GstCaps* caps = NULL;
2011 gchar* caps_str = NULL;
2012 GstStructure* str = NULL;
2013 const gchar* name = NULL;
2014 GstPad* sinkpad = NULL;
2015 GstElement* sinkbin = NULL;
2016 gboolean reusing = FALSE;
2017 GstElement *text_selector = NULL;
2020 player = (mm_player_t*) data;
2022 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2023 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2025 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2027 attrs = MMPLAYER_GET_ATTRS(player);
2029 LOGE("cannot get content attribute\n");
2033 /* get mimetype from caps */
2034 caps = gst_pad_query_caps(pad, NULL);
2036 LOGE("cannot get caps from pad.\n");
2039 caps_str = gst_caps_to_string(caps);
2041 str = gst_caps_get_structure(caps, 0);
2043 LOGE("cannot get structure from caps.\n");
2047 name = gst_structure_get_name(str);
2049 LOGE("cannot get mimetype from structure.\n");
2053 //LOGD("detected mimetype : %s\n", name);
2055 if (strstr(name, "audio")) {
2056 if (player->pipeline->audiobin == NULL) {
2057 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
2058 LOGE("failed to create audiobin. continuing without audio\n");
2062 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2063 LOGD("creating audiosink bin success\n");
2066 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2067 LOGD("reusing audiobin\n");
2068 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2071 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
2072 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2074 player->audiosink_linked = 1;
2076 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2078 LOGE("failed to get pad from sinkbin\n");
2081 } else if (strstr(name, "video")) {
2082 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2083 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2084 player->set_mode.video_zc = TRUE;
2086 if (player->pipeline->videobin == NULL) {
2087 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
2088 /* get video surface type */
2089 int surface_type = 0;
2090 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2091 LOGD("display_surface_type(%d)\n", surface_type);
2093 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
2094 LOGD("not make videobin because it dose not want\n");
2098 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
2099 /* mark video overlay for acquire */
2100 if (player->video_overlay_resource == NULL) {
2101 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
2102 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2103 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2104 &player->video_overlay_resource)
2105 != MM_RESOURCE_MANAGER_ERROR_NONE) {
2106 LOGE("could not mark video_overlay resource for acquire\n");
2112 player->interrupted_by_resource = FALSE;
2113 /* acquire resources for video overlay */
2114 if (mm_resource_manager_commit(player->resource_manager) !=
2115 MM_RESOURCE_MANAGER_ERROR_NONE) {
2116 LOGE("could not acquire resources for video playing\n");
2120 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
2121 LOGE("failed to create videobin. continuing without video\n");
2125 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2126 LOGD("creating videosink bin success\n");
2129 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2130 LOGD("re-using videobin\n");
2131 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2134 player->videosink_linked = 1;
2136 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2138 LOGE("failed to get pad from sinkbin\n");
2141 } else if (strstr(name, "text")) {
2142 if (player->pipeline->textbin == NULL) {
2143 MMPlayerGstElement* mainbin = NULL;
2145 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
2146 LOGE("failed to create text sink bin. continuing without text\n");
2150 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2151 LOGD("creating textsink bin success\n");
2153 /* FIXIT : track number shouldn't be hardcoded */
2154 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2156 player->textsink_linked = 1;
2157 LOGI("player->textsink_linked set to 1\n");
2159 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
2161 LOGE("failed to get pad from sinkbin\n");
2165 mainbin = player->pipeline->mainbin;
2167 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
2168 /* input selector */
2169 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
2170 if (!text_selector) {
2171 LOGE("failed to create subtitle input selector element\n");
2174 g_object_set(text_selector, "sync-streams", TRUE, NULL);
2176 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
2177 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
2180 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
2181 LOGE("failed to set state(READY) to sinkbin\n");
2185 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
2186 LOGW("failed to add subtitle input selector\n");
2190 LOGD("created element input-selector");
2193 LOGD("already having subtitle input selector");
2194 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
2197 if (!player->textsink_linked) {
2198 LOGD("re-using textbin\n");
2201 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2203 player->textsink_linked = 1;
2204 LOGI("player->textsink_linked set to 1\n");
2206 LOGD("ignoring internal subtutle since external subtitle is available");
2209 LOGW("unknown type of elementary stream!ignoring it...\n");
2216 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
2217 LOGE("failed to set state(READY) to sinkbin\n");
2221 /* Added for multi audio support to avoid adding audio bin again*/
2223 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
2224 LOGE("failed to add sinkbin to pipeline\n");
2230 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2231 LOGE("failed to get pad from sinkbin\n");
2237 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
2238 LOGE("failed to set state(PAUSED) to sinkbin\n");
2242 if (text_selector) {
2243 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
2244 LOGE("failed to set state(PAUSED) to sinkbin\n");
2250 gst_object_unref(sinkpad);
2254 LOGD("[handle: %p] linking sink bin success", player);
2256 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2257 * streaming task. if the task blocked, then buffer will not flow to the next element
2258 *(autoplugging element). so this is special hack for streaming. please try to remove it
2260 /* dec stream count. we can remove fakesink if it's zero */
2261 if (player->num_dynamic_pad)
2262 player->num_dynamic_pad--;
2264 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
2266 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
2267 __mmplayer_pipeline_complete(NULL, player);
2271 MMPLAYER_FREEIF(caps_str);
2274 gst_caps_unref(caps);
2277 gst_object_unref(GST_OBJECT(sinkpad));
2279 /* flusing out new attributes */
2280 if (mmf_attrs_commit(attrs))
2281 LOGE("failed to comit attributes\n");
2287 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
2289 int required_angle = 0; /* Angle required for straight view */
2290 int rotation_angle = 0;
2292 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2293 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
2295 /* Counter clockwise */
2296 switch (orientation) {
2301 required_angle = 270;
2304 required_angle = 180;
2307 required_angle = 90;
2311 rotation_angle = display_angle + required_angle;
2312 if (rotation_angle >= 360)
2313 rotation_angle -= 360;
2315 /* chech if supported or not */
2316 if (rotation_angle % 90) {
2317 LOGD("not supported rotation angle = %d", rotation_angle);
2321 switch (rotation_angle) {
2323 *value = MM_DISPLAY_ROTATION_NONE;
2326 *value = MM_DISPLAY_ROTATION_90;
2329 *value = MM_DISPLAY_ROTATION_180;
2332 *value = MM_DISPLAY_ROTATION_270;
2336 LOGD("setting rotation property value : %d", value);
2342 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
2344 /* check video sinkbin is created */
2345 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2347 player->pipeline->videobin &&
2348 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2349 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2350 MM_ERROR_PLAYER_NOT_INITIALIZED);
2352 return MM_ERROR_NONE;
2356 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
2358 int display_rotation = 0;
2359 gchar *org_orient = NULL;
2360 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
2363 LOGE("cannot get content attribute");
2364 return MM_ERROR_PLAYER_INTERNAL;
2367 if (display_angle) {
2368 /* update user roation */
2369 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
2371 /* Counter clockwise */
2372 switch (display_rotation) {
2373 case MM_DISPLAY_ROTATION_NONE:
2376 case MM_DISPLAY_ROTATION_90:
2377 *display_angle = 90;
2379 case MM_DISPLAY_ROTATION_180:
2380 *display_angle = 180;
2382 case MM_DISPLAY_ROTATION_270:
2383 *display_angle = 270;
2386 LOGW("wrong angle type : %d", display_rotation);
2389 LOGD("check user angle: %d", *display_angle);
2393 /* Counter clockwise */
2394 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2397 if (!strcmp(org_orient, "rotate-90"))
2399 else if (!strcmp(org_orient, "rotate-180"))
2401 else if (!strcmp(org_orient, "rotate-270"))
2404 LOGD("original rotation is %s", org_orient);
2406 LOGD("content_video_orientation get fail");
2409 LOGD("check orientation: %d", *orientation);
2412 return MM_ERROR_NONE;
2416 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
2418 int rotation_value = 0;
2419 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2420 int display_angle = 0;
2423 /* check video sinkbin is created */
2424 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2427 __mmplayer_get_video_angle(player, &display_angle, &orientations);
2429 /* get rotation value to set */
2430 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2431 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2432 LOGD("set video param : rotate %d", rotation_value);
2436 __mmplayer_video_param_set_display_visible(mm_player_t* player)
2438 MMHandleType attrs = 0;
2442 /* check video sinkbin is created */
2443 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2446 attrs = MMPLAYER_GET_ATTRS(player);
2447 MMPLAYER_RETURN_IF_FAIL(attrs);
2449 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2450 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2451 LOGD("set video param : visible %d", visible);
2455 __mmplayer_video_param_set_display_method(mm_player_t* player)
2457 MMHandleType attrs = 0;
2458 int display_method = 0;
2461 /* check video sinkbin is created */
2462 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2465 attrs = MMPLAYER_GET_ATTRS(player);
2466 MMPLAYER_RETURN_IF_FAIL(attrs);
2468 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2469 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2470 LOGD("set video param : method %d", display_method);
2473 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
2475 MMHandleType attrs = 0;
2476 void *handle = NULL;
2479 /* check video sinkbin is created */
2480 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
2481 LOGW("There is no video sink");
2485 attrs = MMPLAYER_GET_ATTRS(player);
2486 MMPLAYER_RETURN_IF_FAIL(attrs);
2487 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2489 gst_video_overlay_set_video_roi_area(
2490 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2491 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2492 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2493 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2498 __mmplayer_video_param_set_roi_area(mm_player_t* player)
2500 MMHandleType attrs = 0;
2501 void *handle = NULL;
2505 int win_roi_width = 0;
2506 int win_roi_height = 0;
2509 /* check video sinkbin is created */
2510 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
2511 LOGW("There is no video sink");
2515 attrs = MMPLAYER_GET_ATTRS(player);
2516 MMPLAYER_RETURN_IF_FAIL(attrs);
2518 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2521 /* It should be set after setting window */
2522 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2523 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2524 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2525 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2527 /* After setting window handle, set display roi area */
2528 gst_video_overlay_set_display_roi_area(
2529 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2530 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2531 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2532 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2536 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
2538 MMHandleType attrs = 0;
2539 void *handle = NULL;
2541 /* check video sinkbin is created */
2542 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2545 attrs = MMPLAYER_GET_ATTRS(player);
2546 MMPLAYER_RETURN_IF_FAIL(attrs);
2548 /* common case if using overlay surface */
2549 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2552 /* default is using wl_surface_id */
2553 unsigned int wl_surface_id = 0;
2554 wl_surface_id = *(int*)handle;
2555 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
2556 gst_video_overlay_set_wl_window_wl_surface_id(
2557 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2560 /* FIXIT : is it error case? */
2561 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2566 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
2568 bool update_all_param = FALSE;
2571 /* check video sinkbin is created */
2572 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2573 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2575 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2576 LOGE("can not find tizenwlsink");
2577 return MM_ERROR_PLAYER_INTERNAL;
2580 LOGD("param_name : %s", param_name);
2581 if (!g_strcmp0(param_name, "update_all_param"))
2582 update_all_param = TRUE;
2584 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2585 __mmplayer_video_param_set_display_overlay(player);
2586 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2587 __mmplayer_video_param_set_display_method(player);
2588 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2589 __mmplayer_video_param_set_display_visible(player);
2590 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2591 __mmplayer_video_param_set_display_rotation(player);
2592 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2593 __mmplayer_video_param_set_roi_area(player);
2594 if (update_all_param)
2595 __mmplayer_video_param_set_video_roi_area(player);
2597 return MM_ERROR_NONE;
2601 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2603 MMHandleType attrs = 0;
2604 int surface_type = 0;
2605 int ret = MM_ERROR_NONE;
2609 /* check video sinkbin is created */
2610 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2611 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2613 attrs = MMPLAYER_GET_ATTRS(player);
2615 LOGE("cannot get content attribute");
2616 return MM_ERROR_PLAYER_INTERNAL;
2618 LOGD("param_name : %s", param_name);
2620 /* update display surface */
2621 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2622 LOGD("check display surface type attribute: %d", surface_type);
2624 /* configuring display */
2625 switch (surface_type) {
2626 case MM_DISPLAY_SURFACE_OVERLAY:
2628 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2629 if (ret != MM_ERROR_NONE)
2637 return MM_ERROR_NONE;
2641 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2643 gboolean disable_overlay = FALSE;
2644 mm_player_t* player = (mm_player_t*) hplayer;
2645 int ret = MM_ERROR_NONE;
2648 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2649 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2650 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2651 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2653 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2654 LOGW("Display control is not supported");
2655 return MM_ERROR_PLAYER_INTERNAL;
2658 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2660 if (audio_only == (bool)disable_overlay) {
2661 LOGE("It's the same with current setting: (%d)", audio_only);
2662 return MM_ERROR_NONE;
2666 LOGE("disable overlay");
2667 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2669 /* release overlay resource */
2670 if (player->video_overlay_resource != NULL) {
2671 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2672 player->video_overlay_resource);
2673 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2674 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2677 player->video_overlay_resource = NULL;
2680 ret = mm_resource_manager_commit(player->resource_manager);
2681 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2682 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2686 /* mark video overlay for acquire */
2687 if (player->video_overlay_resource == NULL) {
2688 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2689 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2690 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2691 &player->video_overlay_resource);
2692 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2693 LOGE("could not prepare for video_overlay resource\n");
2698 player->interrupted_by_resource = FALSE;
2699 /* acquire resources for video overlay */
2700 ret = mm_resource_manager_commit(player->resource_manager);
2701 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2702 LOGE("could not acquire resources for video playing\n");
2706 LOGD("enable overlay");
2707 __mmplayer_video_param_set_display_overlay(player);
2708 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2713 return MM_ERROR_NONE;
2717 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2719 mm_player_t* player = (mm_player_t*) hplayer;
2720 gboolean disable_overlay = FALSE;
2724 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2725 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2726 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2727 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2728 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2730 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2731 LOGW("Display control is not supported");
2732 return MM_ERROR_PLAYER_INTERNAL;
2735 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2737 *paudio_only = (bool)(disable_overlay);
2739 LOGD("audio_only : %d", *paudio_only);
2743 return MM_ERROR_NONE;
2747 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2749 GList* bucket = element_bucket;
2750 MMPlayerGstElement* element = NULL;
2751 MMPlayerGstElement* prv_element = NULL;
2752 gint successful_link_count = 0;
2756 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2758 prv_element = (MMPlayerGstElement*)bucket->data;
2759 bucket = bucket->next;
2761 for (; bucket; bucket = bucket->next) {
2762 element = (MMPlayerGstElement*)bucket->data;
2764 if (element && element->gst) {
2765 if (prv_element && prv_element->gst) {
2766 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2767 LOGD("linking [%s] to [%s] success\n",
2768 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2769 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2770 successful_link_count++;
2772 LOGD("linking [%s] to [%s] failed\n",
2773 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2774 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2780 prv_element = element;
2785 return successful_link_count;
2789 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2791 GList* bucket = element_bucket;
2792 MMPlayerGstElement* element = NULL;
2793 int successful_add_count = 0;
2797 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2798 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2800 for (; bucket; bucket = bucket->next) {
2801 element = (MMPlayerGstElement*)bucket->data;
2803 if (element && element->gst) {
2804 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2805 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2806 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2807 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2810 successful_add_count++;
2816 return successful_add_count;
2819 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
2821 mm_player_t* player = (mm_player_t*) data;
2822 GstCaps *caps = NULL;
2823 GstStructure *str = NULL;
2828 MMPLAYER_RETURN_IF_FAIL(pad)
2829 MMPLAYER_RETURN_IF_FAIL(unused)
2830 MMPLAYER_RETURN_IF_FAIL(data)
2832 caps = gst_pad_get_current_caps(pad);
2836 str = gst_caps_get_structure(caps, 0);
2840 name = gst_structure_get_name(str);
2844 LOGD("name = %s\n", name);
2846 if (strstr(name, "audio")) {
2847 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2849 if (player->audio_stream_changed_cb) {
2850 LOGE("call the audio stream changed cb\n");
2851 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2853 } else if (strstr(name, "video")) {
2854 if ((name = gst_structure_get_string(str, "format")))
2855 player->set_mode.video_zc = name[0] == 'S';
2857 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2859 if (player->video_stream_changed_cb) {
2860 LOGE("call the video stream changed cb\n");
2861 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2868 gst_caps_unref(caps);
2878 * This function is to create audio pipeline for playing.
2880 * @param player [in] handle of player
2882 * @return This function returns zero on success.
2884 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2886 /* macro for code readability. just for sinkbin-creation functions */
2887 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2889 x_bin[x_id].id = x_id;\
2890 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2891 if (!x_bin[x_id].gst) {\
2892 LOGE("failed to create %s \n", x_factory);\
2895 if (x_player->ini.set_dump_element_flag)\
2896 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2899 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2903 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2908 MMPLAYER_RETURN_IF_FAIL(player);
2910 if (player->audio_stream_buff_list) {
2911 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2912 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2915 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2916 __mmplayer_audio_stream_send_data(player, tmp);
2919 g_free(tmp->pcm_data);
2923 g_list_free(player->audio_stream_buff_list);
2924 player->audio_stream_buff_list = NULL;
2931 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2933 MMPlayerAudioStreamDataType audio_stream = { 0, };
2936 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
2938 audio_stream.bitrate = a_buffer->bitrate;
2939 audio_stream.channel = a_buffer->channel;
2940 audio_stream.depth = a_buffer->depth;
2941 audio_stream.is_little_endian = a_buffer->is_little_endian;
2942 audio_stream.channel_mask = a_buffer->channel_mask;
2943 audio_stream.data_size = a_buffer->data_size;
2944 audio_stream.data = a_buffer->pcm_data;
2946 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2947 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
2953 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2955 mm_player_t* player = (mm_player_t*) data;
2960 gint endianness = 0;
2961 guint64 channel_mask = 0;
2962 void *a_data = NULL;
2964 mm_player_audio_stream_buff_t *a_buffer = NULL;
2965 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2969 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
2971 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2972 a_data = mapinfo.data;
2973 a_size = mapinfo.size;
2975 GstCaps *caps = gst_pad_get_current_caps(pad);
2976 GstStructure *structure = gst_caps_get_structure(caps, 0);
2978 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2979 gst_structure_get_int(structure, "rate", &rate);
2980 gst_structure_get_int(structure, "channels", &channel);
2981 gst_structure_get_int(structure, "depth", &depth);
2982 gst_structure_get_int(structure, "endianness", &endianness);
2983 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2984 gst_caps_unref(GST_CAPS(caps));
2986 /* In case of the sync is false, use buffer list. *
2987 * The num of buffer list depends on the num of audio channels */
2988 if (player->audio_stream_buff_list) {
2989 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2990 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2992 if (channel_mask == tmp->channel_mask) {
2993 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2994 if (tmp->data_size + a_size < tmp->buff_size) {
2995 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2996 tmp->data_size += a_size;
2998 /* send data to client */
2999 __mmplayer_audio_stream_send_data(player, tmp);
3001 if (a_size > tmp->buff_size) {
3002 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
3003 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
3004 if (tmp->pcm_data == NULL) {
3005 LOGE("failed to realloc data.");
3008 tmp->buff_size = a_size;
3010 memset(tmp->pcm_data, 0x00, tmp->buff_size);
3011 memcpy(tmp->pcm_data, a_data, a_size);
3012 tmp->data_size = a_size;
3017 LOGE("data is empty in list.");
3023 /* create new audio stream data */
3024 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
3025 if (a_buffer == NULL) {
3026 LOGE("failed to alloc data.");
3029 a_buffer->bitrate = rate;
3030 a_buffer->channel = channel;
3031 a_buffer->depth = depth;
3032 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
3033 a_buffer->channel_mask = channel_mask;
3034 a_buffer->data_size = a_size;
3036 if (!player->audio_stream_sink_sync) {
3037 /* If sync is FALSE, use buffer list to reduce the IPC. */
3038 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
3039 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
3040 if (a_buffer->pcm_data == NULL) {
3041 LOGE("failed to alloc data.");
3045 memcpy(a_buffer->pcm_data, a_data, a_size);
3046 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
3047 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
3049 /* If sync is TRUE, send data directly. */
3050 a_buffer->pcm_data = a_data;
3051 __mmplayer_audio_stream_send_data(player, a_buffer);
3056 gst_buffer_unmap(buffer, &mapinfo);
3061 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3063 mm_player_t* player = (mm_player_t*)data;
3064 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
3065 GstPad* sinkpad = NULL;
3066 GstElement *queue = NULL, *sink = NULL;
3069 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3071 queue = gst_element_factory_make("queue", NULL);
3072 if (queue == NULL) {
3073 LOGD("fail make queue\n");
3077 sink = gst_element_factory_make("fakesink", NULL);
3079 LOGD("fail make fakesink\n");
3083 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
3085 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
3086 LOGW("failed to link queue & sink\n");
3090 sinkpad = gst_element_get_static_pad(queue, "sink");
3092 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3093 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
3097 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
3099 gst_object_unref(sinkpad);
3100 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
3101 g_object_set(sink, "signal-handoffs", TRUE, NULL);
3103 gst_element_set_state(sink, GST_STATE_PAUSED);
3104 gst_element_set_state(queue, GST_STATE_PAUSED);
3106 __mmplayer_add_signal_connection(player,
3108 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3110 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3117 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
3119 gst_object_unref(GST_OBJECT(queue));
3123 gst_object_unref(GST_OBJECT(sink));
3127 gst_object_unref(GST_OBJECT(sinkpad));
3134 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
3136 #define MAX_PROPS_LEN 128
3137 gint latency_mode = 0;
3138 gchar *stream_type = NULL;
3139 gchar *latency = NULL;
3141 gchar stream_props[MAX_PROPS_LEN] = {0,};
3142 GstStructure *props = NULL;
3145 * It should be set after player creation through attribute.
3146 * But, it can not be changed during playing.
3149 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
3150 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
3153 LOGE("stream_type is null.\n");
3155 if (player->sound.focus_id)
3156 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
3157 stream_type, stream_id, player->sound.focus_id);
3159 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
3160 stream_type, stream_id);
3161 props = gst_structure_from_string(stream_props, NULL);
3162 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
3163 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
3164 stream_type, stream_id, player->sound.focus_id, stream_props);
3165 gst_structure_free(props);
3168 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
3170 switch (latency_mode) {
3171 case AUDIO_LATENCY_MODE_LOW:
3172 latency = g_strndup("low", 3);
3174 case AUDIO_LATENCY_MODE_MID:
3175 latency = g_strndup("mid", 3);
3177 case AUDIO_LATENCY_MODE_HIGH:
3178 latency = g_strndup("high", 4);
3182 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
3186 LOGD("audiosink property - latency=%s \n", latency);
3194 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
3196 MMPlayerGstElement* first_element = NULL;
3197 MMPlayerGstElement* audiobin = NULL;
3198 MMHandleType attrs = 0;
3200 GstPad *ghostpad = NULL;
3201 GList* element_bucket = NULL;
3202 gboolean link_audio_sink_now = TRUE;
3208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3211 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
3213 LOGE("failed to allocate memory for audiobin\n");
3214 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3217 attrs = MMPLAYER_GET_ATTRS(player);
3220 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3221 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3222 if (!audiobin[MMPLAYER_A_BIN].gst) {
3223 LOGE("failed to create audiobin\n");
3228 player->pipeline->audiobin = audiobin;
3230 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
3232 /* Adding audiotp plugin for reverse trickplay feature */
3233 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
3236 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
3238 /* replaygain volume */
3239 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
3240 if (player->sound.rg_enable)
3241 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
3243 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
3246 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
3248 if (player->set_mode.pcm_extraction) {
3249 // pcm extraction only and no sound output
3250 if (player->audio_stream_render_cb_ex) {
3251 char *caps_str = NULL;
3252 GstCaps* caps = NULL;
3253 gchar *format = NULL;
3256 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3258 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
3260 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
3262 caps = gst_caps_new_simple("audio/x-raw",
3263 "format", G_TYPE_STRING, format,
3264 "rate", G_TYPE_INT, player->pcm_samplerate,
3265 "channels", G_TYPE_INT, player->pcm_channel,
3267 caps_str = gst_caps_to_string(caps);
3268 LOGD("new caps : %s\n", caps_str);
3270 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3273 gst_caps_unref(caps);
3274 MMPLAYER_FREEIF(caps_str);
3276 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
3278 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3279 /* raw pad handling signal */
3280 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
3281 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3283 int dst_samplerate = 0;
3284 int dst_channels = 0;
3286 char *caps_str = NULL;
3287 GstCaps* caps = NULL;
3289 /* get conf. values */
3290 mm_attrs_multiple_get(player->attrs,
3292 "pcm_extraction_samplerate", &dst_samplerate,
3293 "pcm_extraction_channels", &dst_channels,
3294 "pcm_extraction_depth", &dst_depth,
3298 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3299 caps = gst_caps_new_simple("audio/x-raw",
3300 "rate", G_TYPE_INT, dst_samplerate,
3301 "channels", G_TYPE_INT, dst_channels,
3302 "depth", G_TYPE_INT, dst_depth,
3304 caps_str = gst_caps_to_string(caps);
3305 LOGD("new caps : %s\n", caps_str);
3307 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3310 gst_caps_unref(caps);
3311 MMPLAYER_FREEIF(caps_str);
3314 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
3317 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3321 //GstCaps* caps = NULL;
3324 /* for logical volume control */
3325 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
3326 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
3328 if (player->sound.mute) {
3329 LOGD("mute enabled\n");
3330 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
3335 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
3336 caps = gst_caps_from_string("audio/x-raw-int, "
3337 "endianness = (int) LITTLE_ENDIAN, "
3338 "signed = (boolean) true, "
3339 "width = (int) 16, "
3340 "depth = (int) 16");
3341 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3342 gst_caps_unref(caps);
3345 /* check if multi-channels */
3346 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
3347 GstPad *srcpad = NULL;
3348 GstCaps *caps = NULL;
3350 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
3351 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
3352 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3353 GstStructure *str = gst_caps_get_structure(caps, 0);
3355 gst_structure_get_int(str, "channels", &channels);
3356 gst_caps_unref(caps);
3358 gst_object_unref(srcpad);
3362 /* audio effect element. if audio effect is enabled */
3363 if ((strcmp(player->ini.audioeffect_element, ""))
3365 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3366 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
3368 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
3370 if ((!player->bypass_audio_effect)
3371 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3372 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
3373 if (!_mmplayer_audio_effect_custom_apply(player))
3374 LOGI("apply audio effect(custom) setting success\n");
3378 if ((strcmp(player->ini.audioeffect_element_custom, ""))
3379 && (player->set_mode.rich_audio))
3380 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
3383 /* create audio sink */
3384 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
3385 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
3386 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
3388 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
3389 if (player->is_360_feature_enabled &&
3390 player->is_content_spherical &&
3392 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
3393 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
3394 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
3396 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
3398 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
3400 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
3401 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
3402 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
3403 gst_caps_unref(acaps);
3405 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
3406 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
3407 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
3408 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
3410 player->is_openal_plugin_used = TRUE;
3412 if (player->video360_yaw_radians <= M_PI &&
3413 player->video360_yaw_radians >= -M_PI &&
3414 player->video360_pitch_radians <= M_PI_2 &&
3415 player->video360_pitch_radians >= -M_PI_2) {
3416 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3417 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3418 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3419 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3420 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3421 "source-orientation-y", player->video360_metadata.init_view_heading,
3422 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
3425 if (player->is_360_feature_enabled && player->is_content_spherical)
3426 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
3427 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
3431 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
3432 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
3435 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
3436 (player->videodec_linked && player->ini.use_system_clock)) {
3437 LOGD("system clock will be used.\n");
3438 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
3441 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
3442 __mmplayer_gst_set_audiosink_property(player, attrs);
3445 if (audiobin[MMPLAYER_A_SINK].gst) {
3446 GstPad *sink_pad = NULL;
3447 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
3448 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3449 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3450 gst_object_unref(GST_OBJECT(sink_pad));
3453 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3455 /* adding created elements to bin */
3456 LOGD("adding created elements to bin\n");
3457 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
3458 LOGE("failed to add elements\n");
3462 /* linking elements in the bucket by added order. */
3463 LOGD("Linking elements in the bucket by added order.\n");
3464 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3465 LOGE("failed to link elements\n");
3469 /* get first element's sinkpad for creating ghostpad */
3470 first_element = (MMPlayerGstElement *)element_bucket->data;
3471 if (!first_element) {
3472 LOGE("failed to get first elem\n");
3476 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3478 LOGE("failed to get pad from first element of audiobin\n");
3482 ghostpad = gst_ghost_pad_new("sink", pad);
3484 LOGE("failed to create ghostpad\n");
3488 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3489 LOGE("failed to add ghostpad to audiobin\n");
3493 gst_object_unref(pad);
3495 g_list_free(element_bucket);
3498 return MM_ERROR_NONE;
3502 LOGD("ERROR : releasing audiobin\n");
3505 gst_object_unref(GST_OBJECT(pad));
3508 gst_object_unref(GST_OBJECT(ghostpad));
3511 g_list_free(element_bucket);
3513 /* release element which are not added to bin */
3514 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3515 /* NOTE : skip bin */
3516 if (audiobin[i].gst) {
3517 GstObject* parent = NULL;
3518 parent = gst_element_get_parent(audiobin[i].gst);
3521 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3522 audiobin[i].gst = NULL;
3524 gst_object_unref(GST_OBJECT(parent));
3528 /* release audiobin with it's childs */
3529 if (audiobin[MMPLAYER_A_BIN].gst)
3530 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3532 MMPLAYER_FREEIF(audiobin);
3534 player->pipeline->audiobin = NULL;
3536 return MM_ERROR_PLAYER_INTERNAL;
3539 static GstPadProbeReturn
3540 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3542 mm_player_t* player = (mm_player_t*) u_data;
3543 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
3544 GstMapInfo probe_info = GST_MAP_INFO_INIT;
3546 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
3548 if (player->audio_stream_cb && probe_info.size && probe_info.data)
3549 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
3551 return GST_PAD_PROBE_OK;
3554 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
3556 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3559 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
3561 int ret = MM_ERROR_NONE;
3563 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3564 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3566 MMPLAYER_VIDEO_BO_LOCK(player);
3568 if (player->video_bo_list) {
3569 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3570 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3571 if (tmp && tmp->bo == bo) {
3573 LOGD("release bo %p", bo);
3574 tbm_bo_unref(tmp->bo);
3575 MMPLAYER_VIDEO_BO_UNLOCK(player);
3576 MMPLAYER_VIDEO_BO_SIGNAL(player);
3581 /* hw codec is running or the list was reset for DRC. */
3582 LOGW("there is no bo list.");
3584 MMPLAYER_VIDEO_BO_UNLOCK(player);
3586 LOGW("failed to find bo %p", bo);
3591 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
3596 MMPLAYER_RETURN_IF_FAIL(player);
3598 MMPLAYER_VIDEO_BO_LOCK(player);
3599 if (player->video_bo_list) {
3600 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3601 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3602 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3605 tbm_bo_unref(tmp->bo);
3609 g_list_free(player->video_bo_list);
3610 player->video_bo_list = NULL;
3612 player->video_bo_size = 0;
3613 MMPLAYER_VIDEO_BO_UNLOCK(player);
3620 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
3623 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3624 gboolean ret = TRUE;
3626 /* check DRC, if it is, destroy the prev bo list to create again */
3627 if (player->video_bo_size != size) {
3628 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3629 __mmplayer_video_stream_destroy_bo_list(player);
3630 player->video_bo_size = size;
3633 MMPLAYER_VIDEO_BO_LOCK(player);
3635 if ((!player->video_bo_list) ||
3636 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3638 /* create bo list */
3640 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3642 if (player->video_bo_list) {
3643 /* if bo list did not created all, try it again. */
3644 idx = g_list_length(player->video_bo_list);
3645 LOGD("bo list exist(len: %d)", idx);
3648 for (; idx < player->ini.num_of_video_bo; idx++) {
3649 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3651 LOGE("Fail to alloc bo_info.");
3654 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3656 LOGE("Fail to tbm_bo_alloc.");
3660 bo_info->used = FALSE;
3661 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3664 /* update video num buffers */
3665 player->video_num_buffers = idx;
3666 if (idx == player->ini.num_of_video_bo)
3667 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3670 MMPLAYER_VIDEO_BO_UNLOCK(player);
3674 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3678 /* get bo from list*/
3679 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3680 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3681 if (tmp && (tmp->used == FALSE)) {
3682 LOGD("found bo %p to use", tmp->bo);
3684 MMPLAYER_VIDEO_BO_UNLOCK(player);
3685 return tbm_bo_ref(tmp->bo);
3689 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3690 MMPLAYER_VIDEO_BO_UNLOCK(player);
3694 if (player->ini.video_bo_timeout <= 0) {
3695 MMPLAYER_VIDEO_BO_WAIT(player);
3697 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3698 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3705 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3707 mm_player_t* player = (mm_player_t*)data;
3709 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3711 /* send prerolled pkt */
3712 player->video_stream_prerolled = FALSE;
3714 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3716 /* not to send prerolled pkt again */
3717 player->video_stream_prerolled = TRUE;
3721 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3723 mm_player_t* player = (mm_player_t*)data;
3724 GstCaps *caps = NULL;
3725 MMPlayerVideoStreamDataType *stream = NULL;
3726 tbm_surface_h surface;
3727 GstMemory *mem = NULL;
3728 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3729 GstStructure *structure = NULL;
3730 const gchar *string_format = NULL;
3731 unsigned int fourcc = 0;
3732 unsigned int pitch = 0;
3736 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3738 if (player->video_stream_prerolled) {
3739 player->video_stream_prerolled = FALSE;
3740 LOGD("skip the prerolled pkt not to send it again");
3744 caps = gst_pad_get_current_caps(pad);
3746 LOGE("Caps is NULL.");
3750 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
3752 /* clear stream data structure */
3753 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
3755 LOGE("failed to alloc mem for video data");
3759 structure = gst_caps_get_structure(caps, 0);
3760 gst_structure_get_int(structure, "width", &(stream->width));
3761 gst_structure_get_int(structure, "height", &(stream->height));
3762 string_format = gst_structure_get_string(structure, "format");
3764 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
3765 stream->format = util_get_pixtype(fourcc);
3766 gst_caps_unref(caps);
3769 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3772 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
3773 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
3776 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
3777 LOGE("Wrong condition!!");
3781 /* set size and timestamp */
3782 mem = gst_buffer_peek_memory(buffer, 0);
3783 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3784 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3785 surface = gst_tizen_memory_get_surface(mem);
3787 /* check zero-copy */
3788 if (player->set_mode.video_zc &&
3789 player->set_mode.media_packet_video_stream &&
3790 gst_is_tizen_memory(mem)) {
3791 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
3792 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
3793 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
3794 stream->stride[index] = pitch;
3795 stream->elevation[index] = stream->height;
3797 stream->internal_buffer = gst_buffer_ref(buffer);
3798 } else { /* sw codec */
3802 int ret = TBM_SURFACE_ERROR_NONE;
3803 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
3804 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
3806 unsigned char *src = NULL;
3807 unsigned char *dest = NULL;
3808 tbm_bo_handle thandle;
3809 tbm_surface_h surface;
3810 tbm_surface_info_s info;
3813 gst_ret = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
3815 LOGE("fail to gst_memory_map");
3820 if (stream->format == MM_PIXEL_FORMAT_I420) {
3821 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
3823 ret = tbm_surface_get_info(surface, &info);
3825 if (ret != TBM_SURFACE_ERROR_NONE) {
3826 tbm_surface_destroy(surface);
3829 tbm_surface_destroy(surface);
3831 src_stride[0] = GST_ROUND_UP_4(stream->width);
3832 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
3833 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
3834 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
3835 stream->stride[0] = info.planes[0].stride;
3836 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
3837 stream->stride[1] = info.planes[1].stride;
3838 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
3839 stream->stride[2] = info.planes[2].stride;
3840 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
3841 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
3842 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
3843 stream->stride[0] = stream->width * 4;
3844 stream->elevation[0] = stream->height;
3845 size = stream->stride[0] * stream->height;
3847 LOGE("Not support format %d", stream->format);
3851 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
3852 if (!stream->bo[0]) {
3853 LOGE("Fail to tbm_bo_alloc!!");
3857 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
3858 if (thandle.ptr && mapinfo.data) {
3859 if (stream->format == MM_PIXEL_FORMAT_I420) {
3860 for (i = 0; i < 3; i++) {
3861 src = mapinfo.data + src_offset[i];
3862 dest = thandle.ptr + info.planes[i].offset;
3865 for (j = 0; j < stream->height>>k; j++) {
3866 memcpy(dest, src, stream->width>>k);
3867 src += src_stride[i];
3868 dest += stream->stride[i];
3871 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
3872 memcpy(thandle.ptr, mapinfo.data, size);
3874 LOGE("Not support format %d", stream->format);
3878 LOGE("data pointer is wrong. dest : %p, src : %p",
3879 thandle.ptr, mapinfo.data);
3882 tbm_bo_unmap(stream->bo[0]);
3885 if (player->video_stream_cb) { /* This has been already checked at the entry */
3886 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3887 LOGE("failed to send video stream data.");
3891 gst_memory_unmap(mem, &mapinfo);
3896 LOGE("release video stream resource.");
3897 if (gst_is_tizen_memory(mem)) {
3899 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3901 tbm_bo_unref(stream->bo[i]);
3904 /* unref gst buffer */
3905 if (stream->internal_buffer)
3906 gst_buffer_unref(stream->internal_buffer);
3909 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3912 gst_memory_unmap(mem, &mapinfo);
3918 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
3920 gchar* video_csc = "videoconvert"; /* default colorspace converter */
3921 GList* element_bucket = NULL;
3923 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3927 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
3928 LOGD("do not need to add video filters.");
3929 return MM_ERROR_NONE;
3932 /* in case of sw codec except 360 playback,
3933 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3934 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3935 LOGD("using video converter: %s", video_csc);
3937 /* set video rotator */
3938 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3940 *bucket = element_bucket;
3942 return MM_ERROR_NONE;
3944 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3945 g_list_free(element_bucket);
3949 return MM_ERROR_PLAYER_INTERNAL;
3953 * This function is to create video pipeline.
3955 * @param player [in] handle of player
3956 * caps [in] src caps of decoder
3957 * surface_type [in] surface type for video rendering
3959 * @return This function returns zero on success.
3961 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3965 * - video overlay surface(arm/x86) : tizenwlsink
3968 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3972 GList*element_bucket = NULL;
3973 MMPlayerGstElement* first_element = NULL;
3974 MMPlayerGstElement* videobin = NULL;
3975 gchar *videosink_element = NULL;
3979 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3982 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3984 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3986 player->pipeline->videobin = videobin;
3988 attrs = MMPLAYER_GET_ATTRS(player);
3990 LOGE("cannot get content attribute");
3991 return MM_ERROR_PLAYER_INTERNAL;
3995 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3996 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3997 if (!videobin[MMPLAYER_V_BIN].gst) {
3998 LOGE("failed to create videobin");
4002 int enable_video_decoded_cb = 0;
4003 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
4005 if (player->is_360_feature_enabled && player->is_content_spherical) {
4006 LOGD("video360 elem will be added.");
4008 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
4009 "video-360", TRUE, player);
4011 /* Set spatial media metadata and/or user settings to the element.
4013 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4014 "projection-type", player->video360_metadata.projection_type, NULL);
4016 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4017 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
4019 if (player->video360_metadata.full_pano_width_pixels &&
4020 player->video360_metadata.full_pano_height_pixels &&
4021 player->video360_metadata.cropped_area_image_width &&
4022 player->video360_metadata.cropped_area_image_height) {
4023 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4024 "projection-bounds-top", player->video360_metadata.cropped_area_top,
4025 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
4026 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
4027 "projection-bounds-left", player->video360_metadata.cropped_area_left,
4028 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
4029 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
4033 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
4034 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4035 "horizontal-fov", player->video360_horizontal_fov,
4036 "vertical-fov", player->video360_vertical_fov, NULL);
4039 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
4040 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4041 "zoom", 1.0f / player->video360_zoom, NULL);
4044 if (player->video360_yaw_radians <= M_PI &&
4045 player->video360_yaw_radians >= -M_PI &&
4046 player->video360_pitch_radians <= M_PI_2 &&
4047 player->video360_pitch_radians >= -M_PI_2) {
4048 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4049 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4050 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4051 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4052 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4053 "pose-yaw", player->video360_metadata.init_view_heading,
4054 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
4057 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4058 "passthrough", !player->is_video360_enabled, NULL);
4061 /* set video sink */
4062 switch (surface_type) {
4063 case MM_DISPLAY_SURFACE_OVERLAY:
4064 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
4066 if (strlen(player->ini.videosink_element_overlay) > 0)
4067 videosink_element = player->ini.videosink_element_overlay;
4071 case MM_DISPLAY_SURFACE_NULL:
4072 if (strlen(player->ini.videosink_element_fake) > 0)
4073 videosink_element = player->ini.videosink_element_fake;
4077 case MM_DISPLAY_SURFACE_REMOTE:
4078 if (strlen(player->ini.videosink_element_fake) > 0)
4079 videosink_element = player->ini.videosink_element_fake;
4084 LOGE("unidentified surface type");
4087 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
4089 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
4091 /* additional setting for sink plug-in */
4092 switch (surface_type) {
4093 case MM_DISPLAY_SURFACE_OVERLAY:
4095 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
4097 LOGD("selected videosink name: %s", videosink_element);
4099 /* support shard memory with S/W codec on HawkP */
4100 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
4101 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4102 "use-tbm", use_tbm, NULL);
4108 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4111 LOGD("disable last-sample");
4112 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4116 if (player->set_mode.media_packet_video_stream) {
4118 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
4120 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
4122 __mmplayer_add_signal_connection(player,
4123 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4124 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4126 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
4129 __mmplayer_add_signal_connection(player,
4130 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4131 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4133 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
4138 case MM_DISPLAY_SURFACE_REMOTE:
4140 if (player->set_mode.media_packet_video_stream) {
4141 LOGE("add data probe at videosink");
4142 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4143 "sync", TRUE, "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
4145 __mmplayer_add_signal_connection(player,
4146 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4147 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4149 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
4152 __mmplayer_add_signal_connection(player,
4153 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4154 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4156 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
4161 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4164 LOGD("disable last-sample");
4165 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4175 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
4178 if (videobin[MMPLAYER_V_SINK].gst) {
4179 GstPad *sink_pad = NULL;
4180 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
4182 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4183 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
4184 gst_object_unref(GST_OBJECT(sink_pad));
4186 LOGW("failed to get sink pad from videosink\n");
4189 /* store it as it's sink element */
4190 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
4192 /* adding created elements to bin */
4193 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
4194 LOGE("failed to add elements\n");
4198 /* Linking elements in the bucket by added order */
4199 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4200 LOGE("failed to link elements\n");
4204 /* get first element's sinkpad for creating ghostpad */
4206 first_element = (MMPlayerGstElement *)element_bucket->data;
4207 if (!first_element) {
4208 LOGE("failed to get first element from bucket\n");
4212 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4214 LOGE("failed to get pad from first element\n");
4218 /* create ghostpad */
4219 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
4220 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
4221 LOGE("failed to add ghostpad to videobin\n");
4224 gst_object_unref(pad);
4226 /* done. free allocated variables */
4228 g_list_free(element_bucket);
4232 return MM_ERROR_NONE;
4235 LOGE("ERROR : releasing videobin\n");
4237 g_list_free(element_bucket);
4240 gst_object_unref(GST_OBJECT(pad));
4242 /* release videobin with it's childs */
4243 if (videobin[MMPLAYER_V_BIN].gst)
4244 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
4247 MMPLAYER_FREEIF(videobin);
4249 player->pipeline->videobin = NULL;
4251 return MM_ERROR_PLAYER_INTERNAL;
4254 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
4256 GList *element_bucket = NULL;
4257 MMPlayerGstElement *textbin = player->pipeline->textbin;
4259 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
4260 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
4261 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
4262 "signal-handoffs", FALSE,
4265 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
4266 __mmplayer_add_signal_connection(player,
4267 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
4268 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
4270 G_CALLBACK(__mmplayer_update_subtitle),
4273 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
4274 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
4276 if (!player->play_subtitle) {
4277 LOGD("add textbin sink as sink element of whole pipeline.\n");
4278 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
4281 /* adding created elements to bin */
4282 LOGD("adding created elements to bin\n");
4283 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
4284 LOGE("failed to add elements\n");
4288 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
4289 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
4290 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
4292 /* linking elements in the bucket by added order. */
4293 LOGD("Linking elements in the bucket by added order.\n");
4294 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4295 LOGE("failed to link elements\n");
4299 /* done. free allocated variables */
4300 g_list_free(element_bucket);
4302 if (textbin[MMPLAYER_T_QUEUE].gst) {
4304 GstPad *ghostpad = NULL;
4306 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
4308 LOGE("failed to get sink pad of text queue");
4312 ghostpad = gst_ghost_pad_new("text_sink", pad);
4313 gst_object_unref(pad);
4316 LOGE("failed to create ghostpad of textbin\n");
4320 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
4321 LOGE("failed to add ghostpad to textbin\n");
4322 gst_object_unref(ghostpad);
4327 return MM_ERROR_NONE;
4330 g_list_free(element_bucket);
4332 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
4333 LOGE("remove textbin sink from sink list");
4334 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
4337 /* release element at __mmplayer_gst_create_text_sink_bin */
4338 return MM_ERROR_PLAYER_INTERNAL;
4341 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
4343 MMPlayerGstElement *textbin = NULL;
4344 GList *element_bucket = NULL;
4345 int surface_type = 0;
4350 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4353 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
4355 LOGE("failed to allocate memory for textbin\n");
4356 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4360 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
4361 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
4362 if (!textbin[MMPLAYER_T_BIN].gst) {
4363 LOGE("failed to create textbin\n");
4368 player->pipeline->textbin = textbin;
4371 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
4372 LOGD("surface type for subtitle : %d", surface_type);
4373 switch (surface_type) {
4374 case MM_DISPLAY_SURFACE_OVERLAY:
4375 case MM_DISPLAY_SURFACE_NULL:
4376 case MM_DISPLAY_SURFACE_REMOTE:
4377 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
4378 LOGE("failed to make plain text elements\n");
4389 return MM_ERROR_NONE;
4393 LOGD("ERROR : releasing textbin\n");
4395 g_list_free(element_bucket);
4397 /* release signal */
4398 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4400 /* release element which are not added to bin */
4401 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4402 /* NOTE : skip bin */
4403 if (textbin[i].gst) {
4404 GstObject* parent = NULL;
4405 parent = gst_element_get_parent(textbin[i].gst);
4408 gst_object_unref(GST_OBJECT(textbin[i].gst));
4409 textbin[i].gst = NULL;
4411 gst_object_unref(GST_OBJECT(parent));
4416 /* release textbin with it's childs */
4417 if (textbin[MMPLAYER_T_BIN].gst)
4418 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4420 MMPLAYER_FREEIF(player->pipeline->textbin);
4421 player->pipeline->textbin = NULL;
4424 return MM_ERROR_PLAYER_INTERNAL;
4429 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
4431 MMPlayerGstElement* mainbin = NULL;
4432 MMPlayerGstElement* textbin = NULL;
4433 MMHandleType attrs = 0;
4434 GstElement *subsrc = NULL;
4435 GstElement *subparse = NULL;
4436 gchar *subtitle_uri = NULL;
4437 const gchar *charset = NULL;
4443 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4445 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4447 mainbin = player->pipeline->mainbin;
4449 attrs = MMPLAYER_GET_ATTRS(player);
4451 LOGE("cannot get content attribute\n");
4452 return MM_ERROR_PLAYER_INTERNAL;
4455 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4456 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4457 LOGE("subtitle uri is not proper filepath.\n");
4458 return MM_ERROR_PLAYER_INVALID_URI;
4461 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4462 LOGE("failed to get storage info of subtitle path");
4463 return MM_ERROR_PLAYER_INVALID_URI;
4466 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
4468 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4469 player->subtitle_language_list = NULL;
4470 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4472 /* create the subtitle source */
4473 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4475 LOGE("failed to create filesrc element\n");
4478 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4480 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4481 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4483 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4484 LOGW("failed to add queue\n");
4485 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4486 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4487 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4492 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4494 LOGE("failed to create subparse element\n");
4498 charset = util_get_charset(subtitle_uri);
4500 LOGD("detected charset is %s\n", charset);
4501 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4504 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4505 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4507 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4508 LOGW("failed to add subparse\n");
4509 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4510 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4511 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4515 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4516 LOGW("failed to link subsrc and subparse\n");
4520 player->play_subtitle = TRUE;
4521 player->adjust_subtitle_pos = 0;
4523 LOGD("play subtitle using subtitle file\n");
4525 if (player->pipeline->textbin == NULL) {
4526 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4527 LOGE("failed to create text sink bin. continuing without text\n");
4531 textbin = player->pipeline->textbin;
4533 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4534 LOGW("failed to add textbin\n");
4536 /* release signal */
4537 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4539 /* release textbin with it's childs */
4540 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4541 MMPLAYER_FREEIF(player->pipeline->textbin);
4542 player->pipeline->textbin = textbin = NULL;
4546 LOGD("link text input selector and textbin ghost pad");
4548 player->textsink_linked = 1;
4549 player->external_text_idx = 0;
4550 LOGI("player->textsink_linked set to 1\n");
4552 textbin = player->pipeline->textbin;
4553 LOGD("text bin has been created. reuse it.");
4554 player->external_text_idx = 1;
4557 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4558 LOGW("failed to link subparse and textbin\n");
4562 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4564 LOGE("failed to get sink pad from textsink to probe data");
4568 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4569 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4571 gst_object_unref(pad);
4574 /* create dot. for debugging */
4575 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4578 return MM_ERROR_NONE;
4581 /* release text pipeline resource */
4582 player->textsink_linked = 0;
4584 /* release signal */
4585 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4587 if (player->pipeline->textbin) {
4588 LOGE("remove textbin");
4590 /* release textbin with it's childs */
4591 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4592 MMPLAYER_FREEIF(player->pipeline->textbin);
4593 player->pipeline->textbin = NULL;
4597 /* release subtitle elem */
4598 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4599 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4601 return MM_ERROR_PLAYER_INTERNAL;
4605 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4607 mm_player_t* player = (mm_player_t*) data;
4608 MMMessageParamType msg = {0, };
4609 GstClockTime duration = 0;
4610 gpointer text = NULL;
4611 guint text_size = 0;
4612 gboolean ret = TRUE;
4613 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4617 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4618 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4620 if (player->is_subtitle_force_drop) {
4621 LOGW("subtitle is dropped forcedly.");
4625 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4626 text = mapinfo.data;
4627 text_size = mapinfo.size;
4628 duration = GST_BUFFER_DURATION(buffer);
4630 if (player->set_mode.subtitle_off) {
4631 LOGD("subtitle is OFF.\n");
4635 if (!text || (text_size == 0)) {
4636 LOGD("There is no subtitle to be displayed.\n");
4640 msg.data = (void *) text;
4641 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4643 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
4645 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4646 gst_buffer_unmap(buffer, &mapinfo);
4653 static GstPadProbeReturn
4654 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4656 mm_player_t *player = (mm_player_t *) u_data;
4657 GstClockTime cur_timestamp = 0;
4658 gint64 adjusted_timestamp = 0;
4659 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4661 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4663 if (player->set_mode.subtitle_off) {
4664 LOGD("subtitle is OFF.\n");
4668 if (player->adjust_subtitle_pos == 0) {
4669 LOGD("nothing to do");
4673 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4674 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4676 if (adjusted_timestamp < 0) {
4677 LOGD("adjusted_timestamp under zero");
4682 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4683 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4684 GST_TIME_ARGS(cur_timestamp),
4685 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4687 return GST_PAD_PROBE_OK;
4689 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
4693 /* check player and subtitlebin are created */
4694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4695 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4697 if (position == 0) {
4698 LOGD("nothing to do\n");
4700 return MM_ERROR_NONE;
4704 case MM_PLAYER_POS_FORMAT_TIME:
4706 /* check current postion */
4707 player->adjust_subtitle_pos = position;
4709 LOGD("save adjust_subtitle_pos in player") ;
4715 LOGW("invalid format.\n");
4717 return MM_ERROR_INVALID_ARGUMENT;
4723 return MM_ERROR_NONE;
4727 * This function is to create audio or video pipeline for playing.
4729 * @param player [in] handle of player
4731 * @return This function returns zero on success.
4736 __mmplayer_gst_create_pipeline(mm_player_t* player)
4738 int ret = MM_ERROR_NONE;
4739 MMPlayerGstElement *mainbin = NULL;
4740 MMHandleType attrs = 0;
4741 gint mode = MM_PLAYER_PD_MODE_NONE;
4744 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4746 /* get profile attribute */
4747 attrs = MMPLAYER_GET_ATTRS(player);
4749 LOGE("failed to get content attribute");
4753 /* create pipeline handles */
4754 if (player->pipeline) {
4755 LOGE("pipeline should be released before create new one");
4759 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
4760 if (player->pipeline == NULL)
4763 /* create mainbin */
4764 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4765 if (mainbin == NULL)
4768 /* create pipeline */
4769 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4770 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4771 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4772 LOGE("failed to create pipeline");
4777 player->pipeline->mainbin = mainbin;
4780 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
4781 player->pd_mode = mode;
4783 /* create the source and decoder elements */
4784 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4785 ret = __mmplayer_gst_build_es_pipeline(player);
4786 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
4787 ret = __mmplayer_gst_build_pd_pipeline(player);
4789 ret = __mmplayer_gst_build_pipeline(player);
4792 if (ret != MM_ERROR_NONE) {
4793 LOGE("failed to create some elements");
4797 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4798 if (__mmplayer_check_subtitle(player)) {
4799 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
4800 LOGE("failed to create text pipeline");
4804 ret = __mmplayer_gst_add_bus_watch(player);
4805 if (ret != MM_ERROR_NONE) {
4806 LOGE("failed to add bus watch");
4811 return MM_ERROR_NONE;
4814 __mmplayer_gst_destroy_pipeline(player);
4815 return MM_ERROR_PLAYER_INTERNAL;
4819 __mmplayer_reset_gapless_state(mm_player_t* player)
4822 MMPLAYER_RETURN_IF_FAIL(player
4824 && player->pipeline->audiobin
4825 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4827 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4834 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4837 int ret = MM_ERROR_NONE;
4841 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4843 /* cleanup stuffs */
4844 MMPLAYER_FREEIF(player->type);
4845 player->have_dynamic_pad = FALSE;
4846 player->no_more_pad = FALSE;
4847 player->num_dynamic_pad = 0;
4848 player->demux_pad_index = 0;
4849 player->use_deinterleave = FALSE;
4850 player->max_audio_channels = 0;
4851 player->video_share_api_delta = 0;
4852 player->video_share_clock_delta = 0;
4853 player->video_hub_download_mode = 0;
4855 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4856 player->subtitle_language_list = NULL;
4857 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4859 __mmplayer_reset_gapless_state(player);
4861 if (player->streamer) {
4862 __mm_player_streaming_deinitialize(player->streamer);
4863 __mm_player_streaming_destroy(player->streamer);
4864 player->streamer = NULL;
4867 /* cleanup unlinked mime type */
4868 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4869 MMPLAYER_FREEIF(player->unlinked_video_mime);
4870 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4872 /* cleanup running stuffs */
4873 __mmplayer_cancel_eos_timer(player);
4875 /* cleanup gst stuffs */
4876 if (player->pipeline) {
4877 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4878 GstTagList* tag_list = player->pipeline->tag_list;
4880 /* first we need to disconnect all signal hander */
4881 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4884 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4885 MMPlayerGstElement* videobin = player->pipeline->videobin;
4886 MMPlayerGstElement* textbin = player->pipeline->textbin;
4887 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4888 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4889 gst_object_unref(bus);
4891 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4892 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4893 if (ret != MM_ERROR_NONE) {
4894 LOGE("fail to change state to NULL\n");
4895 return MM_ERROR_PLAYER_INTERNAL;
4898 LOGW("succeeded in changing state to NULL\n");
4900 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4903 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4904 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4906 /* free avsysaudiosink
4907 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4908 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4910 MMPLAYER_FREEIF(audiobin);
4911 MMPLAYER_FREEIF(videobin);
4912 MMPLAYER_FREEIF(textbin);
4913 MMPLAYER_FREEIF(mainbin);
4917 gst_tag_list_free(tag_list);
4919 MMPLAYER_FREEIF(player->pipeline);
4921 MMPLAYER_FREEIF(player->album_art);
4923 if (player->v_stream_caps) {
4924 gst_caps_unref(player->v_stream_caps);
4925 player->v_stream_caps = NULL;
4927 if (player->a_stream_caps) {
4928 gst_caps_unref(player->a_stream_caps);
4929 player->a_stream_caps = NULL;
4932 if (player->s_stream_caps) {
4933 gst_caps_unref(player->s_stream_caps);
4934 player->s_stream_caps = NULL;
4936 __mmplayer_track_destroy(player);
4938 if (player->sink_elements)
4939 g_list_free(player->sink_elements);
4940 player->sink_elements = NULL;
4942 if (player->bufmgr) {
4943 tbm_bufmgr_deinit(player->bufmgr);
4944 player->bufmgr = NULL;
4947 LOGW("finished destroy pipeline\n");
4954 static int __mmplayer_gst_realize(mm_player_t* player)
4957 int ret = MM_ERROR_NONE;
4961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4963 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4965 ret = __mmplayer_gst_create_pipeline(player);
4967 LOGE("failed to create pipeline\n");
4971 /* set pipeline state to READY */
4972 /* NOTE : state change to READY must be performed sync. */
4973 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4974 ret = __mmplayer_gst_set_state(player,
4975 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4977 if (ret != MM_ERROR_NONE) {
4978 /* return error if failed to set state */
4979 LOGE("failed to set READY state");
4983 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4985 /* create dot before error-return. for debugging */
4986 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4993 static int __mmplayer_gst_unrealize(mm_player_t* player)
4995 int ret = MM_ERROR_NONE;
4999 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5001 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
5002 MMPLAYER_PRINT_STATE(player);
5004 /* release miscellaneous information */
5005 __mmplayer_release_misc(player);
5007 /* destroy pipeline */
5008 ret = __mmplayer_gst_destroy_pipeline(player);
5009 if (ret != MM_ERROR_NONE) {
5010 LOGE("failed to destory pipeline\n");
5014 /* release miscellaneous information.
5015 these info needs to be released after pipeline is destroyed. */
5016 __mmplayer_release_misc_post(player);
5018 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
5026 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
5031 LOGW("set_message_callback is called with invalid player handle\n");
5032 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5035 player->msg_cb = callback;
5036 player->msg_cb_param = user_param;
5038 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
5042 return MM_ERROR_NONE;
5045 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
5047 int ret = MM_ERROR_PLAYER_INVALID_URI;
5052 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
5053 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
5054 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
5056 memset(data, 0, sizeof(MMPlayerParseProfile));
5058 if ((path = strstr(uri, "es_buff://"))) {
5060 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5061 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
5062 ret = MM_ERROR_NONE;
5064 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
5066 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5067 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5068 ret = MM_ERROR_NONE;
5070 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
5073 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5074 tmp = g_ascii_strdown(uri, strlen(uri));
5076 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
5077 data->uri_type = MM_PLAYER_URI_TYPE_SS;
5079 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5081 ret = MM_ERROR_NONE;
5084 } else if ((path = strstr(uri, "rtspu://"))) {
5086 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5087 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5088 ret = MM_ERROR_NONE;
5090 } else if ((path = strstr(uri, "rtspr://"))) {
5091 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
5092 char *separater = strstr(path, "*");
5096 char *urgent = separater + strlen("*");
5098 if ((urgent_len = strlen(urgent))) {
5099 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
5100 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
5101 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5102 ret = MM_ERROR_NONE;
5105 } else if ((path = strstr(uri, "mms://"))) {
5107 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5108 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
5109 ret = MM_ERROR_NONE;
5111 } else if ((path = strstr(uri, "mem://"))) {
5114 char *buffer = NULL;
5115 char *seperator = strchr(path, ',');
5116 char ext[100] = {0,}, size[100] = {0,};
5119 if ((buffer = strstr(path, "ext="))) {
5120 buffer += strlen("ext=");
5122 if (strlen(buffer)) {
5123 strncpy(ext, buffer, 99);
5125 if ((seperator = strchr(ext, ','))
5126 || (seperator = strchr(ext, ' '))
5127 || (seperator = strchr(ext, '\0'))) {
5128 seperator[0] = '\0';
5133 if ((buffer = strstr(path, "size="))) {
5134 buffer += strlen("size=");
5136 if (strlen(buffer) > 0) {
5137 strncpy(size, buffer, 99);
5139 if ((seperator = strchr(size, ','))
5140 || (seperator = strchr(size, ' '))
5141 || (seperator = strchr(size, '\0'))) {
5142 seperator[0] = '\0';
5145 mem_size = atoi(size);
5150 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
5151 if (mem_size && param) {
5152 if (data->input_mem.buf)
5153 free(data->input_mem.buf);
5154 data->input_mem.buf = malloc(mem_size);
5156 if (data->input_mem.buf) {
5157 memcpy(data->input_mem.buf, param, mem_size);
5158 data->input_mem.len = mem_size;
5159 ret = MM_ERROR_NONE;
5161 LOGE("failed to alloc mem %d", mem_size);
5162 ret = MM_ERROR_PLAYER_INTERNAL;
5165 data->input_mem.offset = 0;
5166 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
5170 gchar *location = NULL;
5173 if ((path = strstr(uri, "file://"))) {
5175 location = g_filename_from_uri(uri, NULL, &err);
5177 if (!location || (err != NULL)) {
5178 LOGE("Invalid URI '%s' for filesrc: %s", path,
5179 (err != NULL) ? err->message : "unknown error");
5181 if (err) g_error_free(err);
5182 if (location) g_free(location);
5184 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5188 LOGD("path from uri: %s", location);
5191 path = (location != NULL) ? (location) : ((char*)uri);
5192 int file_stat = MM_ERROR_NONE;
5194 file_stat = util_exist_file_path(path);
5196 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
5197 if (file_stat == MM_ERROR_NONE) {
5198 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
5200 if (util_is_sdp_file(path)) {
5201 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5202 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5204 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5206 ret = MM_ERROR_NONE;
5207 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
5208 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
5210 LOGE("invalid uri, could not play..\n");
5211 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5214 if (location) g_free(location);
5218 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
5219 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
5220 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
5221 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
5223 /* dump parse result */
5224 SECURE_LOGW("incomming uri : %s\n", uri);
5225 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
5226 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
5234 __mmplayer_can_do_interrupt(mm_player_t *player)
5236 if (!player || !player->pipeline || !player->attrs) {
5237 LOGW("not initialized");
5241 if (player->set_mode.pcm_extraction) {
5242 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
5246 /* check if seeking */
5247 if (player->seek_state != MMPLAYER_SEEK_NONE) {
5248 MMMessageParamType msg_param;
5249 memset(&msg_param, 0, sizeof(MMMessageParamType));
5250 msg_param.code = MM_ERROR_PLAYER_SEEK;
5251 player->seek_state = MMPLAYER_SEEK_NONE;
5252 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5256 /* check other thread */
5257 if (!MMPLAYER_CMD_TRYLOCK(player)) {
5258 LOGW("locked already, cmd state : %d", player->cmd);
5260 /* check application command */
5261 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
5262 LOGW("playing.. should wait cmd lock then, will be interrupted");
5264 /* lock will be released at mrp_resource_release_cb() */
5265 MMPLAYER_CMD_LOCK(player);
5268 LOGW("nothing to do");
5271 LOGW("can interrupt immediately");
5275 FAILED: /* with CMD UNLOCKED */
5278 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
5283 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
5286 mm_player_t *player = NULL;
5290 if (user_data == NULL) {
5291 LOGE("- user_data is null\n");
5294 player = (mm_player_t *)user_data;
5296 /* do something to release resource here.
5297 * player stop and interrupt forwarding */
5298 if (!__mmplayer_can_do_interrupt(player)) {
5299 LOGW("no need to interrupt, so leave");
5301 MMMessageParamType msg = {0, };
5304 player->interrupted_by_resource = TRUE;
5306 /* get last play position */
5307 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
5308 LOGW("failed to get play position.");
5310 msg.union_type = MM_MSG_UNION_TIME;
5311 msg.time.elapsed = pos;
5312 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
5314 LOGD("video resource conflict so, resource will be freed by unrealizing");
5315 if (_mmplayer_unrealize((MMHandleType)player))
5316 LOGW("failed to unrealize");
5318 /* lock is called in __mmplayer_can_do_interrupt() */
5319 MMPLAYER_CMD_UNLOCK(player);
5322 if (res == player->video_overlay_resource)
5323 player->video_overlay_resource = FALSE;
5325 player->video_decoder_resource = FALSE;
5333 __mmplayer_initialize_video_roi(mm_player_t *player)
5335 player->video_roi.scale_x = 0.0;
5336 player->video_roi.scale_y = 0.0;
5337 player->video_roi.scale_width = 1.0;
5338 player->video_roi.scale_height = 1.0;
5342 _mmplayer_create_player(MMHandleType handle)
5344 int ret = MM_ERROR_PLAYER_INTERNAL;
5345 bool enabled = false;
5347 mm_player_t* player = MM_PLAYER_CAST(handle);
5351 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5353 /* initialize player state */
5354 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
5355 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
5356 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
5357 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
5359 /* check current state */
5360 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
5362 /* construct attributes */
5363 player->attrs = _mmplayer_construct_attribute(handle);
5365 if (!player->attrs) {
5366 LOGE("Failed to construct attributes\n");
5370 /* initialize gstreamer with configured parameter */
5371 if (!__mmplayer_init_gstreamer(player)) {
5372 LOGE("Initializing gstreamer failed\n");
5373 _mmplayer_deconstruct_attribute(handle);
5377 /* create lock. note that g_tread_init() has already called in gst_init() */
5378 g_mutex_init(&player->fsink_lock);
5380 /* create update tag lock */
5381 g_mutex_init(&player->update_tag_lock);
5383 /* create next play mutex */
5384 g_mutex_init(&player->next_play_thread_mutex);
5386 /* create next play cond */
5387 g_cond_init(&player->next_play_thread_cond);
5389 /* create next play thread */
5390 player->next_play_thread =
5391 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
5392 if (!player->next_play_thread) {
5393 LOGE("failed to create next play thread");
5394 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
5395 g_mutex_clear(&player->next_play_thread_mutex);
5396 g_cond_clear(&player->next_play_thread_cond);
5400 player->bus_msg_q = g_queue_new();
5401 if (!player->bus_msg_q) {
5402 LOGE("failed to create queue for bus_msg");
5403 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
5407 ret = _mmplayer_initialize_video_capture(player);
5408 if (ret != MM_ERROR_NONE) {
5409 LOGE("failed to initialize video capture\n");
5413 /* initialize resource manager */
5414 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
5415 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
5416 &player->resource_manager)) {
5417 LOGE("failed to initialize resource manager\n");
5418 ret = MM_ERROR_PLAYER_INTERNAL;
5422 if (MMPLAYER_IS_HTTP_PD(player)) {
5423 player->pd_downloader = NULL;
5424 player->pd_file_save_path = NULL;
5427 /* create video bo lock and cond */
5428 g_mutex_init(&player->video_bo_mutex);
5429 g_cond_init(&player->video_bo_cond);
5431 /* create media stream callback mutex */
5432 g_mutex_init(&player->media_stream_cb_lock);
5434 /* create subtitle info lock and cond */
5435 g_mutex_init(&player->subtitle_info_mutex);
5436 g_cond_init(&player->subtitle_info_cond);
5438 player->streaming_type = STREAMING_SERVICE_NONE;
5440 /* give default value of audio effect setting */
5441 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
5442 player->sound.rg_enable = false;
5443 player->playback_rate = DEFAULT_PLAYBACK_RATE;
5445 player->play_subtitle = FALSE;
5446 player->use_deinterleave = FALSE;
5447 player->max_audio_channels = 0;
5448 player->video_share_api_delta = 0;
5449 player->video_share_clock_delta = 0;
5450 player->has_closed_caption = FALSE;
5451 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
5452 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
5453 player->pending_resume = FALSE;
5454 if (player->ini.dump_element_keyword[0][0] == '\0')
5455 player->ini.set_dump_element_flag = FALSE;
5457 player->ini.set_dump_element_flag = TRUE;
5459 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
5460 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
5461 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
5463 /* Set video360 settings to their defaults for just-created player.
5466 player->is_360_feature_enabled = FALSE;
5467 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
5468 LOGI("spherical feature info: %d", enabled);
5470 player->is_360_feature_enabled = TRUE;
5472 LOGE("failed to get spherical feature info");
5475 player->is_content_spherical = FALSE;
5476 player->is_video360_enabled = TRUE;
5477 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
5478 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
5479 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
5480 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
5481 player->video360_zoom = 1.0f;
5482 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
5483 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
5485 __mmplayer_initialize_video_roi(player);
5487 /* set player state to null */
5488 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5489 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
5491 return MM_ERROR_NONE;
5495 g_mutex_clear(&player->fsink_lock);
5497 /* free update tag lock */
5498 g_mutex_clear(&player->update_tag_lock);
5500 g_queue_free(player->bus_msg_q);
5502 /* free next play thread */
5503 if (player->next_play_thread) {
5504 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
5505 player->next_play_thread_exit = TRUE;
5506 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
5507 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
5509 g_thread_join(player->next_play_thread);
5510 player->next_play_thread = NULL;
5512 g_mutex_clear(&player->next_play_thread_mutex);
5513 g_cond_clear(&player->next_play_thread_cond);
5516 /* release attributes */
5517 _mmplayer_deconstruct_attribute(handle);
5525 __mmplayer_init_gstreamer(mm_player_t* player)
5527 static gboolean initialized = FALSE;
5528 static const int max_argc = 50;
5530 gchar** argv = NULL;
5531 gchar** argv2 = NULL;
5537 LOGD("gstreamer already initialized.\n");
5542 argc = malloc(sizeof(int));
5543 argv = malloc(sizeof(gchar*) * max_argc);
5544 argv2 = malloc(sizeof(gchar*) * max_argc);
5546 if (!argc || !argv || !argv2)
5549 memset(argv, 0, sizeof(gchar*) * max_argc);
5550 memset(argv2, 0, sizeof(gchar*) * max_argc);
5554 argv[0] = g_strdup("mmplayer");
5557 for (i = 0; i < 5; i++) {
5558 /* FIXIT : num of param is now fixed to 5. make it dynamic */
5559 if (strlen(player->ini.gst_param[i]) > 0) {
5560 argv[*argc] = g_strdup(player->ini.gst_param[i]);
5565 /* we would not do fork for scanning plugins */
5566 argv[*argc] = g_strdup("--gst-disable-registry-fork");
5569 /* check disable registry scan */
5570 if (player->ini.skip_rescan) {
5571 argv[*argc] = g_strdup("--gst-disable-registry-update");
5575 /* check disable segtrap */
5576 if (player->ini.disable_segtrap) {
5577 argv[*argc] = g_strdup("--gst-disable-segtrap");
5581 LOGD("initializing gstreamer with following parameter\n");
5582 LOGD("argc : %d\n", *argc);
5585 for (i = 0; i < arg_count; i++) {
5587 LOGD("argv[%d] : %s\n", i, argv2[i]);
5590 /* initializing gstreamer */
5591 if (!gst_init_check(argc, &argv, &err)) {
5592 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
5599 for (i = 0; i < arg_count; i++) {
5600 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
5601 MMPLAYER_FREEIF(argv2[i]);
5604 MMPLAYER_FREEIF(argv);
5605 MMPLAYER_FREEIF(argv2);
5606 MMPLAYER_FREEIF(argc);
5616 for (i = 0; i < arg_count; i++) {
5617 LOGD("free[%d] : %s\n", i, argv2[i]);
5618 MMPLAYER_FREEIF(argv2[i]);
5621 MMPLAYER_FREEIF(argv);
5622 MMPLAYER_FREEIF(argv2);
5623 MMPLAYER_FREEIF(argc);
5629 __mmplayer_destroy_streaming_ext(mm_player_t* player)
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5633 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
5634 _mmplayer_destroy_pd_downloader((MMHandleType)player);
5635 MMPLAYER_FREEIF(player->pd_file_save_path);
5638 return MM_ERROR_NONE;
5642 __mmplayer_check_async_state_transition(mm_player_t* player)
5644 GstState element_state = GST_STATE_VOID_PENDING;
5645 GstState element_pending_state = GST_STATE_VOID_PENDING;
5646 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5647 GstElement * element = NULL;
5648 gboolean async = FALSE;
5650 /* check player handle */
5651 MMPLAYER_RETURN_IF_FAIL(player &&
5653 player->pipeline->mainbin &&
5654 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5657 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5659 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5660 LOGD("don't need to check the pipeline state");
5664 MMPLAYER_PRINT_STATE(player);
5666 /* wait for state transition */
5667 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5668 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
5670 if (ret == GST_STATE_CHANGE_FAILURE) {
5671 LOGE(" [%s] state : %s pending : %s \n",
5672 GST_ELEMENT_NAME(element),
5673 gst_element_state_get_name(element_state),
5674 gst_element_state_get_name(element_pending_state));
5676 /* dump state of all element */
5677 __mmplayer_dump_pipeline_state(player);
5682 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
5687 _mmplayer_destroy(MMHandleType handle)
5689 mm_player_t* player = MM_PLAYER_CAST(handle);
5693 /* check player handle */
5694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5696 /* destroy can called at anytime */
5697 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5699 /* check async state transition */
5700 __mmplayer_check_async_state_transition(player);
5702 __mmplayer_destroy_streaming_ext(player);
5704 /* release next play thread */
5705 if (player->next_play_thread) {
5706 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
5707 player->next_play_thread_exit = TRUE;
5708 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
5709 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
5711 LOGD("waitting for next play thread exit\n");
5712 g_thread_join(player->next_play_thread);
5713 g_mutex_clear(&player->next_play_thread_mutex);
5714 g_cond_clear(&player->next_play_thread_cond);
5715 LOGD("next play thread released\n");
5718 _mmplayer_release_video_capture(player);
5720 /* de-initialize resource manager */
5721 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
5722 player->resource_manager))
5723 LOGE("failed to deinitialize resource manager\n");
5725 /* release pipeline */
5726 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
5727 LOGE("failed to destory pipeline\n");
5728 return MM_ERROR_PLAYER_INTERNAL;
5731 g_queue_free(player->bus_msg_q);
5733 /* release subtitle info lock and cond */
5734 g_mutex_clear(&player->subtitle_info_mutex);
5735 g_cond_clear(&player->subtitle_info_cond);
5737 __mmplayer_release_dump_list(player->dump_list);
5739 /* release miscellaneous information */
5740 __mmplayer_release_misc(player);
5742 /* release miscellaneous information.
5743 these info needs to be released after pipeline is destroyed. */
5744 __mmplayer_release_misc_post(player);
5746 /* release attributes */
5747 _mmplayer_deconstruct_attribute(handle);
5750 g_mutex_clear(&player->fsink_lock);
5753 g_mutex_clear(&player->update_tag_lock);
5755 /* release video bo lock and cond */
5756 g_mutex_clear(&player->video_bo_mutex);
5757 g_cond_clear(&player->video_bo_cond);
5759 /* release media stream callback lock */
5760 g_mutex_clear(&player->media_stream_cb_lock);
5764 return MM_ERROR_NONE;
5768 __mmplayer_realize_streaming_ext(mm_player_t* player)
5770 int ret = MM_ERROR_NONE;
5773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5775 if (MMPLAYER_IS_HTTP_PD(player)) {
5776 gboolean bret = FALSE;
5778 player->pd_downloader = _mmplayer_create_pd_downloader();
5779 if (!player->pd_downloader) {
5780 LOGE("Unable to create PD Downloader...");
5781 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
5784 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
5786 if (FALSE == bret) {
5787 LOGE("Unable to create PD Downloader...");
5788 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
5797 _mmplayer_realize(MMHandleType hplayer)
5799 mm_player_t* player = (mm_player_t*)hplayer;
5802 MMHandleType attrs = 0;
5803 int ret = MM_ERROR_NONE;
5807 /* check player handle */
5808 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
5810 /* check current state */
5811 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5813 attrs = MMPLAYER_GET_ATTRS(player);
5815 LOGE("fail to get attributes.\n");
5816 return MM_ERROR_PLAYER_INTERNAL;
5818 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5819 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5821 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5822 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
5824 if (ret != MM_ERROR_NONE) {
5825 LOGE("failed to parse profile\n");
5830 if (uri && (strstr(uri, "es_buff://"))) {
5831 if (strstr(uri, "es_buff://push_mode"))
5832 player->es_player_push_mode = TRUE;
5834 player->es_player_push_mode = FALSE;
5837 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5838 LOGW("mms protocol is not supported format.\n");
5839 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5842 if (MMPLAYER_IS_HTTP_PD(player))
5843 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
5844 else if (MMPLAYER_IS_STREAMING(player))
5845 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5847 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5849 player->smooth_streaming = FALSE;
5850 player->videodec_linked = 0;
5851 player->videosink_linked = 0;
5852 player->audiodec_linked = 0;
5853 player->audiosink_linked = 0;
5854 player->textsink_linked = 0;
5855 player->is_external_subtitle_present = FALSE;
5856 player->is_external_subtitle_added_now = FALSE;
5857 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5858 player->video360_metadata.is_spherical = -1;
5859 player->is_openal_plugin_used = FALSE;
5860 player->demux_pad_index = 0;
5861 player->subtitle_language_list = NULL;
5862 player->is_subtitle_force_drop = FALSE;
5863 player->last_multiwin_status = FALSE;
5865 __mmplayer_track_initialize(player);
5866 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5868 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5869 player->streamer = __mm_player_streaming_create();
5870 __mm_player_streaming_initialize(player->streamer);
5873 /* realize pipeline */
5874 ret = __mmplayer_gst_realize(player);
5875 if (ret != MM_ERROR_NONE)
5876 LOGE("fail to realize the player.\n");
5878 ret = __mmplayer_realize_streaming_ext(player);
5880 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5888 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
5891 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5893 /* destroy can called at anytime */
5894 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
5895 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
5898 return MM_ERROR_NONE;
5902 _mmplayer_unrealize(MMHandleType hplayer)
5904 mm_player_t* player = (mm_player_t*)hplayer;
5905 int ret = MM_ERROR_NONE;
5909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5911 MMPLAYER_CMD_UNLOCK(player);
5912 /* destroy the gst bus msg thread which is created during realize.
5913 this funct have to be called before getting cmd lock. */
5914 __mmplayer_bus_msg_thread_destroy(player);
5915 MMPLAYER_CMD_LOCK(player);
5917 /* check current state */
5918 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5920 /* check async state transition */
5921 __mmplayer_check_async_state_transition(player);
5923 __mmplayer_unrealize_streaming_ext(player);
5925 /* unrealize pipeline */
5926 ret = __mmplayer_gst_unrealize(player);
5928 /* set asm stop if success */
5929 if (MM_ERROR_NONE == ret) {
5930 if (!player->interrupted_by_resource) {
5931 if (player->video_decoder_resource != NULL) {
5932 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5933 player->video_decoder_resource);
5934 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5935 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
5937 player->video_decoder_resource = NULL;
5940 if (player->video_overlay_resource != NULL) {
5941 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5942 player->video_overlay_resource);
5943 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5944 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
5946 player->video_overlay_resource = NULL;
5949 ret = mm_resource_manager_commit(player->resource_manager);
5950 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5951 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
5954 LOGE("failed and don't change asm state to stop");
5962 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5964 mm_player_t* player = (mm_player_t*)hplayer;
5966 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5968 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5972 _mmplayer_get_state(MMHandleType hplayer, int* state)
5974 mm_player_t *player = (mm_player_t*)hplayer;
5976 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5978 *state = MMPLAYER_CURRENT_STATE(player);
5980 return MM_ERROR_NONE;
5985 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5987 mm_player_t* player = (mm_player_t*) hplayer;
5988 GstElement* vol_element = NULL;
5993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5995 LOGD("volume [L]=%f:[R]=%f\n",
5996 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5998 /* invalid factor range or not */
5999 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
6000 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
6001 LOGE("Invalid factor!(valid factor:0~1.0)\n");
6002 return MM_ERROR_INVALID_ARGUMENT;
6006 /* not support to set other value into each channel */
6007 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
6008 return MM_ERROR_INVALID_ARGUMENT;
6010 /* Save volume to handle. Currently the first array element will be saved. */
6011 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
6013 /* check pipeline handle */
6014 if (!player->pipeline || !player->pipeline->audiobin) {
6015 LOGD("audiobin is not created yet\n");
6016 LOGD("but, current stored volume will be set when it's created.\n");
6018 /* NOTE : stored volume will be used in create_audiobin
6019 * returning MM_ERROR_NONE here makes application to able to
6020 * set volume at anytime.
6022 return MM_ERROR_NONE;
6025 /* setting volume to volume element */
6026 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6029 LOGD("volume is set [%f]\n", player->sound.volume);
6030 g_object_set(vol_element, "volume", player->sound.volume, NULL);
6035 return MM_ERROR_NONE;
6040 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
6042 mm_player_t* player = (mm_player_t*) hplayer;
6047 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6048 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
6050 /* returning stored volume */
6051 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
6052 volume->level[i] = player->sound.volume;
6056 return MM_ERROR_NONE;
6060 _mmplayer_set_mute(MMHandleType hplayer, int mute)
6062 mm_player_t* player = (mm_player_t*) hplayer;
6063 GstElement* vol_element = NULL;
6067 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6069 /* mute value shoud 0 or 1 */
6070 if (mute != 0 && mute != 1) {
6071 LOGE("bad mute value\n");
6073 /* FIXIT : definitly, we need _BAD_PARAM error code */
6074 return MM_ERROR_INVALID_ARGUMENT;
6077 player->sound.mute = mute;
6079 /* just hold mute value if pipeline is not ready */
6080 if (!player->pipeline || !player->pipeline->audiobin) {
6081 LOGD("pipeline is not ready. holding mute value\n");
6082 return MM_ERROR_NONE;
6085 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6087 /* NOTE : volume will only created when the bt is enabled */
6089 LOGD("mute : %d\n", mute);
6090 g_object_set(vol_element, "mute", mute, NULL);
6092 LOGD("volume elemnet is not created. using volume in audiosink\n");
6096 return MM_ERROR_NONE;
6100 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
6102 mm_player_t* player = (mm_player_t*) hplayer;
6106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6107 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
6109 /* just hold mute value if pipeline is not ready */
6110 if (!player->pipeline || !player->pipeline->audiobin) {
6111 LOGD("pipeline is not ready. returning stored value\n");
6112 *pmute = player->sound.mute;
6113 return MM_ERROR_NONE;
6116 *pmute = player->sound.mute;
6120 return MM_ERROR_NONE;
6124 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
6126 mm_player_t* player = (mm_player_t*) hplayer;
6130 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6132 player->video_stream_changed_cb = callback;
6133 player->video_stream_changed_cb_user_param = user_param;
6134 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
6138 return MM_ERROR_NONE;
6142 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
6144 mm_player_t* player = (mm_player_t*) hplayer;
6148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6150 player->audio_stream_changed_cb = callback;
6151 player->audio_stream_changed_cb_user_param = user_param;
6152 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
6156 return MM_ERROR_NONE;
6160 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
6162 mm_player_t* player = (mm_player_t*) hplayer;
6166 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6168 player->audio_stream_render_cb_ex = callback;
6169 player->audio_stream_cb_user_param = user_param;
6170 player->audio_stream_sink_sync = sync;
6171 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);
6175 return MM_ERROR_NONE;
6179 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
6181 mm_player_t* player = (mm_player_t*) hplayer;
6185 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6187 if (callback && !player->bufmgr)
6188 player->bufmgr = tbm_bufmgr_init(-1);
6190 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
6191 player->video_stream_cb = callback;
6192 player->video_stream_cb_user_param = user_param;
6194 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
6198 return MM_ERROR_NONE;
6202 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
6204 mm_player_t* player = (mm_player_t*) hplayer;
6208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6210 player->audio_stream_cb = callback;
6211 player->audio_stream_cb_user_param = user_param;
6212 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
6216 return MM_ERROR_NONE;
6220 __mmplayer_start_streaming_ext(mm_player_t *player)
6222 gint ret = MM_ERROR_NONE;
6225 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6227 if (MMPLAYER_IS_HTTP_PD(player)) {
6228 if (!player->pd_downloader) {
6229 ret = __mmplayer_realize_streaming_ext(player);
6231 if (ret != MM_ERROR_NONE) {
6232 LOGE("failed to realize streaming ext\n");
6237 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6238 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
6240 LOGE("ERROR while starting PD...\n");
6241 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6243 ret = MM_ERROR_NONE;
6252 _mmplayer_start(MMHandleType hplayer)
6254 mm_player_t* player = (mm_player_t*) hplayer;
6255 gint ret = MM_ERROR_NONE;
6259 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6261 /* check current state */
6262 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
6264 /* PD - start streaming */
6265 ret = __mmplayer_start_streaming_ext(player);
6266 if (ret != MM_ERROR_NONE) {
6267 LOGE("failed to start streaming ext 0x%X", ret);
6271 /* start pipeline */
6272 ret = __mmplayer_gst_start(player);
6273 if (ret != MM_ERROR_NONE)
6274 LOGE("failed to start player.\n");
6276 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
6277 LOGD("force playing start even during buffering");
6278 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
6286 /* NOTE: post "not supported codec message" to application
6287 * when one codec is not found during AUTOPLUGGING in MSL.
6288 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
6289 * And, if any codec is not found, don't send message here.
6290 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
6293 __mmplayer_handle_missed_plugin(mm_player_t* player)
6295 MMMessageParamType msg_param;
6296 memset(&msg_param, 0, sizeof(MMMessageParamType));
6297 gboolean post_msg_direct = FALSE;
6301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6303 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
6304 player->not_supported_codec, player->can_support_codec);
6306 if (player->not_found_demuxer) {
6307 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6308 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
6310 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6311 MMPLAYER_FREEIF(msg_param.data);
6313 return MM_ERROR_NONE;
6316 if (player->not_supported_codec) {
6317 if (player->can_support_codec) {
6318 // There is one codec to play
6319 post_msg_direct = TRUE;
6321 if (player->pipeline->audiobin) // Some content has only PCM data in container.
6322 post_msg_direct = TRUE;
6325 if (post_msg_direct) {
6326 MMMessageParamType msg_param;
6327 memset(&msg_param, 0, sizeof(MMMessageParamType));
6329 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
6330 LOGW("not found AUDIO codec, posting error code to application.\n");
6332 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6333 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6334 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
6335 LOGW("not found VIDEO codec, posting error code to application.\n");
6337 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
6338 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
6341 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6343 MMPLAYER_FREEIF(msg_param.data);
6345 return MM_ERROR_NONE;
6347 // no any supported codec case
6348 LOGW("not found any codec, posting error code to application.\n");
6350 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
6351 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6352 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6354 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6355 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
6358 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6360 MMPLAYER_FREEIF(msg_param.data);
6366 return MM_ERROR_NONE;
6369 static void __mmplayer_check_pipeline(mm_player_t* player)
6371 GstState element_state = GST_STATE_VOID_PENDING;
6372 GstState element_pending_state = GST_STATE_VOID_PENDING;
6374 int ret = MM_ERROR_NONE;
6376 if (player->gapless.reconfigure) {
6377 LOGW("pipeline is under construction.\n");
6379 MMPLAYER_PLAYBACK_LOCK(player);
6380 MMPLAYER_PLAYBACK_UNLOCK(player);
6382 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6384 /* wait for state transition */
6385 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
6387 if (ret == GST_STATE_CHANGE_FAILURE)
6388 LOGE("failed to change pipeline state within %d sec\n", timeout);
6392 /* NOTE : it should be able to call 'stop' anytime*/
6394 _mmplayer_stop(MMHandleType hplayer)
6396 mm_player_t* player = (mm_player_t*)hplayer;
6397 int ret = MM_ERROR_NONE;
6401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6403 /* check current state */
6404 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
6406 /* check pipline building state */
6407 __mmplayer_check_pipeline(player);
6408 __mmplayer_reset_gapless_state(player);
6410 /* NOTE : application should not wait for EOS after calling STOP */
6411 __mmplayer_cancel_eos_timer(player);
6413 __mmplayer_unrealize_streaming_ext(player);
6416 player->seek_state = MMPLAYER_SEEK_NONE;
6419 ret = __mmplayer_gst_stop(player);
6421 if (ret != MM_ERROR_NONE)
6422 LOGE("failed to stop player.\n");
6430 _mmplayer_pause(MMHandleType hplayer)
6432 mm_player_t* player = (mm_player_t*)hplayer;
6433 gint64 pos_nsec = 0;
6434 gboolean async = FALSE;
6435 gint ret = MM_ERROR_NONE;
6439 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6441 /* check current state */
6442 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
6444 /* check pipline building state */
6445 __mmplayer_check_pipeline(player);
6447 switch (MMPLAYER_CURRENT_STATE(player)) {
6448 case MM_PLAYER_STATE_READY:
6450 /* check prepare async or not.
6451 * In the case of streaming playback, it's recommned to avoid blocking wait.
6453 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6454 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
6456 /* Changing back sync of rtspsrc to async */
6457 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
6458 LOGD("async prepare working mode for rtsp");
6464 case MM_PLAYER_STATE_PLAYING:
6466 /* NOTE : store current point to overcome some bad operation
6467 *(returning zero when getting current position in paused state) of some
6470 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
6471 LOGW("getting current position failed in paused\n");
6473 player->last_position = pos_nsec;
6475 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
6476 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
6477 This causes problem is position calculation during normal pause resume scenarios also.
6478 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
6479 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
6480 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
6481 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
6487 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6488 LOGD("doing async pause in case of ms buff src");
6492 /* pause pipeline */
6493 ret = __mmplayer_gst_pause(player, async);
6495 if (ret != MM_ERROR_NONE)
6496 LOGE("failed to pause player. ret : 0x%x\n", ret);
6498 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
6499 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
6500 LOGE("failed to update display_rotation");
6508 /* in case of streaming, pause could take long time.*/
6510 _mmplayer_abort_pause(MMHandleType hplayer)
6512 mm_player_t* player = (mm_player_t*)hplayer;
6513 int ret = MM_ERROR_NONE;
6517 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6519 player->pipeline->mainbin,
6520 MM_ERROR_PLAYER_NOT_INITIALIZED);
6522 LOGD("set the pipeline state to READY");
6524 /* set state to READY */
6525 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
6526 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
6527 if (ret != MM_ERROR_NONE) {
6528 LOGE("fail to change state to READY");
6529 return MM_ERROR_PLAYER_INTERNAL;
6532 LOGD("succeeded in changing state to READY");
6538 _mmplayer_resume(MMHandleType hplayer)
6540 mm_player_t* player = (mm_player_t*)hplayer;
6541 int ret = MM_ERROR_NONE;
6542 gboolean async = FALSE;
6546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6548 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
6549 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
6550 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
6554 /* Changing back sync mode rtspsrc to async */
6555 LOGD("async resume for rtsp case");
6559 /* check current state */
6560 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
6562 ret = __mmplayer_gst_resume(player, async);
6563 if (ret != MM_ERROR_NONE)
6564 LOGE("failed to resume player.\n");
6566 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
6567 LOGD("force resume even during buffering");
6568 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
6577 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
6579 mm_player_t* player = (mm_player_t*)hplayer;
6580 gint64 pos_nsec = 0;
6581 int ret = MM_ERROR_NONE;
6583 signed long long start = 0, stop = 0;
6584 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6588 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
6590 /* The sound of video is not supported under 0.0 and over 2.0. */
6591 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
6592 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
6595 _mmplayer_set_mute(hplayer, mute);
6597 if (player->playback_rate == rate)
6598 return MM_ERROR_NONE;
6600 /* If the position is reached at start potion during fast backward, EOS is posted.
6601 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
6603 player->playback_rate = rate;
6605 current_state = MMPLAYER_CURRENT_STATE(player);
6607 if (current_state != MM_PLAYER_STATE_PAUSED)
6608 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
6610 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
6612 if ((current_state == MM_PLAYER_STATE_PAUSED)
6613 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
6614 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
6615 pos_nsec = player->last_position;
6620 stop = GST_CLOCK_TIME_NONE;
6622 start = GST_CLOCK_TIME_NONE;
6626 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
6627 player->playback_rate,
6629 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
6630 GST_SEEK_TYPE_SET, start,
6631 GST_SEEK_TYPE_SET, stop)) {
6632 LOGE("failed to set speed playback\n");
6633 return MM_ERROR_PLAYER_SEEK;
6636 LOGD("succeeded to set speed playback as %0.1f\n", rate);
6640 return MM_ERROR_NONE;;
6644 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
6646 mm_player_t* player = (mm_player_t*)hplayer;
6647 int ret = MM_ERROR_NONE;
6651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6653 /* check pipline building state */
6654 __mmplayer_check_pipeline(player);
6656 ret = __mmplayer_gst_set_position(player, position, FALSE);
6664 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
6666 mm_player_t* player = (mm_player_t*)hplayer;
6667 int ret = MM_ERROR_NONE;
6669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6671 ret = __mmplayer_gst_get_position(player, position);
6677 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
6679 mm_player_t* player = (mm_player_t*)hplayer;
6680 int ret = MM_ERROR_NONE;
6682 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6683 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
6685 *duration = player->duration;
6690 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
6692 mm_player_t* player = (mm_player_t*)hplayer;
6693 int ret = MM_ERROR_NONE;
6695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6697 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
6703 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
6705 mm_player_t* player = (mm_player_t*)hplayer;
6706 int ret = MM_ERROR_NONE;
6710 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6712 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
6720 __mmplayer_is_midi_type(gchar* str_caps)
6722 if ((g_strrstr(str_caps, "audio/midi")) ||
6723 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
6724 (g_strrstr(str_caps, "application/x-smaf")) ||
6725 (g_strrstr(str_caps, "audio/x-imelody")) ||
6726 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
6727 (g_strrstr(str_caps, "audio/xmf")) ||
6728 (g_strrstr(str_caps, "audio/mxmf"))) {
6737 __mmplayer_is_only_mp3_type(gchar *str_caps)
6739 if (g_strrstr(str_caps, "application/x-id3") ||
6740 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
6746 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
6748 GstStructure* caps_structure = NULL;
6749 gint samplerate = 0;
6753 MMPLAYER_RETURN_IF_FAIL(player && caps);
6755 caps_structure = gst_caps_get_structure(caps, 0);
6757 /* set stream information */
6758 gst_structure_get_int(caps_structure, "rate", &samplerate);
6759 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
6761 gst_structure_get_int(caps_structure, "channels", &channels);
6762 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
6764 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
6768 __mmplayer_update_content_type_info(mm_player_t* player)
6771 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6773 if (__mmplayer_is_midi_type(player->type)) {
6774 player->bypass_audio_effect = TRUE;
6775 } else if (g_strrstr(player->type, "application/x-hls")) {
6776 /* If it can't know exact type when it parses uri because of redirection case,
6777 * it will be fixed by typefinder or when doing autoplugging.
6779 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6780 if (player->streamer) {
6781 player->streamer->is_adaptive_streaming = TRUE;
6782 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6783 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
6785 } else if (g_strrstr(player->type, "application/dash+xml")) {
6786 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6787 if (player->streamer) {
6788 player->streamer->is_adaptive_streaming = TRUE;
6789 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6793 LOGD("uri type : %d", player->profile.uri_type);
6798 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
6799 GstCaps *caps, gpointer data)
6801 mm_player_t* player = (mm_player_t*)data;
6806 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6808 /* store type string */
6809 MMPLAYER_FREEIF(player->type);
6810 player->type = gst_caps_to_string(caps);
6812 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
6813 player, player->type, probability, gst_caps_get_size(caps));
6816 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6817 (g_strrstr(player->type, "audio/x-raw-int"))) {
6818 LOGE("not support media format\n");
6820 if (player->msg_posted == FALSE) {
6821 MMMessageParamType msg_param;
6822 memset(&msg_param, 0, sizeof(MMMessageParamType));
6824 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6825 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6827 /* don't post more if one was sent already */
6828 player->msg_posted = TRUE;
6833 __mmplayer_update_content_type_info(player);
6835 pad = gst_element_get_static_pad(tf, "src");
6837 LOGE("fail to get typefind src pad.\n");
6841 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
6842 gboolean async = FALSE;
6843 LOGE("failed to autoplug %s\n", player->type);
6845 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6847 if (async && player->msg_posted == FALSE)
6848 __mmplayer_handle_missed_plugin(player);
6854 gst_object_unref(GST_OBJECT(pad));
6862 __mmplayer_create_decodebin(mm_player_t* player)
6864 GstElement *decodebin = NULL;
6868 /* create decodebin */
6869 decodebin = gst_element_factory_make("decodebin", NULL);
6872 LOGE("fail to create decodebin\n");
6876 /* raw pad handling signal */
6877 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6878 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
6880 /* no-more-pad pad handling signal */
6881 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6882 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6884 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6885 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6887 /* This signal is emitted when a pad for which there is no further possible
6888 decoding is added to the decodebin.*/
6889 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6890 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6892 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6893 before looking for any elements that can handle that stream.*/
6894 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6895 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6897 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6898 before looking for any elements that can handle that stream.*/
6899 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6900 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
6902 /* This signal is emitted once decodebin has finished decoding all the data.*/
6903 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6904 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6906 /* This signal is emitted when a element is added to the bin.*/
6907 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6908 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
6915 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
6917 MMPlayerGstElement* mainbin = NULL;
6918 GstElement* decodebin = NULL;
6919 GstElement* queue2 = NULL;
6920 GstPad* sinkpad = NULL;
6921 GstPad* qsrcpad = NULL;
6922 gint64 dur_bytes = 0L;
6924 guint max_buffer_size_bytes = 0;
6925 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6928 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6930 mainbin = player->pipeline->mainbin;
6932 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
6933 (MMPLAYER_IS_HTTP_STREAMING(player))) {
6934 LOGD("creating http streaming buffering queue(queue2)\n");
6936 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6937 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
6939 queue2 = gst_element_factory_make("queue2", "queue2");
6941 LOGE("failed to create buffering queue element\n");
6945 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6946 LOGE("failed to add buffering queue\n");
6950 sinkpad = gst_element_get_static_pad(queue2, "sink");
6951 qsrcpad = gst_element_get_static_pad(queue2, "src");
6953 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6954 LOGE("failed to link buffering queue");
6958 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6959 LOGE("fail to get duration");
6961 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6963 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6965 if (dur_bytes > 0) {
6966 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
6967 type = MUXED_BUFFER_TYPE_FILE;
6969 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6970 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6976 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
6977 * skip the pull mode(file or ring buffering) setting. */
6978 if (!g_strrstr(player->type, "video/mpegts")) {
6979 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
6980 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
6982 __mm_player_streaming_set_queue2(player->streamer,
6985 max_buffer_size_bytes,
6986 player->ini.http_buffering_time,
6987 1.0, /* no meaning */
6988 player->ini.http_buffering_limit, /* no meaning */
6990 player->http_file_buffering_path,
6991 (guint64)dur_bytes);
6994 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
6995 LOGE("failed to sync queue2 state with parent\n");
7001 gst_object_unref(GST_OBJECT(sinkpad));
7003 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
7004 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
7008 /* create decodebin */
7009 decodebin = __mmplayer_create_decodebin(player);
7012 LOGE("can not create autoplug element\n");
7016 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
7017 LOGE("failed to add decodebin\n");
7021 /* to force caps on the decodebin element and avoid reparsing stuff by
7022 * typefind. It also avoids a deadlock in the way typefind activates pads in
7023 * the state change */
7024 g_object_set(decodebin, "sink-caps", caps, NULL);
7026 sinkpad = gst_element_get_static_pad(decodebin, "sink");
7028 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
7029 LOGE("failed to link decodebin\n");
7033 gst_object_unref(GST_OBJECT(sinkpad));
7035 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
7036 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
7038 /* set decodebin property about buffer in streaming playback. *
7039 * in case of HLS/DASH, it does not need to have big buffer *
7040 * because it is kind of adaptive streaming. */
7041 if (!MMPLAYER_IS_HTTP_PD(player) &&
7042 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
7043 gdouble high_percent = 0.0;
7045 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
7046 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
7048 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
7049 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
7051 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
7052 "high-percent", (gint)high_percent,
7053 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
7054 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
7055 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
7056 "max-size-buffers", 0, NULL); // disable or automatic
7059 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
7060 LOGE("failed to sync decodebin state with parent\n");
7071 gst_object_unref(GST_OBJECT(sinkpad));
7074 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
7075 * You need to explicitly set elements to the NULL state before
7076 * dropping the final reference, to allow them to clean up.
7078 gst_element_set_state(queue2, GST_STATE_NULL);
7080 /* And, it still has a parent "player".
7081 * You need to let the parent manage the object instead of unreffing the object directly.
7083 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
7084 gst_object_unref(queue2);
7089 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
7090 * You need to explicitly set elements to the NULL state before
7091 * dropping the final reference, to allow them to clean up.
7093 gst_element_set_state(decodebin, GST_STATE_NULL);
7095 /* And, it still has a parent "player".
7096 * You need to let the parent manage the object instead of unreffing the object directly.
7099 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
7100 gst_object_unref(decodebin);
7108 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
7112 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7113 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
7115 LOGD("class : %s, mime : %s \n", factory_class, mime);
7117 /* add missing plugin */
7118 /* NOTE : msl should check missing plugin for image mime type.
7119 * Some motion jpeg clips can have playable audio track.
7120 * So, msl have to play audio after displaying popup written video format not supported.
7122 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
7123 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
7124 LOGD("not found demuxer\n");
7125 player->not_found_demuxer = TRUE;
7126 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
7132 if (!g_strrstr(factory_class, "Demuxer")) {
7133 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
7134 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
7135 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
7137 /* check that clip have multi tracks or not */
7138 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
7139 LOGD("video plugin is already linked\n");
7141 LOGW("add VIDEO to missing plugin\n");
7142 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
7143 player->unlinked_video_mime = g_strdup_printf("%s", mime);
7145 } else if (g_str_has_prefix(mime, "audio")) {
7146 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
7147 LOGD("audio plugin is already linked\n");
7149 LOGW("add AUDIO to missing plugin\n");
7150 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
7151 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
7159 return MM_ERROR_NONE;
7164 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
7166 mm_player_t* player = (mm_player_t*)data;
7170 MMPLAYER_RETURN_IF_FAIL(player);
7172 /* remove fakesink. */
7173 if (!__mmplayer_gst_remove_fakesink(player,
7174 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
7175 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
7176 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
7177 * source element are not same. To overcome this situation, this function will called
7178 * several places and several times. Therefore, this is not an error case.
7183 LOGD("[handle: %p] pipeline has completely constructed", player);
7185 if ((player->ini.async_start) &&
7186 (player->msg_posted == FALSE) &&
7187 (player->cmd >= MMPLAYER_COMMAND_START))
7188 __mmplayer_handle_missed_plugin(player);
7190 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
7194 __mmplayer_check_profile(void)
7197 static int profile_tv = -1;
7199 if (__builtin_expect(profile_tv != -1, 1))
7202 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
7203 switch (*profileName) {
7218 __mmplayer_get_next_uri(mm_player_t *player)
7220 MMPlayerParseProfile profile;
7222 guint num_of_list = 0;
7225 num_of_list = g_list_length(player->uri_info.uri_list);
7226 uri_idx = player->uri_info.uri_idx;
7228 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
7229 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
7230 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
7232 LOGW("next uri does not exist");
7236 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
7237 LOGE("failed to parse profile");
7241 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
7242 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
7243 LOGW("uri type is not supported(%d)", profile.uri_type);
7247 LOGD("success to find next uri %d", uri_idx);
7251 if (uri_idx == num_of_list) {
7252 LOGE("failed to find next uri");
7256 player->uri_info.uri_idx = uri_idx;
7257 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
7259 if (mmf_attrs_commit(player->attrs)) {
7260 LOGE("failed to commit");
7264 SECURE_LOGD("next playback uri: %s", uri);
7269 __mmplayer_verify_next_play_path(mm_player_t *player)
7271 #define REPEAT_COUNT_INFINITELY -1
7272 #define REPEAT_COUNT_MIN 2
7274 MMHandleType attrs = 0;
7275 gint mode = MM_PLAYER_PD_MODE_NONE;
7279 guint num_of_list = 0;
7280 int profile_tv = -1;
7284 LOGD("checking for next play option");
7286 if (player->pipeline->textbin) {
7287 LOGE("subtitle path is enabled. gapless play is not supported.\n");
7291 attrs = MMPLAYER_GET_ATTRS(player);
7293 LOGE("fail to get attributes.\n");
7297 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
7299 /* gapless playback is not supported in case of video at TV profile. */
7300 profile_tv = __mmplayer_check_profile();
7301 if (profile_tv && video) {
7302 LOGW("not support video gapless playback");
7306 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
7313 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
7314 LOGE("failed to get play count");
7316 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
7317 LOGE("failed to get gapless mode");
7319 /* check repeat count in case of audio */
7321 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
7322 LOGW("gapless is disabled");
7326 num_of_list = g_list_length(player->uri_info.uri_list);
7328 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
7330 if (num_of_list == 0) {
7331 /* audio looping path */
7332 if (count >= REPEAT_COUNT_MIN) {
7333 /* decrease play count */
7334 /* we succeeded to rewind. update play count and then wait for next EOS */
7337 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
7339 /* commit attribute */
7340 if (mmf_attrs_commit(attrs))
7341 LOGE("failed to commit attribute");
7342 } else if (count != REPEAT_COUNT_INFINITELY) {
7343 LOGD("there is no next uri and no repeat");
7347 LOGD("looping cnt %d", count);
7349 /* gapless playback path */
7350 if (!__mmplayer_get_next_uri(player)) {
7351 LOGE("failed to get next uri");
7359 LOGE("unable to play next path. EOS will be posted soon");
7364 __mmplayer_initialize_next_play(mm_player_t *player)
7370 player->smooth_streaming = FALSE;
7371 player->videodec_linked = 0;
7372 player->audiodec_linked = 0;
7373 player->videosink_linked = 0;
7374 player->audiosink_linked = 0;
7375 player->textsink_linked = 0;
7376 player->is_external_subtitle_present = FALSE;
7377 player->is_external_subtitle_added_now = FALSE;
7378 player->not_supported_codec = MISSING_PLUGIN_NONE;
7379 player->can_support_codec = FOUND_PLUGIN_NONE;
7380 player->pending_seek.is_pending = FALSE;
7381 player->pending_seek.pos = 0;
7382 player->msg_posted = FALSE;
7383 player->has_many_types = FALSE;
7384 player->no_more_pad = FALSE;
7385 player->not_found_demuxer = 0;
7386 player->seek_state = MMPLAYER_SEEK_NONE;
7387 player->max_audio_channels = 0;
7388 player->is_subtitle_force_drop = FALSE;
7389 player->play_subtitle = FALSE;
7390 player->adjust_subtitle_pos = 0;
7392 player->total_bitrate = 0;
7393 player->total_maximum_bitrate = 0;
7395 __mmplayer_track_initialize(player);
7396 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7398 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7399 player->bitrate[i] = 0;
7400 player->maximum_bitrate[i] = 0;
7403 if (player->v_stream_caps) {
7404 gst_caps_unref(player->v_stream_caps);
7405 player->v_stream_caps = NULL;
7408 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7410 /* clean found parsers */
7411 if (player->parsers) {
7412 GList *parsers = player->parsers;
7413 for (; parsers; parsers = g_list_next(parsers)) {
7414 gchar *name = parsers->data;
7415 MMPLAYER_FREEIF(name);
7417 g_list_free(player->parsers);
7418 player->parsers = NULL;
7421 /* clean found audio decoders */
7422 if (player->audio_decoders) {
7423 GList *a_dec = player->audio_decoders;
7424 for (; a_dec; a_dec = g_list_next(a_dec)) {
7425 gchar *name = a_dec->data;
7426 MMPLAYER_FREEIF(name);
7428 g_list_free(player->audio_decoders);
7429 player->audio_decoders = NULL;
7436 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
7438 MMPlayerGstElement *mainbin = NULL;
7439 MMMessageParamType msg_param = {0,};
7440 GstElement *element = NULL;
7441 MMHandleType attrs = 0;
7443 enum MainElementID elemId = MMPLAYER_M_NUM;
7447 if (!player || !player->pipeline || !player->pipeline->mainbin) {
7448 LOGE("player is not initialized");
7452 mainbin = player->pipeline->mainbin;
7453 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
7455 attrs = MMPLAYER_GET_ATTRS(player);
7457 LOGE("fail to get attributes");
7461 /* Initialize Player values */
7462 __mmplayer_initialize_next_play(player);
7464 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
7466 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
7467 LOGE("failed to parse profile");
7468 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
7472 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
7473 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
7474 LOGE("dash or hls is not supportable");
7475 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
7479 element = __mmplayer_gst_build_source(player);
7481 LOGE("no source element was created");
7485 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
7486 LOGE("failed to add source element to pipeline");
7487 gst_object_unref(GST_OBJECT(element));
7492 /* take source element */
7493 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
7494 mainbin[MMPLAYER_M_SRC].gst = element;
7498 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7499 if (player->streamer == NULL) {
7500 player->streamer = __mm_player_streaming_create();
7501 __mm_player_streaming_initialize(player->streamer);
7504 elemId = MMPLAYER_M_TYPEFIND;
7505 element = gst_element_factory_make("typefind", "typefinder");
7506 __mmplayer_add_signal_connection(player, G_OBJECT(element),
7507 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
7509 elemId = MMPLAYER_M_AUTOPLUG;
7510 element = __mmplayer_create_decodebin(player);
7513 /* check autoplug element is OK */
7515 LOGE("can not create element(%d)", elemId);
7519 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
7520 LOGE("failed to add sinkbin to pipeline");
7521 gst_object_unref(GST_OBJECT(element));
7526 mainbin[elemId].id = elemId;
7527 mainbin[elemId].gst = element;
7529 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
7530 LOGE("Failed to link src - autoplug(or typefind)");
7534 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
7535 LOGE("Failed to change state of src element");
7539 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7540 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
7541 LOGE("Failed to change state of decodebin");
7545 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
7546 LOGE("Failed to change state of src element");
7551 player->gapless.stream_changed = TRUE;
7552 player->gapless.running = TRUE;
7558 MMPLAYER_PLAYBACK_UNLOCK(player);
7560 if (!player->msg_posted) {
7561 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7562 player->msg_posted = TRUE;
7569 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
7571 mm_player_selector_t *selector = &player->selector[type];
7572 MMPlayerGstElement *sinkbin = NULL;
7573 enum MainElementID selectorId = MMPLAYER_M_NUM;
7574 enum MainElementID sinkId = MMPLAYER_M_NUM;
7575 GstPad *srcpad = NULL;
7576 GstPad *sinkpad = NULL;
7577 gboolean send_notice = FALSE;
7580 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7582 LOGD("type %d", type);
7585 case MM_PLAYER_TRACK_TYPE_AUDIO:
7586 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
7587 sinkId = MMPLAYER_A_BIN;
7588 sinkbin = player->pipeline->audiobin;
7590 case MM_PLAYER_TRACK_TYPE_VIDEO:
7591 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
7592 sinkId = MMPLAYER_V_BIN;
7593 sinkbin = player->pipeline->videobin;
7596 case MM_PLAYER_TRACK_TYPE_TEXT:
7597 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
7598 sinkId = MMPLAYER_T_BIN;
7599 sinkbin = player->pipeline->textbin;
7602 LOGE("requested type is not supportable");
7607 if (player->pipeline->mainbin[selectorId].gst) {
7610 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
7612 if (selector->event_probe_id != 0)
7613 gst_pad_remove_probe(srcpad, selector->event_probe_id);
7614 selector->event_probe_id = 0;
7616 if ((sinkbin) && (sinkbin[sinkId].gst)) {
7617 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
7619 if (srcpad && sinkpad) {
7620 /* after getting drained signal there is no data flows, so no need to do pad_block */
7621 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
7622 gst_pad_unlink(srcpad, sinkpad);
7624 /* send custom event to sink pad to handle it at video sink */
7626 LOGD("send custom event to sinkpad");
7627 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
7628 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
7629 gst_pad_send_event(sinkpad, event);
7633 gst_object_unref(sinkpad);
7636 gst_object_unref(srcpad);
7639 LOGD("selector release");
7641 /* release and unref requests pad from the selector */
7642 for (n = 0; n < selector->channels->len; n++) {
7643 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
7644 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
7646 g_ptr_array_set_size(selector->channels, 0);
7648 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
7649 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
7651 player->pipeline->mainbin[selectorId].gst = NULL;
7659 __mmplayer_deactivate_old_path(mm_player_t *player)
7662 MMPLAYER_RETURN_IF_FAIL(player);
7664 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
7665 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
7666 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
7667 LOGE("deactivate selector error");
7671 __mmplayer_track_destroy(player);
7672 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7674 if (player->streamer) {
7675 __mm_player_streaming_deinitialize(player->streamer);
7676 __mm_player_streaming_destroy(player->streamer);
7677 player->streamer = NULL;
7680 MMPLAYER_PLAYBACK_LOCK(player);
7681 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
7688 if (!player->msg_posted) {
7689 MMMessageParamType msg = {0,};
7692 msg.code = MM_ERROR_PLAYER_INTERNAL;
7693 LOGE("next_uri_play> deactivate error");
7695 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
7696 player->msg_posted = TRUE;
7701 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
7703 int result = MM_ERROR_NONE;
7704 mm_player_t* player = (mm_player_t*) hplayer;
7707 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7710 player->http_file_buffering_path = (gchar*)file_path;
7711 LOGD("temp file path: %s\n", player->http_file_buffering_path);
7717 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
7719 int result = MM_ERROR_NONE;
7720 mm_player_t* player = (mm_player_t*) hplayer;
7723 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7725 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
7726 if (mmf_attrs_commit(player->attrs)) {
7727 LOGE("failed to commit the original uri.\n");
7728 result = MM_ERROR_PLAYER_INTERNAL;
7730 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
7731 LOGE("failed to add the original uri in the uri list.\n");
7738 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
7740 mm_player_t* player = (mm_player_t*) hplayer;
7741 guint num_of_list = 0;
7745 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7746 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
7748 if (player->pipeline && player->pipeline->textbin) {
7749 LOGE("subtitle path is enabled.\n");
7750 return MM_ERROR_PLAYER_INVALID_STATE;
7753 num_of_list = g_list_length(player->uri_info.uri_list);
7755 if (is_first_path == TRUE) {
7756 if (num_of_list == 0) {
7757 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
7758 LOGD("add original path : %s", uri);
7760 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
7761 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
7763 LOGD("change original path : %s", uri);
7766 MMHandleType attrs = 0;
7767 attrs = MMPLAYER_GET_ATTRS(player);
7769 if (num_of_list == 0) {
7770 char *original_uri = NULL;
7773 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
7775 if (!original_uri) {
7776 LOGE("there is no original uri.");
7777 return MM_ERROR_PLAYER_INVALID_STATE;
7780 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
7781 player->uri_info.uri_idx = 0;
7783 LOGD("add original path at first : %s(%d)", original_uri);
7787 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
7788 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
7792 return MM_ERROR_NONE;
7795 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
7797 mm_player_t* player = (mm_player_t*) hplayer;
7798 char *next_uri = NULL;
7799 guint num_of_list = 0;
7802 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7804 num_of_list = g_list_length(player->uri_info.uri_list);
7806 if (num_of_list > 0) {
7807 gint uri_idx = player->uri_info.uri_idx;
7809 if (uri_idx < num_of_list-1)
7814 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
7815 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
7817 *uri = g_strdup(next_uri);
7821 return MM_ERROR_NONE;
7825 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
7826 GstCaps *caps, gpointer data)
7828 mm_player_t* player = (mm_player_t*)data;
7829 const gchar* klass = NULL;
7830 const gchar* mime = NULL;
7831 gchar* caps_str = NULL;
7833 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
7834 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7835 caps_str = gst_caps_to_string(caps);
7837 LOGW("unknown type of caps : %s from %s",
7838 caps_str, GST_ELEMENT_NAME(elem));
7840 MMPLAYER_FREEIF(caps_str);
7842 /* There is no available codec. */
7843 __mmplayer_check_not_supported_codec(player, klass, mime);
7847 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
7848 GstCaps * caps, gpointer data)
7850 mm_player_t* player = (mm_player_t*)data;
7851 const char* mime = NULL;
7852 gboolean ret = TRUE;
7854 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7855 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7857 if (g_str_has_prefix(mime, "audio")) {
7858 GstStructure* caps_structure = NULL;
7859 gint samplerate = 0;
7861 gchar *caps_str = NULL;
7863 caps_structure = gst_caps_get_structure(caps, 0);
7864 gst_structure_get_int(caps_structure, "rate", &samplerate);
7865 gst_structure_get_int(caps_structure, "channels", &channels);
7867 if ((channels > 0 && samplerate == 0)) {
7868 LOGD("exclude audio...");
7872 caps_str = gst_caps_to_string(caps);
7873 /* set it directly because not sent by TAG */
7874 if (g_strrstr(caps_str, "mobile-xmf"))
7875 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
7876 MMPLAYER_FREEIF(caps_str);
7877 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
7878 MMMessageParamType msg_param;
7879 memset(&msg_param, 0, sizeof(MMMessageParamType));
7880 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
7881 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7882 LOGD("video file is not supported on this device");
7884 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7885 LOGD("already video linked");
7888 LOGD("found new stream");
7895 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
7897 int ret = MM_ERROR_NONE;
7899 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7901 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7902 GstStructure* str = NULL;
7904 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7906 LOGD("audio codec type: %d", codec_type);
7907 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7908 /* sw codec will be skipped */
7909 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7910 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7911 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7912 ret = MM_ERROR_PLAYER_INTERNAL;
7916 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7917 /* hw codec will be skipped */
7918 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7919 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7920 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7921 ret = MM_ERROR_PLAYER_INTERNAL;
7926 str = gst_caps_get_structure(caps, 0);
7928 gst_structure_get_int(str, "channels", &channels);
7930 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
7931 if (player->max_audio_channels < channels)
7932 player->max_audio_channels = channels;
7934 /* set stream information */
7935 if (!player->audiodec_linked)
7936 __mmplayer_set_audio_attrs(player, caps);
7938 /* update codec info */
7939 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7940 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7941 player->audiodec_linked = 1;
7943 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7945 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7947 LOGD("video codec type: %d", codec_type);
7948 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7949 /* sw codec is skipped */
7950 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7951 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7952 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7953 ret = MM_ERROR_PLAYER_INTERNAL;
7957 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7958 /* hw codec is skipped */
7959 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7960 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7961 ret = MM_ERROR_PLAYER_INTERNAL;
7966 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7967 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7969 /* mark video decoder for acquire */
7970 if (player->video_decoder_resource == NULL) {
7971 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7972 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7973 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7974 &player->video_decoder_resource)
7975 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7976 LOGE("could not mark video_decoder resource for acquire");
7977 ret = MM_ERROR_PLAYER_INTERNAL;
7981 LOGW("video decoder resource is already acquired, skip it.");
7982 ret = MM_ERROR_PLAYER_INTERNAL;
7986 player->interrupted_by_resource = FALSE;
7987 /* acquire resources for video playing */
7988 if (mm_resource_manager_commit(player->resource_manager)
7989 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7990 LOGE("could not acquire resources for video decoding\n");
7991 ret = MM_ERROR_PLAYER_INTERNAL;
7996 /* update codec info */
7997 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7998 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7999 player->videodec_linked = 1;
8007 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
8008 GstCaps* caps, GstElementFactory* factory, gpointer data)
8010 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
8011 We are defining our own and will be removed when it actually exposed */
8013 GST_AUTOPLUG_SELECT_TRY,
8014 GST_AUTOPLUG_SELECT_EXPOSE,
8015 GST_AUTOPLUG_SELECT_SKIP
8016 } GstAutoplugSelectResult;
8018 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
8019 mm_player_t* player = (mm_player_t*)data;
8021 gchar* factory_name = NULL;
8022 gchar* caps_str = NULL;
8023 const gchar* klass = NULL;
8026 factory_name = GST_OBJECT_NAME(factory);
8027 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
8028 caps_str = gst_caps_to_string(caps);
8030 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
8032 /* store type string */
8033 if (player->type == NULL) {
8034 player->type = gst_caps_to_string(caps);
8035 __mmplayer_update_content_type_info(player);
8038 /* filtering exclude keyword */
8039 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
8040 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
8041 LOGW("skipping [%s] by exculde keyword [%s]",
8042 factory_name, player->ini.exclude_element_keyword[idx]);
8044 result = GST_AUTOPLUG_SELECT_SKIP;
8049 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
8050 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
8051 LOGW("skipping [%s] by unsupported codec keyword [%s]",
8052 factory_name, player->ini.unsupported_codec_keyword[idx]);
8053 result = GST_AUTOPLUG_SELECT_SKIP;
8058 /* exclude webm format */
8059 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
8060 * because webm format is not supportable.
8061 * If webm is disabled in "autoplug-continue", there is no state change
8062 * failure or error because the decodebin will expose the pad directly.
8063 * It make MSL invoke _prepare_async_callback.
8064 * So, we need to disable webm format in "autoplug-select" */
8065 if (caps_str && strstr(caps_str, "webm")) {
8066 LOGW("webm is not supported");
8067 result = GST_AUTOPLUG_SELECT_SKIP;
8071 /* check factory class for filtering */
8072 /* NOTE : msl don't need to use image plugins.
8073 * So, those plugins should be skipped for error handling.
8075 if (g_strrstr(klass, "Codec/Decoder/Image")) {
8076 LOGD("skipping [%s] by not required\n", factory_name);
8077 result = GST_AUTOPLUG_SELECT_SKIP;
8081 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
8082 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
8083 // TO CHECK : subtitle if needed, add subparse exception.
8084 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
8085 result = GST_AUTOPLUG_SELECT_SKIP;
8089 if (g_strrstr(factory_name, "mpegpsdemux")) {
8090 LOGD("skipping PS container - not support\n");
8091 result = GST_AUTOPLUG_SELECT_SKIP;
8095 if (g_strrstr(factory_name, "mssdemux"))
8096 player->smooth_streaming = TRUE;
8098 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
8099 (g_strrstr(klass, "Codec/Decoder/Video"))) {
8102 GstStructure *str = NULL;
8103 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
8105 /* don't make video because of not required */
8106 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
8107 (player->set_mode.media_packet_video_stream == FALSE)) {
8108 LOGD("no video because it's not required. -> return expose");
8109 result = GST_AUTOPLUG_SELECT_EXPOSE;
8113 /* get w/h for omx state-tune */
8114 /* FIXME: deprecated? */
8115 str = gst_caps_get_structure(caps, 0);
8116 gst_structure_get_int(str, "width", &width);
8119 if (player->v_stream_caps) {
8120 gst_caps_unref(player->v_stream_caps);
8121 player->v_stream_caps = NULL;
8124 player->v_stream_caps = gst_caps_copy(caps);
8125 LOGD("take caps for video state tune");
8126 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
8130 if (g_strrstr(klass, "Codec/Decoder")) {
8131 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
8132 LOGD("skipping %s codec", factory_name);
8133 result = GST_AUTOPLUG_SELECT_SKIP;
8139 MMPLAYER_FREEIF(caps_str);
8145 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
8148 //mm_player_t* player = (mm_player_t*)data;
8149 GstCaps* caps = NULL;
8151 LOGD("[Decodebin2] pad-removed signal\n");
8153 caps = gst_pad_query_caps(new_pad, NULL);
8155 gchar* caps_str = NULL;
8156 caps_str = gst_caps_to_string(caps);
8158 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
8160 MMPLAYER_FREEIF(caps_str);
8161 gst_caps_unref(caps);
8166 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
8168 mm_player_t* player = (mm_player_t*)data;
8169 GstIterator *iter = NULL;
8170 GValue item = { 0, };
8172 gboolean done = FALSE;
8173 gboolean is_all_drained = TRUE;
8176 MMPLAYER_RETURN_IF_FAIL(player);
8178 LOGD("__mmplayer_gst_decode_drained");
8180 if (player->use_deinterleave == TRUE) {
8181 LOGD("group playing mode.");
8185 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8186 LOGW("Fail to get cmd lock");
8190 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
8191 !__mmplayer_verify_next_play_path(player)) {
8192 LOGD("decoding is finished.");
8193 __mmplayer_reset_gapless_state(player);
8194 MMPLAYER_CMD_UNLOCK(player);
8198 player->gapless.reconfigure = TRUE;
8200 /* check decodebin src pads whether they received EOS or not */
8201 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
8204 switch (gst_iterator_next(iter, &item)) {
8205 case GST_ITERATOR_OK:
8206 pad = g_value_get_object(&item);
8207 if (pad && !GST_PAD_IS_EOS(pad)) {
8208 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
8209 is_all_drained = FALSE;
8212 g_value_reset(&item);
8214 case GST_ITERATOR_RESYNC:
8215 gst_iterator_resync(iter);
8217 case GST_ITERATOR_ERROR:
8218 case GST_ITERATOR_DONE:
8223 g_value_unset(&item);
8224 gst_iterator_free(iter);
8226 if (!is_all_drained) {
8227 LOGD("Wait util the all pads get EOS.");
8228 MMPLAYER_CMD_UNLOCK(player);
8233 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
8234 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
8236 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
8237 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
8238 __mmplayer_deactivate_old_path(player);
8239 MMPLAYER_CMD_UNLOCK(player);
8245 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
8247 mm_player_t* player = (mm_player_t*)data;
8248 const gchar* klass = NULL;
8249 gchar* factory_name = NULL;
8251 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
8252 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8254 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
8256 if (__mmplayer_add_dump_buffer_probe(player, element))
8257 LOGD("add buffer probe");
8260 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
8261 gchar* selected = NULL;
8262 selected = g_strdup(GST_ELEMENT_NAME(element));
8263 player->audio_decoders = g_list_append(player->audio_decoders, selected);
8267 if (g_strrstr(klass, "Parser")) {
8268 gchar* selected = NULL;
8270 selected = g_strdup(factory_name);
8271 player->parsers = g_list_append(player->parsers, selected);
8274 if (g_strrstr(klass, "Demuxer/Adaptive")) {
8275 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
8276 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
8278 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
8279 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
8281 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8282 "max-bandwidth", player->adaptive_info.limit.bandwidth,
8283 "max-video-width", player->adaptive_info.limit.width,
8284 "max-video-height", player->adaptive_info.limit.height, NULL);
8286 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
8287 /* FIXIT : first value will be overwritten if there's more
8288 * than 1 demuxer/parser
8291 //LOGD("plugged element is demuxer. take it\n");
8292 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
8293 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
8295 /*Added for multi audio support */ // Q. del?
8296 if (g_strrstr(klass, "Demux")) {
8297 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
8298 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
8302 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
8303 int surface_type = 0;
8305 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
8308 // to support trust-zone only
8309 if (g_strrstr(factory_name, "asfdemux")) {
8310 LOGD("set file-location %s\n", player->profile.uri);
8311 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
8313 if (player->video_hub_download_mode == TRUE)
8314 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
8315 } else if (g_strrstr(factory_name, "legacyh264parse")) {
8316 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
8317 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
8318 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
8319 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
8320 (__mmplayer_is_only_mp3_type(player->type))) {
8321 LOGD("[mpegaudioparse] set streaming pull mode.");
8322 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
8324 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
8325 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
8328 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
8329 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
8330 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
8332 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
8333 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
8335 if (!MMPLAYER_IS_HTTP_PD(player) &&
8336 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
8337 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
8338 (MMPLAYER_IS_DASH_STREAMING(player)))) {
8339 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
8340 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
8341 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
8349 gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
8352 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8354 if (MMPLAYER_IS_STREAMING(player))
8357 /* This callback can be set to music player only. */
8358 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
8359 LOGW("audio callback is not supported for video");
8363 if (player->audio_stream_cb) {
8366 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
8369 LOGE("failed to get sink pad from audiosink to probe data\n");
8372 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
8373 __mmplayer_audio_stream_probe, player, NULL);
8375 gst_object_unref(pad);
8379 LOGE("There is no audio callback to configure.\n");
8389 __mmplayer_release_misc(mm_player_t* player)
8392 bool cur_mode = player->set_mode.rich_audio;
8395 MMPLAYER_RETURN_IF_FAIL(player);
8397 player->video_stream_cb = NULL;
8398 player->video_stream_cb_user_param = NULL;
8399 player->video_stream_prerolled = FALSE;
8401 player->audio_stream_cb = NULL;
8402 player->audio_stream_render_cb_ex = NULL;
8403 player->audio_stream_cb_user_param = NULL;
8404 player->audio_stream_sink_sync = false;
8406 player->video_stream_changed_cb = NULL;
8407 player->video_stream_changed_cb_user_param = NULL;
8409 player->audio_stream_changed_cb = NULL;
8410 player->audio_stream_changed_cb_user_param = NULL;
8412 player->sent_bos = FALSE;
8413 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8415 player->seek_state = MMPLAYER_SEEK_NONE;
8417 player->total_bitrate = 0;
8418 player->total_maximum_bitrate = 0;
8420 player->not_found_demuxer = 0;
8422 player->last_position = 0;
8423 player->duration = 0;
8424 player->http_content_size = 0;
8425 player->not_supported_codec = MISSING_PLUGIN_NONE;
8426 player->can_support_codec = FOUND_PLUGIN_NONE;
8427 player->pending_seek.is_pending = FALSE;
8428 player->pending_seek.pos = 0;
8429 player->msg_posted = FALSE;
8430 player->has_many_types = FALSE;
8431 player->max_audio_channels = 0;
8432 player->video_share_api_delta = 0;
8433 player->video_share_clock_delta = 0;
8434 player->is_subtitle_force_drop = FALSE;
8435 player->play_subtitle = FALSE;
8436 player->adjust_subtitle_pos = 0;
8437 player->last_multiwin_status = FALSE;
8438 player->has_closed_caption = FALSE;
8439 player->set_mode.media_packet_video_stream = FALSE;
8440 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
8441 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
8443 player->set_mode.rich_audio = cur_mode;
8445 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
8446 player->bitrate[i] = 0;
8447 player->maximum_bitrate[i] = 0;
8450 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
8452 /* remove media stream cb(appsrc cb) */
8453 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
8454 player->media_stream_buffer_status_cb[i] = NULL;
8455 player->media_stream_seek_data_cb[i] = NULL;
8456 player->buffer_cb_user_param[i] = NULL;
8457 player->seek_cb_user_param[i] = NULL;
8459 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
8461 /* free memory related to audio effect */
8462 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
8464 if (player->adaptive_info.var_list) {
8465 g_list_free_full(player->adaptive_info.var_list, g_free);
8466 player->adaptive_info.var_list = NULL;
8469 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8470 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8471 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8473 /* Reset video360 settings to their defaults in case if the pipeline is to be
8476 player->video360_metadata.is_spherical = -1;
8477 player->is_openal_plugin_used = FALSE;
8479 player->is_content_spherical = FALSE;
8480 player->is_video360_enabled = TRUE;
8481 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8482 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8483 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8484 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8485 player->video360_zoom = 1.0f;
8486 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8487 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8489 player->sound.rg_enable = false;
8491 __mmplayer_initialize_video_roi(player);
8496 __mmplayer_release_misc_post(mm_player_t* player)
8498 char *original_uri = NULL;
8501 /* player->pipeline is already released before. */
8503 MMPLAYER_RETURN_IF_FAIL(player);
8505 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
8507 /* clean found parsers */
8508 if (player->parsers) {
8509 GList *parsers = player->parsers;
8510 for (; parsers; parsers = g_list_next(parsers)) {
8511 gchar *name = parsers->data;
8512 MMPLAYER_FREEIF(name);
8514 g_list_free(player->parsers);
8515 player->parsers = NULL;
8518 /* clean found audio decoders */
8519 if (player->audio_decoders) {
8520 GList *a_dec = player->audio_decoders;
8521 for (; a_dec; a_dec = g_list_next(a_dec)) {
8522 gchar *name = a_dec->data;
8523 MMPLAYER_FREEIF(name);
8525 g_list_free(player->audio_decoders);
8526 player->audio_decoders = NULL;
8529 /* clean the uri list except original uri */
8530 if (player->uri_info.uri_list) {
8531 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
8533 if (player->attrs) {
8534 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
8535 LOGD("restore original uri = %s\n", original_uri);
8537 if (mmf_attrs_commit(player->attrs))
8538 LOGE("failed to commit the original uri.\n");
8541 GList *uri_list = player->uri_info.uri_list;
8542 for (; uri_list; uri_list = g_list_next(uri_list)) {
8543 gchar *uri = uri_list->data;
8544 MMPLAYER_FREEIF(uri);
8546 g_list_free(player->uri_info.uri_list);
8547 player->uri_info.uri_list = NULL;
8550 /* clear the audio stream buffer list */
8551 __mmplayer_audio_stream_clear_buffer(player, FALSE);
8553 /* clear the video stream bo list */
8554 __mmplayer_video_stream_destroy_bo_list(player);
8555 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8557 if (player->profile.input_mem.buf) {
8558 free(player->profile.input_mem.buf);
8559 player->profile.input_mem.buf = NULL;
8561 player->profile.input_mem.len = 0;
8562 player->profile.input_mem.offset = 0;
8564 player->uri_info.uri_idx = 0;
8568 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
8570 GstElement *element = NULL;
8573 LOGD("creating %s to plug\n", name);
8575 element = gst_element_factory_make(name, NULL);
8577 LOGE("failed to create queue\n");
8581 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
8582 LOGE("failed to set state READY to %s\n", name);
8583 gst_object_unref(element);
8587 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
8588 LOGE("failed to add %s\n", name);
8589 gst_object_unref(element);
8593 sinkpad = gst_element_get_static_pad(element, "sink");
8595 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
8596 LOGE("failed to link %s\n", name);
8597 gst_object_unref(sinkpad);
8598 gst_object_unref(element);
8602 LOGD("linked %s to pipeline successfully\n", name);
8604 gst_object_unref(sinkpad);
8610 __mmplayer_check_subtitle(mm_player_t* player)
8612 MMHandleType attrs = 0;
8613 char *subtitle_uri = NULL;
8617 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8619 /* get subtitle attribute */
8620 attrs = MMPLAYER_GET_ATTRS(player);
8624 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8625 if (!subtitle_uri || !strlen(subtitle_uri))
8628 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
8629 player->is_external_subtitle_present = TRUE;
8637 __mmplayer_can_extract_pcm(mm_player_t* player)
8639 MMHandleType attrs = 0;
8640 gboolean sound_extraction = FALSE;
8642 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8644 attrs = MMPLAYER_GET_ATTRS(player);
8646 LOGE("fail to get attributes.");
8650 /* get sound_extraction property */
8651 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
8653 if (!sound_extraction) {
8654 LOGD("checking pcm extraction mode : %d ", sound_extraction);
8662 __mmplayer_cancel_eos_timer(mm_player_t* player)
8664 MMPLAYER_RETURN_IF_FAIL(player);
8666 if (player->eos_timer) {
8667 LOGD("cancel eos timer");
8668 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8669 player->eos_timer = 0;
8676 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
8680 MMPLAYER_RETURN_IF_FAIL(player);
8681 MMPLAYER_RETURN_IF_FAIL(sink);
8683 player->sink_elements =
8684 g_list_append(player->sink_elements, sink);
8690 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
8694 MMPLAYER_RETURN_IF_FAIL(player);
8695 MMPLAYER_RETURN_IF_FAIL(sink);
8697 player->sink_elements =
8698 g_list_remove(player->sink_elements, sink);
8704 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
8705 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
8707 MMPlayerSignalItem* item = NULL;
8710 MMPLAYER_RETURN_IF_FAIL(player);
8712 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8713 LOGE("invalid signal type [%d]", type);
8717 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
8719 LOGE("cannot connect signal [%s]", signal);
8724 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8725 player->signals[type] = g_list_append(player->signals[type], item);
8731 /* NOTE : be careful with calling this api. please refer to below glib comment
8732 * glib comment : Note that there is a bug in GObject that makes this function much
8733 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8734 * will no longer be called, but, the signal handler is not currently disconnected.
8735 * If the instance is itself being freed at the same time than this doesn't matter,
8736 * since the signal will automatically be removed, but if instance persists,
8737 * then the signal handler will leak. You should not remove the signal yourself
8738 * because in a future versions of GObject, the handler will automatically be
8741 * It's possible to work around this problem in a way that will continue to work
8742 * with future versions of GObject by checking that the signal handler is still
8743 * connected before disconnected it:
8745 * if (g_signal_handler_is_connected(instance, id))
8746 * g_signal_handler_disconnect(instance, id);
8749 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
8751 GList* sig_list = NULL;
8752 MMPlayerSignalItem* item = NULL;
8756 MMPLAYER_RETURN_IF_FAIL(player);
8758 LOGD("release signals type : %d", type);
8760 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8761 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8764 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8765 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8769 sig_list = player->signals[type];
8771 for (; sig_list; sig_list = sig_list->next) {
8772 item = sig_list->data;
8774 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
8775 if (g_signal_handler_is_connected(item->obj, item->sig))
8776 g_signal_handler_disconnect(item->obj, item->sig);
8779 MMPLAYER_FREEIF(item);
8782 g_list_free(player->signals[type]);
8783 player->signals[type] = NULL;
8790 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
8792 mm_player_t* player = 0;
8793 int prev_display_surface_type = 0;
8794 void *prev_display_overlay = NULL;
8798 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8799 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
8801 player = MM_PLAYER_CAST(handle);
8803 /* check video sinkbin is created */
8804 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
8805 LOGE("Videosink is already created");
8806 return MM_ERROR_NONE;
8809 LOGD("videosink element is not yet ready");
8811 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8812 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8814 return MM_ERROR_INVALID_ARGUMENT;
8817 /* load previous attributes */
8818 if (player->attrs) {
8819 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8820 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
8821 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8822 if (prev_display_surface_type == surface_type) {
8823 LOGD("incoming display surface type is same as previous one, do nothing..");
8825 return MM_ERROR_NONE;
8828 LOGE("failed to load attributes");
8830 return MM_ERROR_PLAYER_INTERNAL;
8833 /* videobin is not created yet, so we just set attributes related to display surface */
8834 LOGD("store display attribute for given surface type(%d)", surface_type);
8835 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
8836 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
8837 if (mmf_attrs_commit(player->attrs)) {
8838 LOGE("failed to commit attribute");
8840 return MM_ERROR_PLAYER_INTERNAL;
8844 return MM_ERROR_NONE;
8847 /* Note : if silent is true, then subtitle would not be displayed. :*/
8848 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8850 mm_player_t* player = (mm_player_t*) hplayer;
8854 /* check player handle */
8855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8857 player->set_mode.subtitle_off = silent;
8859 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
8863 return MM_ERROR_NONE;
8866 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
8868 MMPlayerGstElement* mainbin = NULL;
8869 MMPlayerGstElement* textbin = NULL;
8870 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8871 GstState current_state = GST_STATE_VOID_PENDING;
8872 GstState element_state = GST_STATE_VOID_PENDING;
8873 GstState element_pending_state = GST_STATE_VOID_PENDING;
8875 GstEvent *event = NULL;
8876 int result = MM_ERROR_NONE;
8878 GstClock *curr_clock = NULL;
8879 GstClockTime base_time, start_time, curr_time;
8884 /* check player handle */
8885 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8887 player->pipeline->mainbin &&
8888 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8890 mainbin = player->pipeline->mainbin;
8891 textbin = player->pipeline->textbin;
8893 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8895 // sync clock with current pipeline
8896 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8897 curr_time = gst_clock_get_time(curr_clock);
8899 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8900 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8902 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8903 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8905 if (current_state > GST_STATE_READY) {
8906 // sync state with current pipeline
8907 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8908 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8909 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8911 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8912 if (GST_STATE_CHANGE_FAILURE == ret) {
8913 LOGE("fail to state change.\n");
8914 result = MM_ERROR_PLAYER_INTERNAL;
8919 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8920 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8923 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8924 gst_object_unref(curr_clock);
8927 // seek to current position
8928 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8929 result = MM_ERROR_PLAYER_INVALID_STATE;
8930 LOGE("gst_element_query_position failed, invalid state\n");
8934 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8935 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);
8937 __mmplayer_gst_send_event_to_sink(player, event);
8939 result = MM_ERROR_PLAYER_INTERNAL;
8940 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8944 /* sync state with current pipeline */
8945 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8946 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8947 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8949 return MM_ERROR_NONE;
8952 /* release text pipeline resource */
8953 player->textsink_linked = 0;
8955 /* release signal */
8956 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8958 /* release textbin with it's childs */
8959 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8960 MMPLAYER_FREEIF(player->pipeline->textbin);
8961 player->pipeline->textbin = NULL;
8963 /* release subtitle elem */
8964 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8971 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
8973 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8974 GstState current_state = GST_STATE_VOID_PENDING;
8976 MMHandleType attrs = 0;
8977 MMPlayerGstElement* mainbin = NULL;
8978 MMPlayerGstElement* textbin = NULL;
8980 gchar* subtitle_uri = NULL;
8981 int result = MM_ERROR_NONE;
8982 const gchar *charset = NULL;
8986 /* check player handle */
8987 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8989 player->pipeline->mainbin &&
8990 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8991 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8993 mainbin = player->pipeline->mainbin;
8994 textbin = player->pipeline->textbin;
8996 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8997 if (current_state < GST_STATE_READY) {
8998 result = MM_ERROR_PLAYER_INVALID_STATE;
8999 LOGE("Pipeline is not in proper state\n");
9003 attrs = MMPLAYER_GET_ATTRS(player);
9005 LOGE("cannot get content attribute\n");
9006 result = MM_ERROR_PLAYER_INTERNAL;
9010 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
9011 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
9012 LOGE("subtitle uri is not proper filepath\n");
9013 result = MM_ERROR_PLAYER_INVALID_URI;
9017 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
9018 LOGE("failed to get storage info of subtitle path");
9019 result = MM_ERROR_PLAYER_INVALID_URI;
9023 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
9024 LOGD("new subtitle file path is [%s]\n", filepath);
9026 if (!strcmp(filepath, subtitle_uri)) {
9027 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
9030 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
9031 if (mmf_attrs_commit(player->attrs)) {
9032 LOGE("failed to commit.\n");
9037 //gst_pad_set_blocked_async(src-srcpad, TRUE)
9038 MMPLAYER_SUBTITLE_INFO_LOCK(player);
9039 player->subtitle_language_list = NULL;
9040 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
9042 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
9043 if (ret != GST_STATE_CHANGE_SUCCESS) {
9044 LOGE("failed to change state of textbin to READY");
9045 result = MM_ERROR_PLAYER_INTERNAL;
9049 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
9050 if (ret != GST_STATE_CHANGE_SUCCESS) {
9051 LOGE("failed to change state of subparse to READY");
9052 result = MM_ERROR_PLAYER_INTERNAL;
9056 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
9057 if (ret != GST_STATE_CHANGE_SUCCESS) {
9058 LOGE("failed to change state of filesrc to READY");
9059 result = MM_ERROR_PLAYER_INTERNAL;
9063 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
9065 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
9067 charset = util_get_charset(filepath);
9069 LOGD("detected charset is %s\n", charset);
9070 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
9073 result = _mmplayer_sync_subtitle_pipeline(player);
9080 /* API to switch between external subtitles */
9081 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
9083 int result = MM_ERROR_NONE;
9084 mm_player_t* player = (mm_player_t*)hplayer;
9089 /* check player handle */
9090 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9092 /* filepath can be null in idle state */
9094 /* check file path */
9095 if ((path = strstr(filepath, "file://")))
9096 result = util_exist_file_path(path + 7);
9098 result = util_exist_file_path(filepath);
9100 if (result != MM_ERROR_NONE) {
9101 LOGE("invalid subtitle path 0x%X", result);
9102 return result; /* file not found or permission denied */
9106 if (!player->pipeline) {
9108 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
9109 if (mmf_attrs_commit(player->attrs)) {
9110 LOGE("failed to commit"); /* subtitle path will not be created */
9111 return MM_ERROR_PLAYER_INTERNAL;
9114 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
9115 /* check filepath */
9116 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
9118 if (!__mmplayer_check_subtitle(player)) {
9119 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
9120 if (mmf_attrs_commit(player->attrs)) {
9121 LOGE("failed to commit");
9122 return MM_ERROR_PLAYER_INTERNAL;
9125 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
9126 LOGE("fail to create text pipeline");
9127 return MM_ERROR_PLAYER_INTERNAL;
9130 result = _mmplayer_sync_subtitle_pipeline(player);
9132 result = __mmplayer_change_external_subtitle_language(player, filepath);
9135 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
9136 player->is_external_subtitle_added_now = TRUE;
9138 MMPLAYER_SUBTITLE_INFO_LOCK(player);
9139 if (!player->subtitle_language_list) {
9140 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
9141 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
9142 LOGW("subtitle language list is not updated yet");
9144 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
9152 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
9154 int result = MM_ERROR_NONE;
9155 gchar* change_pad_name = NULL;
9156 GstPad* sinkpad = NULL;
9157 MMPlayerGstElement* mainbin = NULL;
9158 enum MainElementID elemId = MMPLAYER_M_NUM;
9159 GstCaps* caps = NULL;
9160 gint total_track_num = 0;
9164 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
9165 MM_ERROR_PLAYER_NOT_INITIALIZED);
9167 LOGD("Change Track(%d) to %d\n", type, index);
9169 mainbin = player->pipeline->mainbin;
9171 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
9172 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
9173 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
9174 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
9176 /* Changing Video Track is not supported. */
9177 LOGE("Track Type Error\n");
9181 if (mainbin[elemId].gst == NULL) {
9182 result = MM_ERROR_PLAYER_NO_OP;
9183 LOGD("Req track doesn't exist\n");
9187 total_track_num = player->selector[type].total_track_num;
9188 if (total_track_num <= 0) {
9189 result = MM_ERROR_PLAYER_NO_OP;
9190 LOGD("Language list is not available \n");
9194 if ((index < 0) || (index >= total_track_num)) {
9195 result = MM_ERROR_INVALID_ARGUMENT;
9196 LOGD("Not a proper index : %d \n", index);
9200 /*To get the new pad from the selector*/
9201 change_pad_name = g_strdup_printf("sink_%u", index);
9202 if (change_pad_name == NULL) {
9203 result = MM_ERROR_PLAYER_INTERNAL;
9204 LOGD("Pad does not exists\n");
9208 LOGD("new active pad name: %s\n", change_pad_name);
9210 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
9211 if (sinkpad == NULL) {
9212 LOGD("sinkpad is NULL");
9213 result = MM_ERROR_PLAYER_INTERNAL;
9217 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
9218 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
9220 caps = gst_pad_get_current_caps(sinkpad);
9221 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9224 gst_object_unref(sinkpad);
9226 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
9227 __mmplayer_set_audio_attrs(player, caps);
9231 MMPLAYER_FREEIF(change_pad_name);
9235 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
9237 int result = MM_ERROR_NONE;
9238 mm_player_t* player = NULL;
9239 MMPlayerGstElement* mainbin = NULL;
9241 gint current_active_index = 0;
9243 GstState current_state = GST_STATE_VOID_PENDING;
9244 GstEvent* event = NULL;
9249 player = (mm_player_t*)hplayer;
9250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9252 if (!player->pipeline) {
9253 LOGE("Track %d pre setting -> %d\n", type, index);
9255 player->selector[type].active_pad_index = index;
9259 mainbin = player->pipeline->mainbin;
9261 current_active_index = player->selector[type].active_pad_index;
9263 /*If index is same as running index no need to change the pad*/
9264 if (current_active_index == index)
9267 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
9268 result = MM_ERROR_PLAYER_INVALID_STATE;
9272 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
9273 if (current_state < GST_STATE_PAUSED) {
9274 result = MM_ERROR_PLAYER_INVALID_STATE;
9275 LOGW("Pipeline not in porper state\n");
9279 result = __mmplayer_change_selector_pad(player, type, index);
9280 if (result != MM_ERROR_NONE) {
9281 LOGE("change selector pad error\n");
9285 player->selector[type].active_pad_index = index;
9287 if (current_state == GST_STATE_PLAYING) {
9288 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);
9290 __mmplayer_gst_send_event_to_sink(player, event);
9292 result = MM_ERROR_PLAYER_INTERNAL;
9301 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
9303 mm_player_t* player = (mm_player_t*) hplayer;
9307 /* check player handle */
9308 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9310 *silent = player->set_mode.subtitle_off;
9312 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
9316 return MM_ERROR_NONE;
9320 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
9322 mm_player_t* player = (mm_player_t*) hplayer;
9324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9326 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
9327 MMPLAYER_PRINT_STATE(player);
9328 LOGE("wrong-state : can't set the download mode to parse");
9329 return MM_ERROR_PLAYER_INVALID_STATE;
9332 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
9333 player->video_hub_download_mode = mode;
9335 return MM_ERROR_NONE;
9339 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
9341 mm_player_t* player = (mm_player_t*) hplayer;
9343 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9345 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
9346 player->sync_handler = enable;
9348 return MM_ERROR_NONE;
9352 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
9353 gint64 video_time, gint64 media_clock, gint64 audio_time)
9355 mm_player_t* player = (mm_player_t*) hplayer;
9356 MMPlayerGstElement* mainbin = NULL;
9357 GstClockTime start_time_audio = 0, start_time_video = 0;
9358 GstClockTimeDiff base_time = 0, new_base_time = 0;
9359 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9360 gint64 api_delta = 0;
9361 gint64 position = 0, position_delta = 0;
9362 gint64 adj_base_time = 0;
9363 GstClock *curr_clock = NULL;
9364 GstClockTime curr_time = 0;
9365 gboolean query_ret = TRUE;
9366 int result = MM_ERROR_NONE;
9370 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9371 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
9372 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
9374 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
9375 clock, clock_delta, video_time, media_clock, audio_time); */
9377 if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
9378 LOGD("skip setting master clock. %lld", video_time);
9382 mainbin = player->pipeline->mainbin;
9384 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
9385 curr_time = gst_clock_get_time(curr_clock);
9387 current_state = MMPLAYER_CURRENT_STATE(player);
9389 if (current_state == MM_PLAYER_STATE_PLAYING)
9390 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
9392 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
9394 position = player->last_position;
9395 LOGD("query fail. %"G_GINT64_FORMAT, position);
9398 clock *= GST_USECOND;
9399 clock_delta *= GST_USECOND;
9401 api_delta = clock - curr_time;
9402 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
9403 player->video_share_api_delta = api_delta;
9405 clock_delta += (api_delta - player->video_share_api_delta);
9407 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
9408 player->video_share_clock_delta = (gint64)clock_delta;
9410 position_delta = (position/GST_USECOND) - video_time;
9411 position_delta *= GST_USECOND;
9413 adj_base_time = position_delta;
9414 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
9417 gint64 new_play_time = 0;
9418 gint64 network_delay = 0;
9420 video_time *= GST_USECOND;
9422 network_delay = clock_delta - player->video_share_clock_delta;
9423 new_play_time = video_time + network_delay;
9425 adj_base_time = position - new_play_time;
9427 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
9428 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
9429 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
9432 /* Adjust Current Stream Time with base_time of sink
9433 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
9434 * 2. Set new base time
9435 * if adj_base_time is positive value, the stream time will be decreased.
9436 * 3. If seek event is occurred, the start time will be reset. */
9437 if ((player->pipeline->audiobin) &&
9438 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
9439 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
9441 if (start_time_audio != GST_CLOCK_TIME_NONE) {
9442 LOGD("audio sink : gst_element_set_start_time -> NONE");
9443 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
9446 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
9449 if ((player->pipeline->videobin) &&
9450 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
9451 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
9453 if (start_time_video != GST_CLOCK_TIME_NONE) {
9454 LOGD("video sink : gst_element_set_start_time -> NONE");
9455 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
9458 // if videobin exist, get base_time from videobin.
9459 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
9462 new_base_time = base_time + adj_base_time;
9464 if ((player->pipeline->audiobin) &&
9465 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
9466 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
9468 if ((player->pipeline->videobin) &&
9469 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
9470 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
9479 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
9481 mm_player_t* player = (mm_player_t*) hplayer;
9482 MMPlayerGstElement* mainbin = NULL;
9483 GstClock *curr_clock = NULL;
9484 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9485 gint64 position = 0;
9486 gboolean query_ret = TRUE;
9490 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9491 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
9492 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
9494 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
9495 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
9496 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
9498 mainbin = player->pipeline->mainbin;
9500 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
9502 current_state = MMPLAYER_CURRENT_STATE(player);
9504 if (current_state != MM_PLAYER_STATE_PAUSED)
9505 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
9507 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
9509 position = player->last_position;
9511 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
9513 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
9516 gst_object_unref(curr_clock);
9520 return MM_ERROR_NONE;
9524 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
9526 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9527 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
9529 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
9530 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
9534 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
9535 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
9536 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
9537 mm_player_dump_t *dump_s;
9538 dump_s = g_malloc(sizeof(mm_player_dump_t));
9540 if (dump_s == NULL) {
9541 LOGE("malloc fail");
9545 dump_s->dump_element_file = NULL;
9546 dump_s->dump_pad = NULL;
9547 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
9549 if (dump_s->dump_pad) {
9550 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
9551 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]);
9552 dump_s->dump_element_file = fopen(dump_file_name, "w+");
9553 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);
9554 /* add list for removed buffer probe and close FILE */
9555 player->dump_list = g_list_append(player->dump_list, dump_s);
9556 LOGD("%s sink pad added buffer probe for dump", factory_name);
9561 LOGE("failed to get %s sink pad added", factory_name);
9570 static GstPadProbeReturn
9571 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
9573 FILE *dump_data = (FILE *) u_data;
9575 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
9576 GstMapInfo probe_info = GST_MAP_INFO_INIT;
9578 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
9580 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
9582 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
9584 fwrite(probe_info.data, 1, probe_info.size , dump_data);
9586 return GST_PAD_PROBE_OK;
9590 __mmplayer_release_dump_list(GList *dump_list)
9593 GList *d_list = dump_list;
9594 for (; d_list; d_list = g_list_next(d_list)) {
9595 mm_player_dump_t *dump_s = d_list->data;
9596 if (dump_s->dump_pad) {
9597 if (dump_s->probe_handle_id)
9598 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
9600 if (dump_s->dump_element_file) {
9601 fclose(dump_s->dump_element_file);
9602 dump_s->dump_element_file = NULL;
9604 MMPLAYER_FREEIF(dump_s);
9606 g_list_free(dump_list);
9612 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
9614 mm_player_t* player = (mm_player_t*) hplayer;
9618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9619 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
9621 *exist = player->has_closed_caption;
9625 return MM_ERROR_NONE;
9628 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
9632 // LOGD("unref internal gst buffer %p", buffer);
9633 gst_buffer_unref((GstBuffer *)buffer);
9640 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
9642 mm_player_t* player = (mm_player_t*) hplayer;
9646 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9648 player->pcm_samplerate = samplerate;
9649 player->pcm_channel = channel;
9652 return MM_ERROR_NONE;
9655 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
9657 mm_player_t* player = (mm_player_t*) hplayer;
9661 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9662 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
9664 if (MMPLAYER_IS_HTTP_PD(player))
9665 /* consider the timeout both download pipeline and playback pipeline */
9666 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
9667 else if (MMPLAYER_IS_STREAMING(player))
9668 *timeout = player->ini.live_state_change_timeout;
9670 *timeout = player->ini.localplayback_state_change_timeout;
9672 LOGD("timeout = %d\n", *timeout);
9675 return MM_ERROR_NONE;
9678 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
9680 mm_player_t* player = (mm_player_t*) hplayer;
9684 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9685 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
9687 *num = player->video_num_buffers;
9688 *extra_num = player->video_extra_num_buffers;
9690 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
9693 return MM_ERROR_NONE;
9697 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
9701 MMPLAYER_RETURN_IF_FAIL(player);
9703 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
9705 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
9706 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
9707 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
9708 player->storage_info[i].id = -1;
9709 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
9711 if (path_type != MMPLAYER_PATH_MAX)
9719 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
9721 int ret = MM_ERROR_NONE;
9722 mm_player_t* player = (mm_player_t*)hplayer;
9723 MMMessageParamType msg_param = {0, };
9726 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9728 LOGW("state changed storage %d:%d", id, state);
9730 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
9731 return MM_ERROR_NONE;
9733 /* FIXME: text path should be handled seperately. */
9734 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
9735 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
9736 LOGW("external storage is removed");
9738 if (player->msg_posted == FALSE) {
9739 memset(&msg_param, 0, sizeof(MMMessageParamType));
9740 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9741 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9742 player->msg_posted = TRUE;
9745 /* unrealize the player */
9746 ret = _mmplayer_unrealize(hplayer);
9747 if (ret != MM_ERROR_NONE)
9748 LOGE("failed to unrealize");
9755 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9757 int ret = MM_ERROR_NONE;
9758 mm_player_t* player = (mm_player_t*) hplayer;
9759 int idx = 0, total = 0;
9760 gchar *result = NULL, *tmp = NULL;
9763 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9764 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9766 total = *num = g_list_length(player->adaptive_info.var_list);
9768 LOGW("There is no stream variant info.");
9772 result = g_strdup("");
9773 for (idx = 0 ; idx < total ; idx++) {
9774 VariantData *v_data = NULL;
9775 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9778 gchar data[64] = {0};
9779 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9781 tmp = g_strconcat(result, data, NULL);
9785 LOGW("There is no variant data in %d", idx);
9790 *var_info = (char *)result;
9792 LOGD("variant info %d:%s", *num, *var_info);
9797 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9799 int ret = MM_ERROR_NONE;
9800 mm_player_t* player = (mm_player_t*) hplayer;
9803 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9805 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9807 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9808 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9809 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9811 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9812 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9813 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9814 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9816 /* FIXME: seek to current position for applying new variant limitation */
9824 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9826 int ret = MM_ERROR_NONE;
9827 mm_player_t* player = (mm_player_t*) hplayer;
9830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9831 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9833 *bandwidth = player->adaptive_info.limit.bandwidth;
9834 *width = player->adaptive_info.limit.width;
9835 *height = player->adaptive_info.limit.height;
9837 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9843 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
9845 int ret = MM_ERROR_NONE;
9846 mm_player_t* player = (mm_player_t*) hplayer;
9849 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9851 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9852 LOGW("buffer_ms will not be applied.");
9855 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
9857 if (player->streamer == NULL) {
9858 player->streamer = __mm_player_streaming_create();
9859 __mm_player_streaming_initialize(player->streamer);
9863 player->streamer->buffering_req.prebuffer_time = buffer_ms;
9865 if (rebuffer_ms >= 0)
9866 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
9873 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
9875 int ret = MM_ERROR_NONE;
9876 mm_player_t* player = (mm_player_t*) hplayer;
9879 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9880 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9882 if (player->streamer == NULL) {
9883 player->streamer = __mm_player_streaming_create();
9884 __mm_player_streaming_initialize(player->streamer);
9887 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
9888 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9890 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
9896 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
9898 #define IDX_FIRST_SW_CODEC 0
9899 mm_player_t* player = (mm_player_t*) hplayer;
9900 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
9901 MMHandleType attrs = 0;
9904 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9906 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
9907 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
9908 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
9910 switch (stream_type) {
9911 case MM_PLAYER_STREAM_TYPE_AUDIO:
9912 /* to support audio codec selection, codec info have to be added in ini file as below.
9913 audio codec element hw = xxxx
9914 audio codec element sw = avdec */
9915 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
9916 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
9917 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
9918 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
9919 LOGE("There is no audio codec info for codec_type %d", codec_type);
9920 return MM_ERROR_PLAYER_NO_OP;
9923 case MM_PLAYER_STREAM_TYPE_VIDEO:
9924 /* to support video codec selection, codec info have to be added in ini file as below.
9925 video codec element hw = omx
9926 video codec element sw = avdec */
9927 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
9928 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
9929 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
9930 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
9931 LOGE("There is no video codec info for codec_type %d", codec_type);
9932 return MM_ERROR_PLAYER_NO_OP;
9936 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9937 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9941 LOGD("update %s codec_type to %d", attr_name, codec_type);
9943 attrs = MMPLAYER_GET_ATTRS(player);
9944 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
9946 if (mmf_attrs_commit(player->attrs)) {
9947 LOGE("failed to commit codec_type attributes");
9948 return MM_ERROR_PLAYER_INTERNAL;
9952 return MM_ERROR_NONE;
9956 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9958 mm_player_t* player = (mm_player_t*) hplayer;
9959 GstElement* rg_vol_element = NULL;
9963 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9965 player->sound.rg_enable = enabled;
9967 /* just hold rgvolume enable value if pipeline is not ready */
9968 if (!player->pipeline || !player->pipeline->audiobin) {
9969 LOGD("pipeline is not ready. holding rgvolume enable value\n");
9970 return MM_ERROR_NONE;
9973 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9975 if (!rg_vol_element) {
9976 LOGD("rgvolume element is not created");
9977 return MM_ERROR_PLAYER_INTERNAL;
9981 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9983 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9987 return MM_ERROR_NONE;
9991 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9993 mm_player_t* player = (mm_player_t*) hplayer;
9994 GstElement* rg_vol_element = NULL;
9995 gboolean enable = FALSE;
9999 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10000 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
10002 /* just hold enable_rg value if pipeline is not ready */
10003 if (!player->pipeline || !player->pipeline->audiobin) {
10004 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
10005 *enabled = player->sound.rg_enable;
10006 return MM_ERROR_NONE;
10009 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
10011 if (!rg_vol_element) {
10012 LOGD("rgvolume element is not created");
10013 return MM_ERROR_PLAYER_INTERNAL;
10016 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
10021 return MM_ERROR_NONE;
10025 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
10027 mm_player_t* player = (mm_player_t*) hplayer;
10028 MMHandleType attrs = 0;
10029 void *handle = NULL;
10030 int ret = MM_ERROR_NONE;
10034 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10036 attrs = MMPLAYER_GET_ATTRS(player);
10037 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
10039 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
10041 LOGE("Display handle is NULL, after setting window handle, set video roi area");
10042 return MM_ERROR_PLAYER_INTERNAL;
10045 player->video_roi.scale_x = scale_x;
10046 player->video_roi.scale_y = scale_y;
10047 player->video_roi.scale_width = scale_width;
10048 player->video_roi.scale_height = scale_height;
10050 /* check video sinkbin is created */
10051 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
10052 return MM_ERROR_NONE;
10054 if (!gst_video_overlay_set_video_roi_area(
10055 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
10056 scale_x, scale_y, scale_width, scale_height))
10057 ret = MM_ERROR_PLAYER_INTERNAL;
10059 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
10060 scale_x, scale_y, scale_width, scale_height);
10068 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
10070 mm_player_t* player = (mm_player_t*) hplayer;
10071 int ret = MM_ERROR_NONE;
10075 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10076 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
10078 *scale_x = player->video_roi.scale_x;
10079 *scale_y = player->video_roi.scale_y;
10080 *scale_width = player->video_roi.scale_width;
10081 *scale_height = player->video_roi.scale_height;
10083 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
10084 *scale_x, *scale_y, *scale_width, *scale_height);