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
106 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
107 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
108 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
109 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
111 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
112 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
114 /*---------------------------------------------------------------------------
115 | LOCAL CONSTANT DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------
119 | LOCAL DATA TYPE DEFINITIONS: |
120 ---------------------------------------------------------------------------*/
122 /*---------------------------------------------------------------------------
123 | GLOBAL VARIABLE DEFINITIONS: |
124 ---------------------------------------------------------------------------*/
126 /*---------------------------------------------------------------------------
127 | LOCAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
129 static sound_stream_info_h stream_info;
131 /*---------------------------------------------------------------------------
132 | LOCAL FUNCTION PROTOTYPES: |
133 ---------------------------------------------------------------------------*/
134 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
136 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
137 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
141 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
142 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
143 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
144 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
145 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
146 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
147 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
148 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
149 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
150 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
151 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
153 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static void __mmplayer_release_misc(mm_player_t* player);
155 static void __mmplayer_release_misc_post(mm_player_t* player);
156 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
157 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
158 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
159 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
160 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
161 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
163 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
164 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
165 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
166 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
167 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
168 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
169 static gpointer __mmplayer_next_play_thread(gpointer data);
170 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
171 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
172 static void __mmplayer_release_dump_list(GList *dump_list);
173 static int __mmplayer_gst_realize(mm_player_t* player);
174 static int __mmplayer_gst_unrealize(mm_player_t* player);
175 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
176 static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
177 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
180 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
181 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
182 static int __mmplayer_start_streaming_ext(mm_player_t *player);
183 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
184 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
185 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
186 static void __mmplayer_check_pipeline(mm_player_t* player);
187 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
188 static void __mmplayer_deactivate_old_path(mm_player_t *player);
189 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
190 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
191 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
192 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
193 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
194 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
195 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
197 /*===========================================================================================
199 | FUNCTION DEFINITIONS |
201 ========================================================================================== */
205 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
209 count = gst_tag_list_get_tag_size(list, tag);
211 LOGD("count = %d", count);
213 for (i = 0; i < count; i++) {
216 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
217 if (!gst_tag_list_get_string_index(list, tag, i, &str))
218 g_assert_not_reached();
220 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
223 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
225 g_print(" : %s\n", str);
232 /* This function should be called after the pipeline goes PAUSED or higher
235 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
237 static gboolean has_duration = FALSE;
238 static gboolean has_video_attrs = FALSE;
239 static gboolean has_audio_attrs = FALSE;
240 static gboolean has_bitrate = FALSE;
241 gboolean missing_only = FALSE;
242 gboolean all = FALSE;
244 GstStructure* p = NULL;
245 MMHandleType attrs = 0;
251 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
253 /* check player state here */
254 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
255 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
256 /* give warning now only */
257 LOGW("be careful. content attributes may not available in this state ");
260 /* get content attribute first */
261 attrs = MMPLAYER_GET_ATTRS(player);
263 LOGE("cannot get content attribute");
267 /* get update flag */
269 if (flag & ATTR_MISSING_ONLY) {
271 LOGD("updating missed attr only");
274 if (flag & ATTR_ALL) {
276 has_duration = FALSE;
277 has_video_attrs = FALSE;
278 has_audio_attrs = FALSE;
281 LOGD("updating all attrs");
284 if (missing_only && all) {
285 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
286 missing_only = FALSE;
289 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
290 LOGD("try to update duration");
291 has_duration = FALSE;
293 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
294 player->duration = dur_nsec;
295 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
299 if (player->duration < 0) {
300 LOGW("duration is Non-Initialized !!!");
301 player->duration = 0;
304 /* update streaming service type */
305 player->streaming_type = __mmplayer_get_stream_service_type(player);
307 /* check duration is OK */
308 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
309 /* FIXIT : find another way to get duration here. */
310 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
314 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
315 /* update audio params
316 NOTE : We need original audio params and it can be only obtained from src pad of audio
317 decoder. Below code only valid when we are not using 'resampler' just before
320 LOGD("try to update audio attrs");
321 has_audio_attrs = FALSE;
323 if (player->pipeline->audiobin &&
324 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
325 GstCaps *caps_a = NULL;
327 gint samplerate = 0, channels = 0;
329 pad = gst_element_get_static_pad(
330 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
333 caps_a = gst_pad_get_current_caps(pad);
336 p = gst_caps_get_structure(caps_a, 0);
338 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
340 gst_structure_get_int(p, "rate", &samplerate);
341 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
343 gst_structure_get_int(p, "channels", &channels);
344 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
346 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
348 gst_caps_unref(caps_a);
351 has_audio_attrs = TRUE;
353 LOGW("not ready to get audio caps");
355 gst_object_unref(pad);
357 LOGW("failed to get pad from audiosink");
361 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
362 LOGD("try to update video attrs");
363 has_video_attrs = FALSE;
365 if (player->pipeline->videobin &&
366 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
367 GstCaps *caps_v = NULL;
372 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
374 caps_v = gst_pad_get_current_caps(pad);
376 /* Use v_stream_caps, if fail to get video_sink sink pad*/
377 if (!caps_v && player->v_stream_caps) {
378 caps_v = player->v_stream_caps;
379 gst_caps_ref(caps_v);
383 p = gst_caps_get_structure(caps_v, 0);
384 gst_structure_get_int(p, "width", &width);
385 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
387 gst_structure_get_int(p, "height", &height);
388 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
390 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
392 SECURE_LOGD("width : %d height : %d", width, height);
394 gst_caps_unref(caps_v);
398 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
399 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
402 has_video_attrs = TRUE;
404 LOGD("no negitiated caps from videosink");
405 gst_object_unref(pad);
408 LOGD("no videosink sink pad");
414 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
417 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
418 if (player->duration) {
419 guint64 data_size = 0;
421 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
422 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
424 if (stat(path, &sb) == 0)
425 data_size = (guint64)sb.st_size;
426 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
427 data_size = player->http_content_size;
429 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
433 guint64 msec_dur = 0;
435 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
437 bitrate = data_size * 8 * 1000 / msec_dur;
438 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
439 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
443 LOGD("player duration is less than 0");
447 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
448 if (player->total_bitrate) {
449 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
457 if (mmf_attrs_commit(attrs)) {
458 LOGE("failed to update attributes\n");
467 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
469 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
473 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
475 player->pipeline->mainbin &&
476 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
477 STREAMING_SERVICE_NONE);
479 /* streaming service type if streaming */
480 if (!MMPLAYER_IS_STREAMING(player))
481 return STREAMING_SERVICE_NONE;
483 streaming_type = (player->duration == 0) ?
484 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
486 switch (streaming_type) {
487 case STREAMING_SERVICE_LIVE:
488 LOGD("it's live streaming");
490 case STREAMING_SERVICE_VOD:
491 LOGD("it's vod streaming");
494 LOGE("should not get here");
500 return streaming_type;
504 /* this function sets the player state and also report
505 * it to applicaton by calling callback function
508 __mmplayer_set_state(mm_player_t* player, int state)
510 MMMessageParamType msg = {0, };
511 gboolean post_bos = FALSE;
513 MMPLAYER_RETURN_IF_FAIL(player);
515 if (MMPLAYER_CURRENT_STATE(player) == state) {
516 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
517 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
521 /* update player states */
522 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
523 MMPLAYER_CURRENT_STATE(player) = state;
525 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
526 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
529 MMPLAYER_PRINT_STATE(player);
531 switch (MMPLAYER_CURRENT_STATE(player)) {
532 case MM_PLAYER_STATE_NULL:
533 case MM_PLAYER_STATE_READY:
536 case MM_PLAYER_STATE_PAUSED:
538 if (!player->sent_bos) {
539 /* rtsp case, get content attrs by GstMessage */
540 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
541 /* it's first time to update all content attrs. */
542 __mmplayer_update_content_attrs(player, ATTR_ALL);
546 /* add audio callback probe if condition is satisfied */
547 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
548 __mmplayer_configure_audio_callback(player);
550 /* FIXIT : handle return value */
554 case MM_PLAYER_STATE_PLAYING:
556 /* try to get content metadata */
557 if (!player->sent_bos) {
558 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
559 * c-api since c-api doesn't use _start() anymore. It may not work propery with
560 * legacy mmfw-player api */
561 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
564 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
565 if (!player->sent_bos)
566 __mmplayer_handle_missed_plugin(player);
569 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
570 /* initialize because auto resume is done well. */
571 player->resumed_by_rewind = FALSE;
572 player->playback_rate = 1.0;
575 if (!player->sent_bos) {
576 /* check audio codec field is set or not
577 * we can get it from typefinder or codec's caps.
579 gchar *audio_codec = NULL;
580 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
582 /* The codec format can't be sent for audio only case like amr, mid etc.
583 * Because, parser don't make related TAG.
584 * So, if it's not set yet, fill it with found data.
587 if (g_strrstr(player->type, "audio/midi"))
588 audio_codec = g_strdup("MIDI");
589 else if (g_strrstr(player->type, "audio/x-amr"))
590 audio_codec = g_strdup("AMR");
591 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
592 audio_codec = g_strdup("AAC");
594 audio_codec = g_strdup("unknown");
595 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
597 MMPLAYER_FREEIF(audio_codec);
598 if (mmf_attrs_commit(player->attrs))
599 LOGE("failed to update attributes\n");
601 LOGD("set audio codec type with caps\n");
609 case MM_PLAYER_STATE_NONE:
611 LOGW("invalid target state, there is nothing to do.\n");
616 /* post message to application */
617 if (MMPLAYER_TARGET_STATE(player) == state) {
618 /* fill the message with state of player */
619 msg.union_type = MM_MSG_UNION_STATE;
620 msg.state.previous = MMPLAYER_PREV_STATE(player);
621 msg.state.current = MMPLAYER_CURRENT_STATE(player);
623 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
625 /* state changed by resource callback */
626 if (player->interrupted_by_resource) {
627 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
628 } else { /* state changed by usecase */
629 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
632 LOGD("intermediate state, do nothing.\n");
633 MMPLAYER_PRINT_STATE(player);
638 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
639 player->sent_bos = TRUE;
646 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
648 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
649 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
653 //LOGD("incomming command : %d \n", command);
655 current_state = MMPLAYER_CURRENT_STATE(player);
656 pending_state = MMPLAYER_PENDING_STATE(player);
658 MMPLAYER_PRINT_STATE(player);
661 case MMPLAYER_COMMAND_CREATE:
663 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
665 if (current_state == MM_PLAYER_STATE_NULL ||
666 current_state == MM_PLAYER_STATE_READY ||
667 current_state == MM_PLAYER_STATE_PAUSED ||
668 current_state == MM_PLAYER_STATE_PLAYING)
673 case MMPLAYER_COMMAND_DESTROY:
675 /* destroy can called anytime */
677 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
681 case MMPLAYER_COMMAND_REALIZE:
683 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
685 if (pending_state != MM_PLAYER_STATE_NONE) {
688 /* need ready state to realize */
689 if (current_state == MM_PLAYER_STATE_READY)
692 if (current_state != MM_PLAYER_STATE_NULL)
698 case MMPLAYER_COMMAND_UNREALIZE:
700 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
702 if (current_state == MM_PLAYER_STATE_NULL)
707 case MMPLAYER_COMMAND_START:
709 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
711 if (pending_state == MM_PLAYER_STATE_NONE) {
712 if (current_state == MM_PLAYER_STATE_PLAYING)
714 else if (current_state != MM_PLAYER_STATE_READY &&
715 current_state != MM_PLAYER_STATE_PAUSED)
717 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
719 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
720 LOGD("player is going to paused state, just change the pending state as playing");
726 case MMPLAYER_COMMAND_STOP:
728 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
730 if (current_state == MM_PLAYER_STATE_READY)
733 /* need playing/paused state to stop */
734 if (current_state != MM_PLAYER_STATE_PLAYING &&
735 current_state != MM_PLAYER_STATE_PAUSED)
740 case MMPLAYER_COMMAND_PAUSE:
742 if (MMPLAYER_IS_LIVE_STREAMING(player))
745 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
746 goto NOT_COMPLETED_SEEK;
748 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
750 if (pending_state == MM_PLAYER_STATE_NONE) {
751 if (current_state == MM_PLAYER_STATE_PAUSED)
753 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
755 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
757 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
758 if (current_state == MM_PLAYER_STATE_PAUSED)
759 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
766 case MMPLAYER_COMMAND_RESUME:
768 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
769 goto NOT_COMPLETED_SEEK;
771 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
773 if (pending_state == MM_PLAYER_STATE_NONE) {
774 if (current_state == MM_PLAYER_STATE_PLAYING)
776 else if (current_state != MM_PLAYER_STATE_PAUSED)
778 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
780 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
781 LOGD("player is going to paused state, just change the pending state as playing");
790 player->cmd = command;
792 return MM_ERROR_NONE;
795 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
796 MMPLAYER_STATE_GET_NAME(current_state), command);
797 return MM_ERROR_PLAYER_INVALID_STATE;
800 LOGW("not completed seek");
801 return MM_ERROR_PLAYER_DOING_SEEK;
804 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
805 return MM_ERROR_PLAYER_NO_OP;
808 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
809 return MM_ERROR_PLAYER_NO_OP;
812 static gpointer __mmplayer_next_play_thread(gpointer data)
814 mm_player_t* player = (mm_player_t*) data;
815 MMPlayerGstElement *mainbin = NULL;
817 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
819 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
820 while (!player->next_play_thread_exit) {
821 LOGD("next play thread started. waiting for signal.\n");
822 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
824 LOGD("reconfigure pipeline for gapless play.\n");
826 if (player->next_play_thread_exit) {
827 if (player->gapless.reconfigure) {
828 player->gapless.reconfigure = false;
829 MMPLAYER_PLAYBACK_UNLOCK(player);
831 LOGD("exiting gapless play thread\n");
835 mainbin = player->pipeline->mainbin;
837 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
838 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
839 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
840 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
841 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
843 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
845 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
851 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
853 GSource *source = NULL;
857 source = g_main_context_find_source_by_id(context, source_id);
859 if (source != NULL) {
860 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
861 g_source_destroy(source);
867 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
869 mm_player_t* player = (mm_player_t*)hplayer;
870 GstMessage *msg = NULL;
871 GQueue *queue = NULL;
874 MMPLAYER_RETURN_IF_FAIL(player);
876 /* disconnecting bus watch */
877 if (player->bus_watcher)
878 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
879 player->bus_watcher = 0;
881 /* destroy the gst bus msg thread */
882 if (player->bus_msg_thread) {
883 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
884 player->bus_msg_thread_exit = TRUE;
885 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
886 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
888 LOGD("gst bus msg thread exit.");
889 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
890 player->bus_msg_thread = NULL;
892 g_mutex_clear(&player->bus_msg_thread_mutex);
893 g_cond_clear(&player->bus_msg_thread_cond);
896 g_mutex_lock(&player->bus_msg_q_lock);
897 queue = player->bus_msg_q;
898 while (!g_queue_is_empty(queue)) {
899 msg = (GstMessage *)g_queue_pop_head(queue);
900 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
901 gst_message_unref(msg);
903 g_mutex_unlock(&player->bus_msg_q_lock);
909 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
911 GstElement* parent = NULL;
913 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
915 /* if we have no fakesink. this meas we are using decodebin which doesn'
916 t need to add extra fakesink */
917 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
920 MMPLAYER_FSINK_LOCK(player);
925 /* get parent of fakesink */
926 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
928 LOGD("fakesink already removed\n");
932 gst_element_set_locked_state(fakesink->gst, TRUE);
934 /* setting the state to NULL never returns async
935 * so no need to wait for completion of state transiton
937 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
938 LOGE("fakesink state change failure!\n");
939 /* FIXIT : should I return here? or try to proceed to next? */
942 /* remove fakesink from it's parent */
943 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
944 LOGE("failed to remove fakesink\n");
946 gst_object_unref(parent);
951 gst_object_unref(parent);
953 LOGD("state-holder removed\n");
955 gst_element_set_locked_state(fakesink->gst, FALSE);
957 MMPLAYER_FSINK_UNLOCK(player);
962 gst_element_set_locked_state(fakesink->gst, FALSE);
964 MMPLAYER_FSINK_UNLOCK(player);
968 static GstPadProbeReturn
969 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
971 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
972 return GST_PAD_PROBE_OK;
976 __mmplayer_gst_selector_update_start_time(mm_player_t* player, MMPlayerTrackType stream_type)
978 gint64 stop_running_time = 0;
979 gint64 position_running_time = 0;
983 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
984 if ((player->gapless.update_segment[idx] == TRUE) ||
985 !(player->selector[idx].event_probe_id)) {
986 /* LOGW("[%d] skip", idx); */
990 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
992 gst_segment_to_running_time(&player->gapless.segment[idx],
993 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
994 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
996 gst_segment_to_running_time(&player->gapless.segment[idx],
997 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
999 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
1001 gst_segment_to_running_time(&player->gapless.segment[idx],
1002 GST_FORMAT_TIME, player->duration);
1005 position_running_time =
1006 gst_segment_to_running_time(&player->gapless.segment[idx],
1007 GST_FORMAT_TIME, player->gapless.segment[idx].position);
1009 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
1010 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
1012 GST_TIME_ARGS(stop_running_time),
1013 GST_TIME_ARGS(position_running_time),
1014 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
1015 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
1017 position_running_time = MAX(position_running_time, stop_running_time);
1018 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
1019 GST_FORMAT_TIME, player->gapless.segment[idx].start);
1020 position_running_time = MAX(0, position_running_time);
1021 position = MAX(position, position_running_time);
1024 if (position != 0) {
1025 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1026 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
1027 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
1029 player->gapless.start_time[stream_type] += position;
1035 static GstPadProbeReturn
1036 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
1038 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1039 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
1040 mm_player_t* player = (mm_player_t*)data;
1041 GstCaps* caps = NULL;
1042 GstStructure* str = NULL;
1043 const gchar* name = NULL;
1044 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1046 if (GST_EVENT_IS_DOWNSTREAM(event) &&
1047 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1048 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1049 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1050 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
1052 } else if (GST_EVENT_IS_UPSTREAM(event) &&
1053 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
1057 caps = gst_pad_query_caps(pad, NULL);
1059 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
1063 str = gst_caps_get_structure(caps, 0);
1065 LOGE("failed to get structure from caps");
1069 name = gst_structure_get_name(str);
1071 LOGE("failed to get name from str");
1075 if (strstr(name, "audio")) {
1076 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1077 } else if (strstr(name, "video")) {
1078 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1080 /* text track is not supportable */
1081 LOGE("invalid name %s", name);
1085 switch (GST_EVENT_TYPE(event)) {
1088 /* in case of gapless, drop eos event not to send it to sink */
1089 if (player->gapless.reconfigure && !player->msg_posted) {
1090 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1091 ret = GST_PAD_PROBE_DROP;
1095 case GST_EVENT_STREAM_START:
1097 __mmplayer_gst_selector_update_start_time(player, stream_type);
1100 case GST_EVENT_FLUSH_STOP:
1102 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1103 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1104 player->gapless.start_time[stream_type] = 0;
1107 case GST_EVENT_SEGMENT:
1112 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1113 gst_event_copy_segment(event, &segment);
1115 if (segment.format != GST_FORMAT_TIME)
1118 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1119 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1120 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1121 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1122 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1123 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1125 /* keep the all the segment ev to cover the seeking */
1126 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1127 player->gapless.update_segment[stream_type] = TRUE;
1129 if (!player->gapless.running)
1132 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1134 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1136 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1137 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1138 gst_event_unref(event);
1139 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1145 gdouble proportion = 0.0;
1146 GstClockTimeDiff diff = 0;
1147 GstClockTime timestamp = 0;
1148 gint64 running_time_diff = -1;
1149 GstQOSType type = 0;
1150 GstEvent *tmpev = NULL;
1152 running_time_diff = player->gapless.segment[stream_type].base;
1154 if (running_time_diff <= 0) /* don't need to adjust */
1157 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1158 gst_event_unref(event);
1160 if (timestamp < running_time_diff) {
1161 LOGW("QOS event from previous group");
1162 ret = GST_PAD_PROBE_DROP;
1166 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1167 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1168 stream_type, GST_TIME_ARGS(timestamp),
1169 GST_TIME_ARGS(running_time_diff),
1170 GST_TIME_ARGS(timestamp - running_time_diff));
1172 timestamp -= running_time_diff;
1174 /* That case is invalid for QoS events */
1175 if (diff < 0 && -diff > timestamp) {
1176 LOGW("QOS event from previous group");
1177 ret = GST_PAD_PROBE_DROP;
1181 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1182 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1192 gst_caps_unref(caps);
1197 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1199 mm_player_t* player = NULL;
1200 GstElement* pipeline = NULL;
1201 GstElement* selector = NULL;
1202 GstElement* fakesink = NULL;
1203 GstCaps* caps = NULL;
1204 GstStructure* str = NULL;
1205 const gchar* name = NULL;
1206 GstPad* sinkpad = NULL;
1207 GstPad* srcpad = NULL;
1208 gboolean first_track = FALSE;
1210 enum MainElementID elemId = MMPLAYER_M_NUM;
1211 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1214 player = (mm_player_t*)data;
1216 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1217 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1219 //LOGD("pad-added signal handling\n");
1221 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1223 /* get mimetype from caps */
1224 caps = gst_pad_query_caps(pad, NULL);
1226 LOGE("cannot get caps from pad.\n");
1230 str = gst_caps_get_structure(caps, 0);
1232 LOGE("cannot get structure from caps.\n");
1236 name = gst_structure_get_name(str);
1238 LOGE("cannot get mimetype from structure.\n");
1242 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1243 //LOGD("detected mimetype : %s\n", name);
1245 if (strstr(name, "video")) {
1248 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1249 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1251 /* don't make video because of not required, and not support multiple track */
1252 if (stype == MM_DISPLAY_SURFACE_NULL) {
1253 LOGD("no video sink by null surface");
1255 gchar *caps_str = gst_caps_to_string(caps);
1256 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1257 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1258 player->set_mode.video_zc = TRUE;
1260 MMPLAYER_FREEIF(caps_str);
1262 if (player->v_stream_caps) {
1263 gst_caps_unref(player->v_stream_caps);
1264 player->v_stream_caps = NULL;
1267 LOGD("create fakesink instead of videobin");
1270 fakesink = gst_element_factory_make("fakesink", NULL);
1271 if (fakesink == NULL) {
1272 LOGE("ERROR : fakesink create error\n");
1276 if (player->ini.set_dump_element_flag)
1277 __mmplayer_add_dump_buffer_probe(player, fakesink);
1279 player->video_fakesink = fakesink;
1281 /* store it as it's sink element */
1282 __mmplayer_add_sink(player, player->video_fakesink);
1284 gst_bin_add(GST_BIN(pipeline), fakesink);
1287 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1289 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1290 LOGW("failed to link fakesink\n");
1291 gst_object_unref(GST_OBJECT(fakesink));
1295 if (player->set_mode.media_packet_video_stream) {
1296 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
1298 __mmplayer_add_signal_connection(player,
1300 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1302 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
1305 __mmplayer_add_signal_connection(player,
1307 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1309 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
1313 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
1314 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1318 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1319 __mmplayer_gst_decode_callback(elem, pad, player);
1323 LOGD("video selector \n");
1324 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
1325 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1327 if (strstr(name, "audio")) {
1328 gint samplerate = 0;
1331 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1332 __mmplayer_gst_decode_callback(elem, pad, player);
1336 LOGD("audio selector \n");
1337 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
1338 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1340 gst_structure_get_int(str, "rate", &samplerate);
1341 gst_structure_get_int(str, "channels", &channels);
1343 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
1345 fakesink = gst_element_factory_make("fakesink", NULL);
1346 if (fakesink == NULL) {
1347 LOGE("ERROR : fakesink create error\n");
1351 gst_bin_add(GST_BIN(pipeline), fakesink);
1354 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1356 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1357 LOGW("failed to link fakesink\n");
1358 gst_object_unref(GST_OBJECT(fakesink));
1362 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1363 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1367 } else if (strstr(name, "text")) {
1368 LOGD("text selector \n");
1369 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
1370 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1372 LOGE("wrong elem id \n");
1377 selector = player->pipeline->mainbin[elemId].gst;
1378 if (selector == NULL) {
1379 selector = gst_element_factory_make("input-selector", NULL);
1380 LOGD("Creating input-selector\n");
1381 if (selector == NULL) {
1382 LOGE("ERROR : input-selector create error\n");
1385 g_object_set(selector, "sync-streams", TRUE, NULL);
1387 player->pipeline->mainbin[elemId].id = elemId;
1388 player->pipeline->mainbin[elemId].gst = selector;
1391 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
1393 srcpad = gst_element_get_static_pad(selector, "src");
1395 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1396 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1397 __mmplayer_gst_selector_blocked, NULL, NULL);
1398 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1399 __mmplayer_gst_selector_event_probe, player, NULL);
1401 gst_element_set_state(selector, GST_STATE_PAUSED);
1402 gst_bin_add(GST_BIN(pipeline), selector);
1404 LOGD("input-selector is already created.\n");
1407 LOGD("Calling request pad with selector %p \n", selector);
1408 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1410 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
1412 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1413 LOGW("failed to link selector\n");
1414 gst_object_unref(GST_OBJECT(selector));
1419 LOGD("this is first track --> active track \n");
1420 g_object_set(selector, "active-pad", sinkpad, NULL);
1423 __mmplayer_track_update_info(player, stream_type, sinkpad);
1430 gst_caps_unref(caps);
1433 gst_object_unref(GST_OBJECT(sinkpad));
1438 gst_object_unref(GST_OBJECT(srcpad));
1445 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
1447 GstPad* srcpad = NULL;
1448 MMHandleType attrs = 0;
1449 gint active_index = 0;
1451 // [link] input-selector :: textbin
1452 srcpad = gst_element_get_static_pad(text_selector, "src");
1454 LOGE("failed to get srcpad from selector\n");
1458 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
1460 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
1461 if ((active_index != DEFAULT_TRACK) &&
1462 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
1463 LOGW("failed to change text track\n");
1464 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
1467 player->no_more_pad = TRUE;
1468 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
1470 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1471 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
1472 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
1473 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
1476 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1478 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1479 player->has_closed_caption = TRUE;
1481 attrs = MMPLAYER_GET_ATTRS(player);
1483 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1484 if (mmf_attrs_commit(attrs))
1485 LOGE("failed to commit.\n");
1487 LOGE("cannot get content attribute");
1490 gst_object_unref(GST_OBJECT(srcpad));
1496 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t* player = (mm_player_t*)data;
1499 GstElement* selector = NULL;
1500 GstElement* queue = NULL;
1502 GstPad* srcpad = NULL;
1503 GstPad* sinkpad = NULL;
1504 GstCaps* caps = NULL;
1505 gchar* caps_str = NULL;
1508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1510 caps = gst_pad_get_current_caps(pad);
1511 caps_str = gst_caps_to_string(caps);
1512 LOGD("deinterleave new caps : %s\n", caps_str);
1513 MMPLAYER_FREEIF(caps_str);
1514 gst_caps_unref(caps);
1516 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
1517 LOGE("ERROR : queue create error\n");
1521 g_object_set(G_OBJECT(queue),
1522 "max-size-buffers", 10,
1523 "max-size-bytes", 0,
1524 "max-size-time", (guint64)0,
1527 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1530 LOGE("there is no audio channel selector.\n");
1534 srcpad = gst_element_get_static_pad(queue, "src");
1535 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1537 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
1539 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1540 LOGW("failed to link deinterleave - selector\n");
1544 gst_element_set_state(queue, GST_STATE_PAUSED);
1545 player->audio_mode.total_track_num++;
1550 gst_object_unref(GST_OBJECT(srcpad));
1555 gst_object_unref(GST_OBJECT(sinkpad));
1564 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
1566 mm_player_t* player = NULL;
1567 GstElement* selector = NULL;
1568 GstPad* sinkpad = NULL;
1569 gint active_index = 0;
1570 gchar* change_pad_name = NULL;
1571 GstCaps* caps = NULL; // no need to unref
1572 gint default_audio_ch = 0;
1575 player = (mm_player_t*) data;
1577 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1580 LOGE("there is no audio channel selector.\n");
1584 active_index = player->audio_mode.active_pad_index;
1586 if (active_index != default_audio_ch) {
1587 gint audio_ch = default_audio_ch;
1589 /*To get the new pad from the selector*/
1590 change_pad_name = g_strdup_printf("sink%d", active_index);
1591 if (change_pad_name != NULL) {
1592 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
1593 if (sinkpad != NULL) {
1594 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
1595 g_object_set(selector, "active-pad", sinkpad, NULL);
1597 audio_ch = active_index;
1599 caps = gst_pad_get_current_caps(sinkpad);
1600 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1602 __mmplayer_set_audio_attrs(player, caps);
1603 gst_caps_unref(caps);
1605 MMPLAYER_FREEIF(change_pad_name);
1608 player->audio_mode.active_pad_index = audio_ch;
1609 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
1615 gst_object_unref(sinkpad);
1622 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
1624 mm_player_t* player = NULL;
1625 MMPlayerGstElement *mainbin = NULL;
1627 GstElement* tee = NULL;
1628 GstElement* stereo_queue = NULL;
1629 GstElement* mono_queue = NULL;
1630 GstElement* conv = NULL;
1631 GstElement* filter = NULL;
1632 GstElement* deinterleave = NULL;
1633 GstElement* selector = NULL;
1635 GstPad* srcpad = NULL;
1636 GstPad* selector_srcpad = NULL;
1637 GstPad* sinkpad = NULL;
1638 GstCaps* caps = NULL;
1639 gulong block_id = 0;
1644 player = (mm_player_t*) data;
1646 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1647 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1649 mainbin = player->pipeline->mainbin;
1652 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
1653 LOGE("ERROR : tee create error\n");
1657 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
1658 mainbin[MMPLAYER_M_A_TEE].gst = tee;
1660 gst_element_set_state(tee, GST_STATE_PAUSED);
1663 srcpad = gst_element_get_request_pad(tee, "src_%u");
1664 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1665 LOGE("ERROR : stereo queue create error\n");
1669 g_object_set(G_OBJECT(stereo_queue),
1670 "max-size-buffers", 10,
1671 "max-size-bytes", 0,
1672 "max-size-time", (guint64)0,
1675 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
1676 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
1679 gst_object_unref(GST_OBJECT(srcpad));
1683 srcpad = gst_element_get_request_pad(tee, "src_%u");
1685 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1686 LOGE("ERROR : mono queue create error\n");
1690 g_object_set(G_OBJECT(mono_queue),
1691 "max-size-buffers", 10,
1692 "max-size-bytes", 0,
1693 "max-size-time", (guint64)0,
1696 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
1697 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
1699 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
1700 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
1703 srcpad = gst_element_get_static_pad(mono_queue, "src");
1704 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
1705 LOGE("ERROR : audioconvert create error\n");
1709 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
1710 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
1714 gst_object_unref(GST_OBJECT(srcpad));
1717 srcpad = gst_element_get_static_pad(conv, "src");
1719 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
1720 LOGE("ERROR : capsfilter create error\n");
1724 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
1725 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
1727 caps = gst_caps_from_string("audio/x-raw-int, "
1728 "width = (int) 16, "
1729 "depth = (int) 16, "
1730 "channels = (int) 2");
1732 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
1733 gst_caps_unref(caps);
1735 gst_element_set_state(conv, GST_STATE_PAUSED);
1736 gst_element_set_state(filter, GST_STATE_PAUSED);
1740 gst_object_unref(GST_OBJECT(srcpad));
1743 srcpad = gst_element_get_static_pad(filter, "src");
1745 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
1746 LOGE("ERROR : deinterleave create error\n");
1750 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
1752 __mmplayer_add_signal_connection(player, G_OBJECT(deinterleave), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
1753 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), (gpointer)player);
1755 __mmplayer_add_signal_connection(player, G_OBJECT(deinterleave), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
1756 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), (gpointer)player);
1758 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
1759 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
1762 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
1763 if (selector == NULL) {
1764 LOGE("ERROR : audio-selector create error\n");
1768 g_object_set(selector, "sync-streams", TRUE, NULL);
1769 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
1771 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
1772 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
1774 selector_srcpad = gst_element_get_static_pad(selector, "src");
1776 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
1778 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1779 __mmplayer_gst_selector_blocked, NULL, NULL);
1782 gst_object_unref(GST_OBJECT(srcpad));
1786 srcpad = gst_element_get_static_pad(stereo_queue, "src");
1787 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1789 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1790 LOGW("failed to link queue_stereo - selector\n");
1794 player->audio_mode.total_track_num++;
1796 g_object_set(selector, "active-pad", sinkpad, NULL);
1797 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
1798 gst_element_set_state(selector, GST_STATE_PAUSED);
1800 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
1804 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
1805 if (block_id != 0) {
1806 gst_pad_remove_probe(selector_srcpad, block_id);
1811 gst_object_unref(GST_OBJECT(sinkpad));
1816 gst_object_unref(GST_OBJECT(srcpad));
1820 if (selector_srcpad) {
1821 gst_object_unref(GST_OBJECT(selector_srcpad));
1822 selector_srcpad = NULL;
1830 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1832 mm_player_t* player = NULL;
1833 GstPad* srcpad = NULL;
1834 GstElement* video_selector = NULL;
1835 GstElement* audio_selector = NULL;
1836 GstElement* text_selector = NULL;
1837 MMHandleType attrs = 0;
1838 gint active_index = 0;
1839 gint64 dur_bytes = 0L;
1841 player = (mm_player_t*) data;
1843 LOGD("no-more-pad signal handling\n");
1845 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1846 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1847 LOGW("no need to go more");
1849 if (player->gapless.reconfigure) {
1850 player->gapless.reconfigure = FALSE;
1851 MMPLAYER_PLAYBACK_UNLOCK(player);
1857 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
1858 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
1859 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1860 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1861 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1863 if (NULL == player->streamer) {
1864 LOGW("invalid state for buffering");
1868 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1869 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1871 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1872 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
1874 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1876 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1877 LOGE("fail to get duration.\n");
1879 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1880 * use file information was already set on Q2 when it was created. */
1881 __mm_player_streaming_set_queue2(player->streamer,
1882 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1883 TRUE, /* use_buffering */
1885 init_buffering_time,
1886 1.0, /* low percent */
1887 player->ini.http_buffering_limit, /* high percent */
1888 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1890 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1893 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1894 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1895 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1896 if (video_selector) {
1897 // [link] input-selector :: videobin
1898 srcpad = gst_element_get_static_pad(video_selector, "src");
1900 LOGE("failed to get srcpad from video selector\n");
1904 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
1905 if (!text_selector && !audio_selector)
1906 player->no_more_pad = TRUE;
1908 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
1910 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1911 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
1912 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
1913 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
1917 if (audio_selector) {
1918 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
1919 if ((active_index != DEFAULT_TRACK) &&
1920 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
1921 LOGW("failed to change audio track\n");
1922 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
1925 // [link] input-selector :: audiobin
1926 srcpad = gst_element_get_static_pad(audio_selector, "src");
1928 LOGE("failed to get srcpad from selector\n");
1932 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
1934 player->no_more_pad = TRUE;
1936 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
1937 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1938 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
1939 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
1940 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
1943 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
1945 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
1947 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1948 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
1949 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
1950 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
1954 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
1956 attrs = MMPLAYER_GET_ATTRS(player);
1958 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
1959 if (mmf_attrs_commit(attrs))
1960 LOGE("failed to commit.\n");
1962 LOGE("cannot get content attribute");
1964 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1965 LOGD("There is no audio track : remove audiobin");
1967 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1968 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1970 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1971 MMPLAYER_FREEIF(player->pipeline->audiobin);
1974 if (player->num_dynamic_pad == 0)
1975 __mmplayer_pipeline_complete(NULL, player);
1978 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
1980 __mmplayer_handle_text_decode_path(player, text_selector);
1987 gst_object_unref(GST_OBJECT(srcpad));
1991 if (player->gapless.reconfigure) {
1992 player->gapless.reconfigure = FALSE;
1993 MMPLAYER_PLAYBACK_UNLOCK(player);
1998 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
2000 mm_player_t* player = NULL;
2001 MMHandleType attrs = 0;
2002 GstElement* pipeline = NULL;
2003 GstCaps* caps = NULL;
2004 gchar* caps_str = NULL;
2005 GstStructure* str = NULL;
2006 const gchar* name = NULL;
2007 GstPad* sinkpad = NULL;
2008 GstElement* sinkbin = NULL;
2009 gboolean reusing = FALSE;
2010 GstElement *text_selector = NULL;
2013 player = (mm_player_t*) data;
2015 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2016 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2018 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2020 attrs = MMPLAYER_GET_ATTRS(player);
2022 LOGE("cannot get content attribute\n");
2026 /* get mimetype from caps */
2027 caps = gst_pad_query_caps(pad, NULL);
2029 LOGE("cannot get caps from pad.\n");
2032 caps_str = gst_caps_to_string(caps);
2034 str = gst_caps_get_structure(caps, 0);
2036 LOGE("cannot get structure from caps.\n");
2040 name = gst_structure_get_name(str);
2042 LOGE("cannot get mimetype from structure.\n");
2046 //LOGD("detected mimetype : %s\n", name);
2048 if (strstr(name, "audio")) {
2049 if (player->pipeline->audiobin == NULL) {
2050 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
2051 LOGE("failed to create audiobin. continuing without audio\n");
2055 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2056 LOGD("creating audiosink bin success\n");
2059 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2060 LOGD("reusing audiobin\n");
2061 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2064 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
2065 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2067 player->audiosink_linked = 1;
2069 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2071 LOGE("failed to get pad from sinkbin\n");
2074 } else if (strstr(name, "video")) {
2075 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2076 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2077 player->set_mode.video_zc = TRUE;
2079 if (player->pipeline->videobin == NULL) {
2080 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
2081 /* get video surface type */
2082 int surface_type = 0;
2083 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2084 LOGD("display_surface_type(%d)\n", surface_type);
2086 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
2087 LOGD("not make videobin because it dose not want\n");
2091 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
2092 /* mark video overlay for acquire */
2093 if (player->video_overlay_resource == NULL) {
2094 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
2095 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2096 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2097 &player->video_overlay_resource)
2098 != MM_RESOURCE_MANAGER_ERROR_NONE) {
2099 LOGE("could not mark video_overlay resource for acquire\n");
2105 player->interrupted_by_resource = FALSE;
2106 /* acquire resources for video overlay */
2107 if (mm_resource_manager_commit(player->resource_manager) !=
2108 MM_RESOURCE_MANAGER_ERROR_NONE) {
2109 LOGE("could not acquire resources for video playing\n");
2113 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
2114 LOGE("failed to create videobin. continuing without video\n");
2118 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2119 LOGD("creating videosink bin success\n");
2122 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2123 LOGD("re-using videobin\n");
2124 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2127 player->videosink_linked = 1;
2129 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2131 LOGE("failed to get pad from sinkbin\n");
2134 } else if (strstr(name, "text")) {
2135 if (player->pipeline->textbin == NULL) {
2136 MMPlayerGstElement* mainbin = NULL;
2138 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
2139 LOGE("failed to create text sink bin. continuing without text\n");
2143 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2144 LOGD("creating textsink bin success\n");
2146 /* FIXIT : track number shouldn't be hardcoded */
2147 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2149 player->textsink_linked = 1;
2150 LOGI("player->textsink_linked set to 1\n");
2152 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
2154 LOGE("failed to get pad from sinkbin\n");
2158 mainbin = player->pipeline->mainbin;
2160 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
2161 /* input selector */
2162 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
2163 if (!text_selector) {
2164 LOGE("failed to create subtitle input selector element\n");
2167 g_object_set(text_selector, "sync-streams", TRUE, NULL);
2169 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
2170 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
2173 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
2174 LOGE("failed to set state(READY) to sinkbin\n");
2178 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
2179 LOGW("failed to add subtitle input selector\n");
2183 LOGD("created element input-selector");
2186 LOGD("already having subtitle input selector");
2187 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
2190 if (!player->textsink_linked) {
2191 LOGD("re-using textbin\n");
2194 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2196 player->textsink_linked = 1;
2197 LOGI("player->textsink_linked set to 1\n");
2199 LOGD("ignoring internal subtutle since external subtitle is available");
2202 LOGW("unknown type of elementary stream!ignoring it...\n");
2209 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
2210 LOGE("failed to set state(READY) to sinkbin\n");
2214 /* Added for multi audio support to avoid adding audio bin again*/
2216 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
2217 LOGE("failed to add sinkbin to pipeline\n");
2223 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2224 LOGE("failed to get pad from sinkbin\n");
2230 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
2231 LOGE("failed to set state(PAUSED) to sinkbin\n");
2235 if (text_selector) {
2236 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
2237 LOGE("failed to set state(PAUSED) to sinkbin\n");
2243 gst_object_unref(sinkpad);
2247 LOGD("[handle: %p] linking sink bin success", player);
2249 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2250 * streaming task. if the task blocked, then buffer will not flow to the next element
2251 *(autoplugging element). so this is special hack for streaming. please try to remove it
2253 /* dec stream count. we can remove fakesink if it's zero */
2254 if (player->num_dynamic_pad)
2255 player->num_dynamic_pad--;
2257 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
2259 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
2260 __mmplayer_pipeline_complete(NULL, player);
2264 MMPLAYER_FREEIF(caps_str);
2267 gst_caps_unref(caps);
2270 gst_object_unref(GST_OBJECT(sinkpad));
2272 /* flusing out new attributes */
2273 if (mmf_attrs_commit(attrs))
2274 LOGE("failed to comit attributes\n");
2280 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
2282 int required_angle = 0; /* Angle required for straight view */
2283 int rotation_angle = 0;
2285 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2286 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
2288 /* Counter clockwise */
2289 switch (orientation) {
2294 required_angle = 270;
2297 required_angle = 180;
2300 required_angle = 90;
2304 rotation_angle = display_angle + required_angle;
2305 if (rotation_angle >= 360)
2306 rotation_angle -= 360;
2308 /* chech if supported or not */
2309 if (rotation_angle % 90) {
2310 LOGD("not supported rotation angle = %d", rotation_angle);
2314 switch (rotation_angle) {
2316 *value = MM_DISPLAY_ROTATION_NONE;
2319 *value = MM_DISPLAY_ROTATION_90;
2322 *value = MM_DISPLAY_ROTATION_180;
2325 *value = MM_DISPLAY_ROTATION_270;
2329 LOGD("setting rotation property value : %d", value);
2335 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
2337 /* check video sinkbin is created */
2338 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2340 player->pipeline->videobin &&
2341 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2342 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2343 MM_ERROR_PLAYER_NOT_INITIALIZED);
2345 return MM_ERROR_NONE;
2349 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
2351 int display_rotation = 0;
2352 gchar *org_orient = NULL;
2353 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
2356 LOGE("cannot get content attribute");
2357 return MM_ERROR_PLAYER_INTERNAL;
2360 if (display_angle) {
2361 /* update user roation */
2362 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
2364 /* Counter clockwise */
2365 switch (display_rotation) {
2366 case MM_DISPLAY_ROTATION_NONE:
2369 case MM_DISPLAY_ROTATION_90:
2370 *display_angle = 90;
2372 case MM_DISPLAY_ROTATION_180:
2373 *display_angle = 180;
2375 case MM_DISPLAY_ROTATION_270:
2376 *display_angle = 270;
2379 LOGW("wrong angle type : %d", display_rotation);
2382 LOGD("check user angle: %d", *display_angle);
2386 /* Counter clockwise */
2387 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2390 if (!strcmp(org_orient, "rotate-90"))
2392 else if (!strcmp(org_orient, "rotate-180"))
2394 else if (!strcmp(org_orient, "rotate-270"))
2397 LOGD("original rotation is %s", org_orient);
2399 LOGD("content_video_orientation get fail");
2402 LOGD("check orientation: %d", *orientation);
2405 return MM_ERROR_NONE;
2409 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
2411 int rotation_value = 0;
2412 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2413 int display_angle = 0;
2416 /* check video sinkbin is created */
2417 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2420 __mmplayer_get_video_angle(player, &display_angle, &orientations);
2422 /* get rotation value to set */
2423 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2424 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2425 LOGD("set video param : rotate %d", rotation_value);
2429 __mmplayer_video_param_set_display_visible(mm_player_t* player)
2431 MMHandleType attrs = 0;
2435 /* check video sinkbin is created */
2436 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2439 attrs = MMPLAYER_GET_ATTRS(player);
2440 MMPLAYER_RETURN_IF_FAIL(attrs);
2442 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2443 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2444 LOGD("set video param : visible %d", visible);
2448 __mmplayer_video_param_set_display_method(mm_player_t* player)
2450 MMHandleType attrs = 0;
2451 int display_method = 0;
2454 /* check video sinkbin is created */
2455 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2458 attrs = MMPLAYER_GET_ATTRS(player);
2459 MMPLAYER_RETURN_IF_FAIL(attrs);
2461 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2462 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2463 LOGD("set video param : method %d", display_method);
2466 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
2468 MMHandleType attrs = 0;
2469 void *handle = NULL;
2472 /* check video sinkbin is created */
2473 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
2474 LOGW("There is no video sink");
2478 attrs = MMPLAYER_GET_ATTRS(player);
2479 MMPLAYER_RETURN_IF_FAIL(attrs);
2480 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2482 gst_video_overlay_set_video_roi_area(
2483 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2484 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2485 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2486 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2491 __mmplayer_video_param_set_roi_area(mm_player_t* player)
2493 MMHandleType attrs = 0;
2494 void *handle = NULL;
2498 int win_roi_width = 0;
2499 int win_roi_height = 0;
2502 /* check video sinkbin is created */
2503 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
2504 LOGW("There is no video sink");
2508 attrs = MMPLAYER_GET_ATTRS(player);
2509 MMPLAYER_RETURN_IF_FAIL(attrs);
2511 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2514 /* It should be set after setting window */
2515 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2516 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2517 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2518 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2520 /* After setting window handle, set display roi area */
2521 gst_video_overlay_set_display_roi_area(
2522 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2523 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2524 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2525 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2529 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
2531 MMHandleType attrs = 0;
2532 void *handle = NULL;
2534 /* check video sinkbin is created */
2535 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2538 attrs = MMPLAYER_GET_ATTRS(player);
2539 MMPLAYER_RETURN_IF_FAIL(attrs);
2541 /* common case if using overlay surface */
2542 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2545 /* default is using wl_surface_id */
2546 unsigned int wl_surface_id = 0;
2547 wl_surface_id = *(int*)handle;
2548 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
2549 gst_video_overlay_set_wl_window_wl_surface_id(
2550 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2553 /* FIXIT : is it error case? */
2554 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2559 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
2561 bool update_all_param = FALSE;
2564 /* check video sinkbin is created */
2565 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2566 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2568 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2569 LOGE("can not find tizenwlsink");
2570 return MM_ERROR_PLAYER_INTERNAL;
2573 LOGD("param_name : %s", param_name);
2574 if (!g_strcmp0(param_name, "update_all_param"))
2575 update_all_param = TRUE;
2577 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2578 __mmplayer_video_param_set_display_overlay(player);
2579 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2580 __mmplayer_video_param_set_display_method(player);
2581 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2582 __mmplayer_video_param_set_display_visible(player);
2583 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2584 __mmplayer_video_param_set_display_rotation(player);
2585 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2586 __mmplayer_video_param_set_roi_area(player);
2587 if (update_all_param)
2588 __mmplayer_video_param_set_video_roi_area(player);
2590 return MM_ERROR_NONE;
2594 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2596 MMHandleType attrs = 0;
2597 int surface_type = 0;
2598 int ret = MM_ERROR_NONE;
2602 /* check video sinkbin is created */
2603 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2604 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2606 attrs = MMPLAYER_GET_ATTRS(player);
2608 LOGE("cannot get content attribute");
2609 return MM_ERROR_PLAYER_INTERNAL;
2611 LOGD("param_name : %s", param_name);
2613 /* update display surface */
2614 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2615 LOGD("check display surface type attribute: %d", surface_type);
2617 /* configuring display */
2618 switch (surface_type) {
2619 case MM_DISPLAY_SURFACE_OVERLAY:
2621 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2622 if (ret != MM_ERROR_NONE)
2630 return MM_ERROR_NONE;
2634 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2636 gboolean disable_overlay = FALSE;
2637 mm_player_t* player = (mm_player_t*) hplayer;
2638 int ret = MM_ERROR_NONE;
2641 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2642 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2643 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2644 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2646 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2647 LOGW("Display control is not supported");
2648 return MM_ERROR_PLAYER_INTERNAL;
2651 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2653 if (audio_only == (bool)disable_overlay) {
2654 LOGE("It's the same with current setting: (%d)", audio_only);
2655 return MM_ERROR_NONE;
2659 LOGE("disable overlay");
2660 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2662 /* release overlay resource */
2663 if (player->video_overlay_resource != NULL) {
2664 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2665 player->video_overlay_resource);
2666 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2667 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2670 player->video_overlay_resource = NULL;
2673 ret = mm_resource_manager_commit(player->resource_manager);
2674 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2675 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2679 /* mark video overlay for acquire */
2680 if (player->video_overlay_resource == NULL) {
2681 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2682 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2683 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2684 &player->video_overlay_resource);
2685 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2686 LOGE("could not prepare for video_overlay resource\n");
2691 player->interrupted_by_resource = FALSE;
2692 /* acquire resources for video overlay */
2693 ret = mm_resource_manager_commit(player->resource_manager);
2694 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2695 LOGE("could not acquire resources for video playing\n");
2699 LOGD("enable overlay");
2700 __mmplayer_video_param_set_display_overlay(player);
2701 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2706 return MM_ERROR_NONE;
2710 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2712 mm_player_t* player = (mm_player_t*) hplayer;
2713 gboolean disable_overlay = FALSE;
2717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2718 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2719 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2720 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2721 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2723 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2724 LOGW("Display control is not supported");
2725 return MM_ERROR_PLAYER_INTERNAL;
2728 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2730 *paudio_only = (bool)(disable_overlay);
2732 LOGD("audio_only : %d", *paudio_only);
2736 return MM_ERROR_NONE;
2740 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2742 GList* bucket = element_bucket;
2743 MMPlayerGstElement* element = NULL;
2744 MMPlayerGstElement* prv_element = NULL;
2745 gint successful_link_count = 0;
2749 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2751 prv_element = (MMPlayerGstElement*)bucket->data;
2752 bucket = bucket->next;
2754 for (; bucket; bucket = bucket->next) {
2755 element = (MMPlayerGstElement*)bucket->data;
2757 if (element && element->gst) {
2758 if (prv_element && prv_element->gst) {
2759 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2760 LOGD("linking [%s] to [%s] success\n",
2761 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2762 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2763 successful_link_count++;
2765 LOGD("linking [%s] to [%s] failed\n",
2766 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2767 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2773 prv_element = element;
2778 return successful_link_count;
2782 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2784 GList* bucket = element_bucket;
2785 MMPlayerGstElement* element = NULL;
2786 int successful_add_count = 0;
2790 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2791 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2793 for (; bucket; bucket = bucket->next) {
2794 element = (MMPlayerGstElement*)bucket->data;
2796 if (element && element->gst) {
2797 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2798 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2799 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2800 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2803 successful_add_count++;
2809 return successful_add_count;
2812 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
2814 mm_player_t* player = (mm_player_t*) data;
2815 GstCaps *caps = NULL;
2816 GstStructure *str = NULL;
2821 MMPLAYER_RETURN_IF_FAIL(pad)
2822 MMPLAYER_RETURN_IF_FAIL(unused)
2823 MMPLAYER_RETURN_IF_FAIL(data)
2825 caps = gst_pad_get_current_caps(pad);
2829 str = gst_caps_get_structure(caps, 0);
2833 name = gst_structure_get_name(str);
2837 LOGD("name = %s\n", name);
2839 if (strstr(name, "audio")) {
2840 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2842 if (player->audio_stream_changed_cb) {
2843 LOGE("call the audio stream changed cb\n");
2844 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2846 } else if (strstr(name, "video")) {
2847 if ((name = gst_structure_get_string(str, "format")))
2848 player->set_mode.video_zc = name[0] == 'S';
2850 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2852 if (player->video_stream_changed_cb) {
2853 LOGE("call the video stream changed cb\n");
2854 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2861 gst_caps_unref(caps);
2871 * This function is to create audio pipeline for playing.
2873 * @param player [in] handle of player
2875 * @return This function returns zero on success.
2877 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
2879 /* macro for code readability. just for sinkbin-creation functions */
2880 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2882 x_bin[x_id].id = x_id;\
2883 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2884 if (!x_bin[x_id].gst) {\
2885 LOGE("failed to create %s \n", x_factory);\
2888 if (x_player->ini.set_dump_element_flag)\
2889 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2892 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2896 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2901 MMPLAYER_RETURN_IF_FAIL(player);
2903 if (player->audio_stream_buff_list) {
2904 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2905 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2908 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2909 __mmplayer_audio_stream_send_data(player, tmp);
2912 g_free(tmp->pcm_data);
2916 g_list_free(player->audio_stream_buff_list);
2917 player->audio_stream_buff_list = NULL;
2924 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2926 MMPlayerAudioStreamDataType audio_stream = { 0, };
2929 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
2931 audio_stream.bitrate = a_buffer->bitrate;
2932 audio_stream.channel = a_buffer->channel;
2933 audio_stream.depth = a_buffer->depth;
2934 audio_stream.is_little_endian = a_buffer->is_little_endian;
2935 audio_stream.channel_mask = a_buffer->channel_mask;
2936 audio_stream.data_size = a_buffer->data_size;
2937 audio_stream.data = a_buffer->pcm_data;
2939 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2940 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
2946 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2948 mm_player_t* player = (mm_player_t*) data;
2953 gint endianness = 0;
2954 guint64 channel_mask = 0;
2955 void *a_data = NULL;
2957 mm_player_audio_stream_buff_t *a_buffer = NULL;
2958 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2962 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
2964 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2965 a_data = mapinfo.data;
2966 a_size = mapinfo.size;
2968 GstCaps *caps = gst_pad_get_current_caps(pad);
2969 GstStructure *structure = gst_caps_get_structure(caps, 0);
2971 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2972 gst_structure_get_int(structure, "rate", &rate);
2973 gst_structure_get_int(structure, "channels", &channel);
2974 gst_structure_get_int(structure, "depth", &depth);
2975 gst_structure_get_int(structure, "endianness", &endianness);
2976 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2977 gst_caps_unref(GST_CAPS(caps));
2979 /* In case of the sync is false, use buffer list. *
2980 * The num of buffer list depends on the num of audio channels */
2981 if (player->audio_stream_buff_list) {
2982 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2983 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2985 if (channel_mask == tmp->channel_mask) {
2986 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2987 if (tmp->data_size + a_size < tmp->buff_size) {
2988 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2989 tmp->data_size += a_size;
2991 /* send data to client */
2992 __mmplayer_audio_stream_send_data(player, tmp);
2994 if (a_size > tmp->buff_size) {
2995 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2996 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2997 if (tmp->pcm_data == NULL) {
2998 LOGE("failed to realloc data.");
3001 tmp->buff_size = a_size;
3003 memset(tmp->pcm_data, 0x00, tmp->buff_size);
3004 memcpy(tmp->pcm_data, a_data, a_size);
3005 tmp->data_size = a_size;
3010 LOGE("data is empty in list.");
3016 /* create new audio stream data */
3017 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
3018 if (a_buffer == NULL) {
3019 LOGE("failed to alloc data.");
3022 a_buffer->bitrate = rate;
3023 a_buffer->channel = channel;
3024 a_buffer->depth = depth;
3025 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
3026 a_buffer->channel_mask = channel_mask;
3027 a_buffer->data_size = a_size;
3029 if (!player->audio_stream_sink_sync) {
3030 /* If sync is FALSE, use buffer list to reduce the IPC. */
3031 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
3032 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
3033 if (a_buffer->pcm_data == NULL) {
3034 LOGE("failed to alloc data.");
3038 memcpy(a_buffer->pcm_data, a_data, a_size);
3039 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
3040 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
3042 /* If sync is TRUE, send data directly. */
3043 a_buffer->pcm_data = a_data;
3044 __mmplayer_audio_stream_send_data(player, a_buffer);
3049 gst_buffer_unmap(buffer, &mapinfo);
3054 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3056 mm_player_t* player = (mm_player_t*)data;
3057 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
3058 GstPad* sinkpad = NULL;
3059 GstElement *queue = NULL, *sink = NULL;
3062 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3064 queue = gst_element_factory_make("queue", NULL);
3065 if (queue == NULL) {
3066 LOGD("fail make queue\n");
3070 sink = gst_element_factory_make("fakesink", NULL);
3072 LOGD("fail make fakesink\n");
3076 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
3078 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
3079 LOGW("failed to link queue & sink\n");
3083 sinkpad = gst_element_get_static_pad(queue, "sink");
3085 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3086 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
3090 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
3092 gst_object_unref(sinkpad);
3093 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
3094 g_object_set(sink, "signal-handoffs", TRUE, NULL);
3096 gst_element_set_state(sink, GST_STATE_PAUSED);
3097 gst_element_set_state(queue, GST_STATE_PAUSED);
3099 __mmplayer_add_signal_connection(player,
3101 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3103 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3110 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
3112 gst_object_unref(GST_OBJECT(queue));
3116 gst_object_unref(GST_OBJECT(sink));
3120 gst_object_unref(GST_OBJECT(sinkpad));
3127 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
3129 #define MAX_PROPS_LEN 128
3130 gint latency_mode = 0;
3131 gchar *stream_type = NULL;
3132 gchar *latency = NULL;
3134 gchar stream_props[MAX_PROPS_LEN] = {0,};
3135 GstStructure *props = NULL;
3138 * It should be set after player creation through attribute.
3139 * But, it can not be changed during playing.
3142 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
3143 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
3146 LOGE("stream_type is null.\n");
3148 if (player->sound.focus_id)
3149 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
3150 stream_type, stream_id, player->sound.focus_id);
3152 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
3153 stream_type, stream_id);
3154 props = gst_structure_from_string(stream_props, NULL);
3155 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
3156 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
3157 stream_type, stream_id, player->sound.focus_id, stream_props);
3158 gst_structure_free(props);
3161 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
3163 switch (latency_mode) {
3164 case AUDIO_LATENCY_MODE_LOW:
3165 latency = g_strndup("low", 3);
3167 case AUDIO_LATENCY_MODE_MID:
3168 latency = g_strndup("mid", 3);
3170 case AUDIO_LATENCY_MODE_HIGH:
3171 latency = g_strndup("high", 4);
3175 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
3179 LOGD("audiosink property - latency=%s \n", latency);
3187 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
3189 MMPlayerGstElement* first_element = NULL;
3190 MMPlayerGstElement* audiobin = NULL;
3191 MMHandleType attrs = 0;
3193 GstPad *ghostpad = NULL;
3194 GList* element_bucket = NULL;
3195 gboolean link_audio_sink_now = TRUE;
3201 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3204 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
3206 LOGE("failed to allocate memory for audiobin\n");
3207 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3210 attrs = MMPLAYER_GET_ATTRS(player);
3213 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3214 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3215 if (!audiobin[MMPLAYER_A_BIN].gst) {
3216 LOGE("failed to create audiobin\n");
3221 player->pipeline->audiobin = audiobin;
3223 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
3225 /* Adding audiotp plugin for reverse trickplay feature */
3226 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
3229 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
3231 /* replaygain volume */
3232 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
3233 if (player->sound.rg_enable)
3234 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
3236 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
3239 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
3241 if (player->set_mode.pcm_extraction) {
3242 // pcm extraction only and no sound output
3243 if (player->audio_stream_render_cb_ex) {
3244 char *caps_str = NULL;
3245 GstCaps* caps = NULL;
3246 gchar *format = NULL;
3249 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3251 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
3253 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
3255 caps = gst_caps_new_simple("audio/x-raw",
3256 "format", G_TYPE_STRING, format,
3257 "rate", G_TYPE_INT, player->pcm_samplerate,
3258 "channels", G_TYPE_INT, player->pcm_channel,
3260 caps_str = gst_caps_to_string(caps);
3261 LOGD("new caps : %s\n", caps_str);
3263 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3266 gst_caps_unref(caps);
3267 MMPLAYER_FREEIF(caps_str);
3269 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
3271 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3272 /* raw pad handling signal */
3273 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
3274 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3276 int dst_samplerate = 0;
3277 int dst_channels = 0;
3279 char *caps_str = NULL;
3280 GstCaps* caps = NULL;
3282 /* get conf. values */
3283 mm_attrs_multiple_get(player->attrs,
3285 "pcm_extraction_samplerate", &dst_samplerate,
3286 "pcm_extraction_channels", &dst_channels,
3287 "pcm_extraction_depth", &dst_depth,
3291 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3292 caps = gst_caps_new_simple("audio/x-raw",
3293 "rate", G_TYPE_INT, dst_samplerate,
3294 "channels", G_TYPE_INT, dst_channels,
3295 "depth", G_TYPE_INT, dst_depth,
3297 caps_str = gst_caps_to_string(caps);
3298 LOGD("new caps : %s\n", caps_str);
3300 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3303 gst_caps_unref(caps);
3304 MMPLAYER_FREEIF(caps_str);
3307 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
3310 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3314 //GstCaps* caps = NULL;
3317 /* for logical volume control */
3318 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
3319 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
3321 if (player->sound.mute) {
3322 LOGD("mute enabled\n");
3323 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
3328 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
3329 caps = gst_caps_from_string("audio/x-raw-int, "
3330 "endianness = (int) LITTLE_ENDIAN, "
3331 "signed = (boolean) true, "
3332 "width = (int) 16, "
3333 "depth = (int) 16");
3334 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3335 gst_caps_unref(caps);
3338 /* check if multi-channels */
3339 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
3340 GstPad *srcpad = NULL;
3341 GstCaps *caps = NULL;
3343 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
3344 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
3345 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3346 GstStructure *str = gst_caps_get_structure(caps, 0);
3348 gst_structure_get_int(str, "channels", &channels);
3349 gst_caps_unref(caps);
3351 gst_object_unref(srcpad);
3355 /* audio effect element. if audio effect is enabled */
3356 if ((strcmp(player->ini.audioeffect_element, ""))
3358 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3359 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
3361 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
3363 if ((!player->bypass_audio_effect)
3364 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3365 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
3366 if (!_mmplayer_audio_effect_custom_apply(player))
3367 LOGI("apply audio effect(custom) setting success\n");
3371 if ((strcmp(player->ini.audioeffect_element_custom, ""))
3372 && (player->set_mode.rich_audio))
3373 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
3376 /* create audio sink */
3377 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
3378 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
3379 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
3381 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
3382 if (player->is_360_feature_enabled &&
3383 player->is_content_spherical &&
3385 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
3386 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
3387 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
3389 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
3391 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
3393 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
3394 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
3395 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
3396 gst_caps_unref(acaps);
3398 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
3399 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
3400 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
3401 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
3403 player->is_openal_plugin_used = TRUE;
3405 if (player->video360_yaw_radians <= M_PI &&
3406 player->video360_yaw_radians >= -M_PI &&
3407 player->video360_pitch_radians <= M_PI_2 &&
3408 player->video360_pitch_radians >= -M_PI_2) {
3409 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3410 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3411 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3412 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3413 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3414 "source-orientation-y", player->video360_metadata.init_view_heading,
3415 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
3418 if (player->is_360_feature_enabled && player->is_content_spherical)
3419 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
3420 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
3424 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
3425 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
3428 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
3429 (player->videodec_linked && player->ini.use_system_clock)) {
3430 LOGD("system clock will be used.\n");
3431 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
3434 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
3435 __mmplayer_gst_set_audiosink_property(player, attrs);
3438 if (audiobin[MMPLAYER_A_SINK].gst) {
3439 GstPad *sink_pad = NULL;
3440 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
3441 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3442 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3443 gst_object_unref(GST_OBJECT(sink_pad));
3446 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3448 /* adding created elements to bin */
3449 LOGD("adding created elements to bin\n");
3450 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
3451 LOGE("failed to add elements\n");
3455 /* linking elements in the bucket by added order. */
3456 LOGD("Linking elements in the bucket by added order.\n");
3457 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3458 LOGE("failed to link elements\n");
3462 /* get first element's sinkpad for creating ghostpad */
3463 first_element = (MMPlayerGstElement *)element_bucket->data;
3464 if (!first_element) {
3465 LOGE("failed to get first elem\n");
3469 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3471 LOGE("failed to get pad from first element of audiobin\n");
3475 ghostpad = gst_ghost_pad_new("sink", pad);
3477 LOGE("failed to create ghostpad\n");
3481 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3482 LOGE("failed to add ghostpad to audiobin\n");
3486 gst_object_unref(pad);
3488 g_list_free(element_bucket);
3491 return MM_ERROR_NONE;
3495 LOGD("ERROR : releasing audiobin\n");
3498 gst_object_unref(GST_OBJECT(pad));
3501 gst_object_unref(GST_OBJECT(ghostpad));
3504 g_list_free(element_bucket);
3506 /* release element which are not added to bin */
3507 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3508 /* NOTE : skip bin */
3509 if (audiobin[i].gst) {
3510 GstObject* parent = NULL;
3511 parent = gst_element_get_parent(audiobin[i].gst);
3514 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3515 audiobin[i].gst = NULL;
3517 gst_object_unref(GST_OBJECT(parent));
3521 /* release audiobin with it's childs */
3522 if (audiobin[MMPLAYER_A_BIN].gst)
3523 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3525 MMPLAYER_FREEIF(audiobin);
3527 player->pipeline->audiobin = NULL;
3529 return MM_ERROR_PLAYER_INTERNAL;
3532 static GstPadProbeReturn
3533 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3535 mm_player_t* player = (mm_player_t*) u_data;
3536 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
3537 GstMapInfo probe_info = GST_MAP_INFO_INIT;
3539 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
3541 if (player->audio_stream_cb && probe_info.size && probe_info.data)
3542 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
3544 return GST_PAD_PROBE_OK;
3547 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
3549 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3552 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
3554 int ret = MM_ERROR_NONE;
3556 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3557 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3559 MMPLAYER_VIDEO_BO_LOCK(player);
3561 if (player->video_bo_list) {
3562 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3563 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3564 if (tmp && tmp->bo == bo) {
3566 LOGD("release bo %p", bo);
3567 tbm_bo_unref(tmp->bo);
3568 MMPLAYER_VIDEO_BO_UNLOCK(player);
3569 MMPLAYER_VIDEO_BO_SIGNAL(player);
3574 /* hw codec is running or the list was reset for DRC. */
3575 LOGW("there is no bo list.");
3577 MMPLAYER_VIDEO_BO_UNLOCK(player);
3579 LOGW("failed to find bo %p", bo);
3584 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
3589 MMPLAYER_RETURN_IF_FAIL(player);
3591 MMPLAYER_VIDEO_BO_LOCK(player);
3592 if (player->video_bo_list) {
3593 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3594 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3595 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3598 tbm_bo_unref(tmp->bo);
3602 g_list_free(player->video_bo_list);
3603 player->video_bo_list = NULL;
3605 player->video_bo_size = 0;
3606 MMPLAYER_VIDEO_BO_UNLOCK(player);
3613 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
3616 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3617 gboolean ret = TRUE;
3619 /* check DRC, if it is, destroy the prev bo list to create again */
3620 if (player->video_bo_size != size) {
3621 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3622 __mmplayer_video_stream_destroy_bo_list(player);
3623 player->video_bo_size = size;
3626 MMPLAYER_VIDEO_BO_LOCK(player);
3628 if ((!player->video_bo_list) ||
3629 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3631 /* create bo list */
3633 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3635 if (player->video_bo_list) {
3636 /* if bo list did not created all, try it again. */
3637 idx = g_list_length(player->video_bo_list);
3638 LOGD("bo list exist(len: %d)", idx);
3641 for (; idx < player->ini.num_of_video_bo; idx++) {
3642 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3644 LOGE("Fail to alloc bo_info.");
3647 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3649 LOGE("Fail to tbm_bo_alloc.");
3653 bo_info->using = FALSE;
3654 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3657 /* update video num buffers */
3658 player->video_num_buffers = idx;
3659 if (idx == player->ini.num_of_video_bo)
3660 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3663 MMPLAYER_VIDEO_BO_UNLOCK(player);
3667 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3671 /* get bo from list*/
3672 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3673 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3674 if (tmp && (tmp->using == FALSE)) {
3675 LOGD("found bo %p to use", tmp->bo);
3677 MMPLAYER_VIDEO_BO_UNLOCK(player);
3678 return tbm_bo_ref(tmp->bo);
3682 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3683 MMPLAYER_VIDEO_BO_UNLOCK(player);
3687 if (player->ini.video_bo_timeout <= 0) {
3688 MMPLAYER_VIDEO_BO_WAIT(player);
3690 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3691 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3698 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3700 mm_player_t* player = (mm_player_t*)data;
3702 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3704 /* send prerolled pkt */
3705 player->video_stream_prerolled = FALSE;
3707 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3709 /* not to send prerolled pkt again */
3710 player->video_stream_prerolled = TRUE;
3714 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3716 mm_player_t* player = (mm_player_t*)data;
3717 GstCaps *caps = NULL;
3718 MMPlayerVideoStreamDataType *stream = NULL;
3719 tbm_surface_h surface;
3720 GstMemory *mem = NULL;
3721 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3722 GstStructure *structure = NULL;
3723 const gchar *string_format = NULL;
3724 unsigned int fourcc = 0;
3725 unsigned int pitch = 0;
3729 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3731 if (player->video_stream_prerolled) {
3732 player->video_stream_prerolled = FALSE;
3733 LOGD("skip the prerolled pkt not to send it again");
3737 caps = gst_pad_get_current_caps(pad);
3739 LOGE("Caps is NULL.");
3743 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
3745 /* clear stream data structure */
3746 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
3748 LOGE("failed to alloc mem for video data");
3752 structure = gst_caps_get_structure(caps, 0);
3753 gst_structure_get_int(structure, "width", &(stream->width));
3754 gst_structure_get_int(structure, "height", &(stream->height));
3755 string_format = gst_structure_get_string(structure, "format");
3757 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
3758 stream->format = util_get_pixtype(fourcc);
3759 gst_caps_unref(caps);
3762 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3765 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
3766 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
3769 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
3770 LOGE("Wrong condition!!");
3774 /* set size and timestamp */
3775 mem = gst_buffer_peek_memory(buffer, 0);
3776 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3777 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3778 surface = gst_tizen_memory_get_surface(mem);
3780 /* check zero-copy */
3781 if (player->set_mode.video_zc &&
3782 player->set_mode.media_packet_video_stream &&
3783 gst_is_tizen_memory(mem)) {
3784 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
3785 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
3786 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
3787 stream->stride[index] = pitch;
3788 stream->elevation[index] = stream->height;
3790 stream->internal_buffer = gst_buffer_ref(buffer);
3791 } else { /* sw codec */
3795 int ret = TBM_SURFACE_ERROR_NONE;
3796 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
3797 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
3799 unsigned char *src = NULL;
3800 unsigned char *dest = NULL;
3801 tbm_bo_handle thandle;
3802 tbm_surface_h surface;
3803 tbm_surface_info_s info;
3806 gst_ret = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
3808 LOGE("fail to gst_memory_map");
3813 if (stream->format == MM_PIXEL_FORMAT_I420) {
3814 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
3816 ret = tbm_surface_get_info(surface, &info);
3818 if (ret != TBM_SURFACE_ERROR_NONE) {
3819 tbm_surface_destroy(surface);
3822 tbm_surface_destroy(surface);
3824 src_stride[0] = GST_ROUND_UP_4(stream->width);
3825 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
3826 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
3827 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
3828 stream->stride[0] = info.planes[0].stride;
3829 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
3830 stream->stride[1] = info.planes[1].stride;
3831 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
3832 stream->stride[2] = info.planes[2].stride;
3833 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
3834 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
3835 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
3836 stream->stride[0] = stream->width * 4;
3837 stream->elevation[0] = stream->height;
3838 size = stream->stride[0] * stream->height;
3840 LOGE("Not support format %d", stream->format);
3844 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
3845 if (!stream->bo[0]) {
3846 LOGE("Fail to tbm_bo_alloc!!");
3850 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
3851 if (thandle.ptr && mapinfo.data) {
3852 if (stream->format == MM_PIXEL_FORMAT_I420) {
3853 for (i = 0; i < 3; i++) {
3854 src = mapinfo.data + src_offset[i];
3855 dest = thandle.ptr + info.planes[i].offset;
3858 for (j = 0; j < stream->height>>k; j++) {
3859 memcpy(dest, src, stream->width>>k);
3860 src += src_stride[i];
3861 dest += stream->stride[i];
3864 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
3865 memcpy(thandle.ptr, mapinfo.data, size);
3867 LOGE("Not support format %d", stream->format);
3871 LOGE("data pointer is wrong. dest : %p, src : %p",
3872 thandle.ptr, mapinfo.data);
3875 tbm_bo_unmap(stream->bo[0]);
3878 if (player->video_stream_cb) { /* This has been already checked at the entry */
3879 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3880 LOGE("failed to send video stream data.");
3884 gst_memory_unmap(mem, &mapinfo);
3889 LOGE("release video stream resource.");
3890 if (gst_is_tizen_memory(mem)) {
3892 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3894 tbm_bo_unref(stream->bo[i]);
3897 /* unref gst buffer */
3898 if (stream->internal_buffer)
3899 gst_buffer_unref(stream->internal_buffer);
3902 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3905 gst_memory_unmap(mem, &mapinfo);
3911 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
3913 gchar* video_csc = "videoconvert"; /* default colorspace converter */
3914 GList* element_bucket = NULL;
3916 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3920 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
3921 LOGD("do not need to add video filters.");
3922 return MM_ERROR_NONE;
3925 /* in case of sw codec except 360 playback,
3926 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3927 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3928 LOGD("using video converter: %s", video_csc);
3930 /* set video rotator */
3931 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3933 *bucket = element_bucket;
3935 return MM_ERROR_NONE;
3937 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3938 g_list_free(element_bucket);
3942 return MM_ERROR_PLAYER_INTERNAL;
3946 * This function is to create video pipeline.
3948 * @param player [in] handle of player
3949 * caps [in] src caps of decoder
3950 * surface_type [in] surface type for video rendering
3952 * @return This function returns zero on success.
3954 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
3958 * - video overlay surface(arm/x86) : tizenwlsink
3961 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3965 GList*element_bucket = NULL;
3966 MMPlayerGstElement* first_element = NULL;
3967 MMPlayerGstElement* videobin = NULL;
3968 gchar *videosink_element = NULL;
3972 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3975 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3977 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3979 player->pipeline->videobin = videobin;
3981 attrs = MMPLAYER_GET_ATTRS(player);
3983 LOGE("cannot get content attribute");
3984 return MM_ERROR_PLAYER_INTERNAL;
3988 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3989 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3990 if (!videobin[MMPLAYER_V_BIN].gst) {
3991 LOGE("failed to create videobin");
3995 int enable_video_decoded_cb = 0;
3996 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
3998 if (player->is_360_feature_enabled && player->is_content_spherical) {
3999 LOGD("video360 elem will be added.");
4001 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
4002 "video-360", TRUE, player);
4004 /* Set spatial media metadata and/or user settings to the element.
4006 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4007 "projection-type", player->video360_metadata.projection_type, NULL);
4009 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4010 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
4012 if (player->video360_metadata.full_pano_width_pixels &&
4013 player->video360_metadata.full_pano_height_pixels &&
4014 player->video360_metadata.cropped_area_image_width &&
4015 player->video360_metadata.cropped_area_image_height) {
4016 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4017 "projection-bounds-top", player->video360_metadata.cropped_area_top,
4018 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
4019 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
4020 "projection-bounds-left", player->video360_metadata.cropped_area_left,
4021 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
4022 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
4026 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
4027 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4028 "horizontal-fov", player->video360_horizontal_fov,
4029 "vertical-fov", player->video360_vertical_fov, NULL);
4032 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
4033 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4034 "zoom", 1.0f / player->video360_zoom, NULL);
4037 if (player->video360_yaw_radians <= M_PI &&
4038 player->video360_yaw_radians >= -M_PI &&
4039 player->video360_pitch_radians <= M_PI_2 &&
4040 player->video360_pitch_radians >= -M_PI_2) {
4041 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4042 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4043 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4044 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4045 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4046 "pose-yaw", player->video360_metadata.init_view_heading,
4047 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
4050 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4051 "passthrough", !player->is_video360_enabled, NULL);
4054 /* set video sink */
4055 switch (surface_type) {
4056 case MM_DISPLAY_SURFACE_OVERLAY:
4057 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
4059 if (strlen(player->ini.videosink_element_overlay) > 0)
4060 videosink_element = player->ini.videosink_element_overlay;
4064 case MM_DISPLAY_SURFACE_NULL:
4065 if (strlen(player->ini.videosink_element_fake) > 0)
4066 videosink_element = player->ini.videosink_element_fake;
4070 case MM_DISPLAY_SURFACE_REMOTE:
4071 if (strlen(player->ini.videosink_element_fake) > 0)
4072 videosink_element = player->ini.videosink_element_fake;
4077 LOGE("unidentified surface type");
4080 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
4082 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
4084 /* additional setting for sink plug-in */
4085 switch (surface_type) {
4086 case MM_DISPLAY_SURFACE_OVERLAY:
4088 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
4090 LOGD("selected videosink name: %s", videosink_element);
4092 /* support shard memory with S/W codec on HawkP */
4093 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
4094 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4095 "use-tbm", use_tbm, NULL);
4101 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4104 LOGD("disable last-sample");
4105 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4109 if (player->set_mode.media_packet_video_stream) {
4111 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
4113 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
4115 __mmplayer_add_signal_connection(player,
4116 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4117 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4119 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
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_preroll_cb),
4131 case MM_DISPLAY_SURFACE_REMOTE:
4133 if (player->set_mode.media_packet_video_stream) {
4134 LOGE("add data probe at videosink");
4135 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4136 "sync", TRUE, "signal-handoffs", TRUE, NULL);
4138 __mmplayer_add_signal_connection(player,
4139 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4140 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4142 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
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_preroll_cb),
4154 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4157 LOGD("disable last-sample");
4158 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4168 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
4171 if (videobin[MMPLAYER_V_SINK].gst) {
4172 GstPad *sink_pad = NULL;
4173 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
4175 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4176 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
4177 gst_object_unref(GST_OBJECT(sink_pad));
4179 LOGW("failed to get sink pad from videosink\n");
4182 /* store it as it's sink element */
4183 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
4185 /* adding created elements to bin */
4186 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
4187 LOGE("failed to add elements\n");
4191 /* Linking elements in the bucket by added order */
4192 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4193 LOGE("failed to link elements\n");
4197 /* get first element's sinkpad for creating ghostpad */
4199 first_element = (MMPlayerGstElement *)element_bucket->data;
4200 if (!first_element) {
4201 LOGE("failed to get first element from bucket\n");
4205 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4207 LOGE("failed to get pad from first element\n");
4211 /* create ghostpad */
4212 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
4213 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
4214 LOGE("failed to add ghostpad to videobin\n");
4217 gst_object_unref(pad);
4219 /* done. free allocated variables */
4221 g_list_free(element_bucket);
4225 return MM_ERROR_NONE;
4228 LOGE("ERROR : releasing videobin\n");
4230 g_list_free(element_bucket);
4233 gst_object_unref(GST_OBJECT(pad));
4235 /* release videobin with it's childs */
4236 if (videobin[MMPLAYER_V_BIN].gst)
4237 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
4240 MMPLAYER_FREEIF(videobin);
4242 player->pipeline->videobin = NULL;
4244 return MM_ERROR_PLAYER_INTERNAL;
4247 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
4249 GList *element_bucket = NULL;
4250 MMPlayerGstElement *textbin = player->pipeline->textbin;
4252 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
4253 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
4254 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
4255 "signal-handoffs", FALSE,
4258 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
4259 __mmplayer_add_signal_connection(player,
4260 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
4261 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
4263 G_CALLBACK(__mmplayer_update_subtitle),
4266 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
4267 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
4269 if (!player->play_subtitle) {
4270 LOGD("add textbin sink as sink element of whole pipeline.\n");
4271 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
4274 /* adding created elements to bin */
4275 LOGD("adding created elements to bin\n");
4276 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
4277 LOGE("failed to add elements\n");
4281 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
4282 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
4283 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
4285 /* linking elements in the bucket by added order. */
4286 LOGD("Linking elements in the bucket by added order.\n");
4287 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4288 LOGE("failed to link elements\n");
4292 /* done. free allocated variables */
4293 g_list_free(element_bucket);
4295 if (textbin[MMPLAYER_T_QUEUE].gst) {
4297 GstPad *ghostpad = NULL;
4299 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
4301 LOGE("failed to get sink pad of text queue");
4305 ghostpad = gst_ghost_pad_new("text_sink", pad);
4306 gst_object_unref(pad);
4309 LOGE("failed to create ghostpad of textbin\n");
4313 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
4314 LOGE("failed to add ghostpad to textbin\n");
4315 gst_object_unref(ghostpad);
4320 return MM_ERROR_NONE;
4323 g_list_free(element_bucket);
4325 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
4326 LOGE("remove textbin sink from sink list");
4327 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
4330 /* release element at __mmplayer_gst_create_text_sink_bin */
4331 return MM_ERROR_PLAYER_INTERNAL;
4334 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
4336 MMPlayerGstElement *textbin = NULL;
4337 GList *element_bucket = NULL;
4338 int surface_type = 0;
4343 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4346 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
4348 LOGE("failed to allocate memory for textbin\n");
4349 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4353 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
4354 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
4355 if (!textbin[MMPLAYER_T_BIN].gst) {
4356 LOGE("failed to create textbin\n");
4361 player->pipeline->textbin = textbin;
4364 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
4365 LOGD("surface type for subtitle : %d", surface_type);
4366 switch (surface_type) {
4367 case MM_DISPLAY_SURFACE_OVERLAY:
4368 case MM_DISPLAY_SURFACE_NULL:
4369 case MM_DISPLAY_SURFACE_REMOTE:
4370 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
4371 LOGE("failed to make plain text elements\n");
4382 return MM_ERROR_NONE;
4386 LOGD("ERROR : releasing textbin\n");
4388 g_list_free(element_bucket);
4390 /* release signal */
4391 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4393 /* release element which are not added to bin */
4394 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4395 /* NOTE : skip bin */
4396 if (textbin[i].gst) {
4397 GstObject* parent = NULL;
4398 parent = gst_element_get_parent(textbin[i].gst);
4401 gst_object_unref(GST_OBJECT(textbin[i].gst));
4402 textbin[i].gst = NULL;
4404 gst_object_unref(GST_OBJECT(parent));
4409 /* release textbin with it's childs */
4410 if (textbin[MMPLAYER_T_BIN].gst)
4411 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4413 MMPLAYER_FREEIF(player->pipeline->textbin);
4414 player->pipeline->textbin = NULL;
4417 return MM_ERROR_PLAYER_INTERNAL;
4422 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
4424 MMPlayerGstElement* mainbin = NULL;
4425 MMPlayerGstElement* textbin = NULL;
4426 MMHandleType attrs = 0;
4427 GstElement *subsrc = NULL;
4428 GstElement *subparse = NULL;
4429 gchar *subtitle_uri = NULL;
4430 const gchar *charset = NULL;
4436 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4438 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4440 mainbin = player->pipeline->mainbin;
4442 attrs = MMPLAYER_GET_ATTRS(player);
4444 LOGE("cannot get content attribute\n");
4445 return MM_ERROR_PLAYER_INTERNAL;
4448 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4449 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4450 LOGE("subtitle uri is not proper filepath.\n");
4451 return MM_ERROR_PLAYER_INVALID_URI;
4454 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4455 LOGE("failed to get storage info of subtitle path");
4456 return MM_ERROR_PLAYER_INVALID_URI;
4459 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
4461 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4462 player->subtitle_language_list = NULL;
4463 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4465 /* create the subtitle source */
4466 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4468 LOGE("failed to create filesrc element\n");
4471 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4473 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4474 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4476 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4477 LOGW("failed to add queue\n");
4478 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4479 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4480 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4485 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4487 LOGE("failed to create subparse element\n");
4491 charset = util_get_charset(subtitle_uri);
4493 LOGD("detected charset is %s\n", charset);
4494 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4497 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4498 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4500 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4501 LOGW("failed to add subparse\n");
4502 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4503 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4504 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4508 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4509 LOGW("failed to link subsrc and subparse\n");
4513 player->play_subtitle = TRUE;
4514 player->adjust_subtitle_pos = 0;
4516 LOGD("play subtitle using subtitle file\n");
4518 if (player->pipeline->textbin == NULL) {
4519 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4520 LOGE("failed to create text sink bin. continuing without text\n");
4524 textbin = player->pipeline->textbin;
4526 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4527 LOGW("failed to add textbin\n");
4529 /* release signal */
4530 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4532 /* release textbin with it's childs */
4533 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4534 MMPLAYER_FREEIF(player->pipeline->textbin);
4535 player->pipeline->textbin = textbin = NULL;
4539 LOGD("link text input selector and textbin ghost pad");
4541 player->textsink_linked = 1;
4542 player->external_text_idx = 0;
4543 LOGI("player->textsink_linked set to 1\n");
4545 textbin = player->pipeline->textbin;
4546 LOGD("text bin has been created. reuse it.");
4547 player->external_text_idx = 1;
4550 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4551 LOGW("failed to link subparse and textbin\n");
4555 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4557 LOGE("failed to get sink pad from textsink to probe data");
4561 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4562 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4564 gst_object_unref(pad);
4567 /* create dot. for debugging */
4568 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4571 return MM_ERROR_NONE;
4574 /* release text pipeline resource */
4575 player->textsink_linked = 0;
4577 /* release signal */
4578 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4580 if (player->pipeline->textbin) {
4581 LOGE("remove textbin");
4583 /* release textbin with it's childs */
4584 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4585 MMPLAYER_FREEIF(player->pipeline->textbin);
4586 player->pipeline->textbin = NULL;
4590 /* release subtitle elem */
4591 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4592 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4594 return MM_ERROR_PLAYER_INTERNAL;
4598 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4600 mm_player_t* player = (mm_player_t*) data;
4601 MMMessageParamType msg = {0, };
4602 GstClockTime duration = 0;
4603 gpointer text = NULL;
4604 guint text_size = 0;
4605 gboolean ret = TRUE;
4606 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4610 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4611 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4613 if (player->is_subtitle_force_drop) {
4614 LOGW("subtitle is dropped forcedly.");
4618 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4619 text = mapinfo.data;
4620 text_size = mapinfo.size;
4621 duration = GST_BUFFER_DURATION(buffer);
4623 if (player->set_mode.subtitle_off) {
4624 LOGD("subtitle is OFF.\n");
4628 if (!text || (text_size == 0)) {
4629 LOGD("There is no subtitle to be displayed.\n");
4633 msg.data = (void *) text;
4634 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4636 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
4638 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4639 gst_buffer_unmap(buffer, &mapinfo);
4646 static GstPadProbeReturn
4647 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4649 mm_player_t *player = (mm_player_t *) u_data;
4650 GstClockTime cur_timestamp = 0;
4651 gint64 adjusted_timestamp = 0;
4652 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4654 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4656 if (player->set_mode.subtitle_off) {
4657 LOGD("subtitle is OFF.\n");
4661 if (player->adjust_subtitle_pos == 0) {
4662 LOGD("nothing to do");
4666 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4667 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4669 if (adjusted_timestamp < 0) {
4670 LOGD("adjusted_timestamp under zero");
4675 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4676 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4677 GST_TIME_ARGS(cur_timestamp),
4678 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4680 return GST_PAD_PROBE_OK;
4682 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
4686 /* check player and subtitlebin are created */
4687 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4688 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4690 if (position == 0) {
4691 LOGD("nothing to do\n");
4693 return MM_ERROR_NONE;
4697 case MM_PLAYER_POS_FORMAT_TIME:
4699 /* check current postion */
4700 player->adjust_subtitle_pos = position;
4702 LOGD("save adjust_subtitle_pos in player") ;
4708 LOGW("invalid format.\n");
4710 return MM_ERROR_INVALID_ARGUMENT;
4716 return MM_ERROR_NONE;
4720 * This function is to create audio or video pipeline for playing.
4722 * @param player [in] handle of player
4724 * @return This function returns zero on success.
4729 __mmplayer_gst_create_pipeline(mm_player_t* player)
4731 int ret = MM_ERROR_NONE;
4732 MMPlayerGstElement *mainbin = NULL;
4733 MMHandleType attrs = 0;
4734 gint mode = MM_PLAYER_PD_MODE_NONE;
4737 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4739 /* get profile attribute */
4740 attrs = MMPLAYER_GET_ATTRS(player);
4742 LOGE("failed to get content attribute");
4746 /* create pipeline handles */
4747 if (player->pipeline) {
4748 LOGE("pipeline should be released before create new one");
4752 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
4753 if (player->pipeline == NULL)
4756 /* create mainbin */
4757 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
4758 if (mainbin == NULL)
4761 /* create pipeline */
4762 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4763 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4764 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4765 LOGE("failed to create pipeline");
4770 player->pipeline->mainbin = mainbin;
4773 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
4774 player->pd_mode = mode;
4776 /* create the source and decoder elements */
4777 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4778 ret = __mmplayer_gst_build_es_pipeline(player);
4779 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
4780 ret = __mmplayer_gst_build_pd_pipeline(player);
4782 ret = __mmplayer_gst_build_pipeline(player);
4785 if (ret != MM_ERROR_NONE) {
4786 LOGE("failed to create some elements");
4790 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4791 if (__mmplayer_check_subtitle(player)) {
4792 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
4793 LOGE("failed to create text pipeline");
4797 ret = __mmplayer_gst_add_bus_watch(player);
4798 if (ret != MM_ERROR_NONE) {
4799 LOGE("failed to add bus watch");
4804 return MM_ERROR_NONE;
4807 __mmplayer_gst_destroy_pipeline(player);
4808 return MM_ERROR_PLAYER_INTERNAL;
4812 __mmplayer_reset_gapless_state(mm_player_t* player)
4815 MMPLAYER_RETURN_IF_FAIL(player
4817 && player->pipeline->audiobin
4818 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4820 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4827 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4830 int ret = MM_ERROR_NONE;
4834 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4836 /* cleanup stuffs */
4837 MMPLAYER_FREEIF(player->type);
4838 player->have_dynamic_pad = FALSE;
4839 player->no_more_pad = FALSE;
4840 player->num_dynamic_pad = 0;
4841 player->demux_pad_index = 0;
4842 player->use_deinterleave = FALSE;
4843 player->max_audio_channels = 0;
4844 player->video_share_api_delta = 0;
4845 player->video_share_clock_delta = 0;
4846 player->video_hub_download_mode = 0;
4848 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4849 player->subtitle_language_list = NULL;
4850 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4852 __mmplayer_reset_gapless_state(player);
4854 if (player->streamer) {
4855 __mm_player_streaming_deinitialize(player->streamer);
4856 __mm_player_streaming_destroy(player->streamer);
4857 player->streamer = NULL;
4860 /* cleanup unlinked mime type */
4861 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4862 MMPLAYER_FREEIF(player->unlinked_video_mime);
4863 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4865 /* cleanup running stuffs */
4866 __mmplayer_cancel_eos_timer(player);
4868 /* cleanup gst stuffs */
4869 if (player->pipeline) {
4870 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4871 GstTagList* tag_list = player->pipeline->tag_list;
4873 /* first we need to disconnect all signal hander */
4874 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4877 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4878 MMPlayerGstElement* videobin = player->pipeline->videobin;
4879 MMPlayerGstElement* textbin = player->pipeline->textbin;
4880 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4881 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4882 gst_object_unref(bus);
4884 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4885 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4886 if (ret != MM_ERROR_NONE) {
4887 LOGE("fail to change state to NULL\n");
4888 return MM_ERROR_PLAYER_INTERNAL;
4891 LOGW("succeeded in changing state to NULL\n");
4893 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4896 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4897 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4899 /* free avsysaudiosink
4900 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4901 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4903 MMPLAYER_FREEIF(audiobin);
4904 MMPLAYER_FREEIF(videobin);
4905 MMPLAYER_FREEIF(textbin);
4906 MMPLAYER_FREEIF(mainbin);
4910 gst_tag_list_free(tag_list);
4912 MMPLAYER_FREEIF(player->pipeline);
4914 MMPLAYER_FREEIF(player->album_art);
4916 if (player->v_stream_caps) {
4917 gst_caps_unref(player->v_stream_caps);
4918 player->v_stream_caps = NULL;
4920 if (player->a_stream_caps) {
4921 gst_caps_unref(player->a_stream_caps);
4922 player->a_stream_caps = NULL;
4925 if (player->s_stream_caps) {
4926 gst_caps_unref(player->s_stream_caps);
4927 player->s_stream_caps = NULL;
4929 __mmplayer_track_destroy(player);
4931 if (player->sink_elements)
4932 g_list_free(player->sink_elements);
4933 player->sink_elements = NULL;
4935 if (player->bufmgr) {
4936 tbm_bufmgr_deinit(player->bufmgr);
4937 player->bufmgr = NULL;
4940 LOGW("finished destroy pipeline\n");
4947 static int __mmplayer_gst_realize(mm_player_t* player)
4950 int ret = MM_ERROR_NONE;
4954 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4956 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4958 ret = __mmplayer_gst_create_pipeline(player);
4960 LOGE("failed to create pipeline\n");
4964 /* set pipeline state to READY */
4965 /* NOTE : state change to READY must be performed sync. */
4966 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4967 ret = __mmplayer_gst_set_state(player,
4968 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4970 if (ret != MM_ERROR_NONE) {
4971 /* return error if failed to set state */
4972 LOGE("failed to set READY state");
4976 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4978 /* create dot before error-return. for debugging */
4979 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4986 static int __mmplayer_gst_unrealize(mm_player_t* player)
4988 int ret = MM_ERROR_NONE;
4992 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4994 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4995 MMPLAYER_PRINT_STATE(player);
4997 /* release miscellaneous information */
4998 __mmplayer_release_misc(player);
5000 /* destroy pipeline */
5001 ret = __mmplayer_gst_destroy_pipeline(player);
5002 if (ret != MM_ERROR_NONE) {
5003 LOGE("failed to destory pipeline\n");
5007 /* release miscellaneous information.
5008 these info needs to be released after pipeline is destroyed. */
5009 __mmplayer_release_misc_post(player);
5011 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
5019 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
5024 LOGW("set_message_callback is called with invalid player handle\n");
5025 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5028 player->msg_cb = callback;
5029 player->msg_cb_param = user_param;
5031 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
5035 return MM_ERROR_NONE;
5038 static int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
5040 int ret = MM_ERROR_PLAYER_INVALID_URI;
5045 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
5046 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
5047 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
5049 memset(data, 0, sizeof(MMPlayerParseProfile));
5051 if ((path = strstr(uri, "es_buff://"))) {
5053 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5054 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
5055 ret = MM_ERROR_NONE;
5057 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
5059 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5060 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5061 ret = MM_ERROR_NONE;
5063 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
5066 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5067 tmp = g_ascii_strdown(uri, strlen(uri));
5069 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
5070 data->uri_type = MM_PLAYER_URI_TYPE_SS;
5072 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
5074 ret = MM_ERROR_NONE;
5077 } else if ((path = strstr(uri, "rtspu://"))) {
5079 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5080 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5081 ret = MM_ERROR_NONE;
5083 } else if ((path = strstr(uri, "rtspr://"))) {
5084 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
5085 char *separater = strstr(path, "*");
5089 char *urgent = separater + strlen("*");
5091 if ((urgent_len = strlen(urgent))) {
5092 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
5093 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
5094 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5095 ret = MM_ERROR_NONE;
5098 } else if ((path = strstr(uri, "mms://"))) {
5100 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
5101 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
5102 ret = MM_ERROR_NONE;
5104 } else if ((path = strstr(uri, "mem://"))) {
5107 char *buffer = NULL;
5108 char *seperator = strchr(path, ',');
5109 char ext[100] = {0,}, size[100] = {0,};
5112 if ((buffer = strstr(path, "ext="))) {
5113 buffer += strlen("ext=");
5115 if (strlen(buffer)) {
5116 strncpy(ext, buffer, 99);
5118 if ((seperator = strchr(ext, ','))
5119 || (seperator = strchr(ext, ' '))
5120 || (seperator = strchr(ext, '\0'))) {
5121 seperator[0] = '\0';
5126 if ((buffer = strstr(path, "size="))) {
5127 buffer += strlen("size=");
5129 if (strlen(buffer) > 0) {
5130 strncpy(size, buffer, 99);
5132 if ((seperator = strchr(size, ','))
5133 || (seperator = strchr(size, ' '))
5134 || (seperator = strchr(size, '\0'))) {
5135 seperator[0] = '\0';
5138 mem_size = atoi(size);
5143 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
5144 if (mem_size && param) {
5145 if (data->input_mem.buf)
5146 free(data->input_mem.buf);
5147 data->input_mem.buf = malloc(mem_size);
5149 if (data->input_mem.buf) {
5150 memcpy(data->input_mem.buf, param, mem_size);
5151 data->input_mem.len = mem_size;
5152 ret = MM_ERROR_NONE;
5154 LOGE("failed to alloc mem %d", mem_size);
5155 ret = MM_ERROR_PLAYER_INTERNAL;
5158 data->input_mem.offset = 0;
5159 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
5163 gchar *location = NULL;
5166 if ((path = strstr(uri, "file://"))) {
5168 location = g_filename_from_uri(uri, NULL, &err);
5170 if (!location || (err != NULL)) {
5171 LOGE("Invalid URI '%s' for filesrc: %s", path,
5172 (err != NULL) ? err->message : "unknown error");
5174 if (err) g_error_free(err);
5175 if (location) g_free(location);
5177 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5181 LOGD("path from uri: %s", location);
5184 path = (location != NULL) ? (location) : ((char*)uri);
5185 int file_stat = MM_ERROR_NONE;
5187 file_stat = util_exist_file_path(path);
5189 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
5190 if (file_stat == MM_ERROR_NONE) {
5191 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
5193 if (util_is_sdp_file(path)) {
5194 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
5195 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
5197 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
5199 ret = MM_ERROR_NONE;
5200 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
5201 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
5203 LOGE("invalid uri, could not play..\n");
5204 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
5207 if (location) g_free(location);
5211 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
5212 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
5213 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
5214 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
5216 /* dump parse result */
5217 SECURE_LOGW("incomming uri : %s\n", uri);
5218 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
5219 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
5227 __mmplayer_can_do_interrupt(mm_player_t *player)
5229 if (!player || !player->pipeline || !player->attrs) {
5230 LOGW("not initialized");
5234 if (player->set_mode.pcm_extraction) {
5235 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
5239 /* check if seeking */
5240 if (player->seek_state != MMPLAYER_SEEK_NONE) {
5241 MMMessageParamType msg_param;
5242 memset(&msg_param, 0, sizeof(MMMessageParamType));
5243 msg_param.code = MM_ERROR_PLAYER_SEEK;
5244 player->seek_state = MMPLAYER_SEEK_NONE;
5245 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5249 /* check other thread */
5250 if (!MMPLAYER_CMD_TRYLOCK(player)) {
5251 LOGW("locked already, cmd state : %d", player->cmd);
5253 /* check application command */
5254 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
5255 LOGW("playing.. should wait cmd lock then, will be interrupted");
5257 /* lock will be released at mrp_resource_release_cb() */
5258 MMPLAYER_CMD_LOCK(player);
5261 LOGW("nothing to do");
5264 LOGW("can interrupt immediately");
5268 FAILED: /* with CMD UNLOCKED */
5271 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
5276 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
5279 mm_player_t *player = NULL;
5283 if (user_data == NULL) {
5284 LOGE("- user_data is null\n");
5287 player = (mm_player_t *)user_data;
5289 /* do something to release resource here.
5290 * player stop and interrupt forwarding */
5291 if (!__mmplayer_can_do_interrupt(player)) {
5292 LOGW("no need to interrupt, so leave");
5294 MMMessageParamType msg = {0, };
5297 player->interrupted_by_resource = TRUE;
5299 /* get last play position */
5300 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
5301 LOGW("failed to get play position.");
5303 msg.union_type = MM_MSG_UNION_TIME;
5304 msg.time.elapsed = pos;
5305 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
5307 LOGD("video resource conflict so, resource will be freed by unrealizing");
5308 if (_mmplayer_unrealize((MMHandleType)player))
5309 LOGW("failed to unrealize");
5311 /* lock is called in __mmplayer_can_do_interrupt() */
5312 MMPLAYER_CMD_UNLOCK(player);
5315 if (res == player->video_overlay_resource)
5316 player->video_overlay_resource = FALSE;
5318 player->video_decoder_resource = FALSE;
5326 __mmplayer_initialize_video_roi(mm_player_t *player)
5328 player->video_roi.scale_x = 0.0;
5329 player->video_roi.scale_y = 0.0;
5330 player->video_roi.scale_width = 1.0;
5331 player->video_roi.scale_height = 1.0;
5335 _mmplayer_create_player(MMHandleType handle)
5337 int ret = MM_ERROR_PLAYER_INTERNAL;
5338 bool enabled = false;
5340 mm_player_t* player = MM_PLAYER_CAST(handle);
5344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346 /* initialize player state */
5347 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
5348 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
5349 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
5350 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
5352 /* check current state */
5353 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
5355 /* construct attributes */
5356 player->attrs = _mmplayer_construct_attribute(handle);
5358 if (!player->attrs) {
5359 LOGE("Failed to construct attributes\n");
5363 /* initialize gstreamer with configured parameter */
5364 if (!__mmplayer_init_gstreamer(player)) {
5365 LOGE("Initializing gstreamer failed\n");
5366 _mmplayer_deconstruct_attribute(handle);
5370 /* create lock. note that g_tread_init() has already called in gst_init() */
5371 g_mutex_init(&player->fsink_lock);
5373 /* create update tag lock */
5374 g_mutex_init(&player->update_tag_lock);
5376 /* create next play mutex */
5377 g_mutex_init(&player->next_play_thread_mutex);
5379 /* create next play cond */
5380 g_cond_init(&player->next_play_thread_cond);
5382 /* create next play thread */
5383 player->next_play_thread =
5384 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
5385 if (!player->next_play_thread) {
5386 LOGE("failed to create next play thread");
5387 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
5388 g_mutex_clear(&player->next_play_thread_mutex);
5389 g_cond_clear(&player->next_play_thread_cond);
5393 player->bus_msg_q = g_queue_new();
5394 if (!player->bus_msg_q) {
5395 LOGE("failed to create queue for bus_msg");
5396 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
5400 ret = _mmplayer_initialize_video_capture(player);
5401 if (ret != MM_ERROR_NONE) {
5402 LOGE("failed to initialize video capture\n");
5406 /* initialize resource manager */
5407 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
5408 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
5409 &player->resource_manager)) {
5410 LOGE("failed to initialize resource manager\n");
5414 if (MMPLAYER_IS_HTTP_PD(player)) {
5415 player->pd_downloader = NULL;
5416 player->pd_file_save_path = NULL;
5419 /* create video bo lock and cond */
5420 g_mutex_init(&player->video_bo_mutex);
5421 g_cond_init(&player->video_bo_cond);
5423 /* create media stream callback mutex */
5424 g_mutex_init(&player->media_stream_cb_lock);
5426 /* create subtitle info lock and cond */
5427 g_mutex_init(&player->subtitle_info_mutex);
5428 g_cond_init(&player->subtitle_info_cond);
5430 player->streaming_type = STREAMING_SERVICE_NONE;
5432 /* give default value of audio effect setting */
5433 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
5434 player->sound.rg_enable = false;
5435 player->playback_rate = DEFAULT_PLAYBACK_RATE;
5437 player->play_subtitle = FALSE;
5438 player->use_deinterleave = FALSE;
5439 player->max_audio_channels = 0;
5440 player->video_share_api_delta = 0;
5441 player->video_share_clock_delta = 0;
5442 player->has_closed_caption = FALSE;
5443 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
5444 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
5445 player->pending_resume = FALSE;
5446 if (player->ini.dump_element_keyword[0][0] == '\0')
5447 player->ini.set_dump_element_flag = FALSE;
5449 player->ini.set_dump_element_flag = TRUE;
5451 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
5452 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
5453 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
5455 /* Set video360 settings to their defaults for just-created player.
5458 player->is_360_feature_enabled = FALSE;
5459 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
5460 LOGI("spherical feature info: %d", enabled);
5462 player->is_360_feature_enabled = TRUE;
5464 LOGE("failed to get spherical feature info");
5467 player->is_content_spherical = FALSE;
5468 player->is_video360_enabled = TRUE;
5469 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
5470 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
5471 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
5472 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
5473 player->video360_zoom = 1.0f;
5474 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
5475 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
5477 __mmplayer_initialize_video_roi(player);
5479 /* set player state to null */
5480 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5481 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
5483 return MM_ERROR_NONE;
5487 g_mutex_clear(&player->fsink_lock);
5489 /* free update tag lock */
5490 g_mutex_clear(&player->update_tag_lock);
5492 g_queue_free(player->bus_msg_q);
5494 /* free next play thread */
5495 if (player->next_play_thread) {
5496 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
5497 player->next_play_thread_exit = TRUE;
5498 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
5499 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
5501 g_thread_join(player->next_play_thread);
5502 player->next_play_thread = NULL;
5504 g_mutex_clear(&player->next_play_thread_mutex);
5505 g_cond_clear(&player->next_play_thread_cond);
5508 /* release attributes */
5509 _mmplayer_deconstruct_attribute(handle);
5517 __mmplayer_init_gstreamer(mm_player_t* player)
5519 static gboolean initialized = FALSE;
5520 static const int max_argc = 50;
5522 gchar** argv = NULL;
5523 gchar** argv2 = NULL;
5529 LOGD("gstreamer already initialized.\n");
5534 argc = malloc(sizeof(int));
5535 argv = malloc(sizeof(gchar*) * max_argc);
5536 argv2 = malloc(sizeof(gchar*) * max_argc);
5538 if (!argc || !argv || !argv2)
5541 memset(argv, 0, sizeof(gchar*) * max_argc);
5542 memset(argv2, 0, sizeof(gchar*) * max_argc);
5546 argv[0] = g_strdup("mmplayer");
5549 for (i = 0; i < 5; i++) {
5550 /* FIXIT : num of param is now fixed to 5. make it dynamic */
5551 if (strlen(player->ini.gst_param[i]) > 0) {
5552 argv[*argc] = g_strdup(player->ini.gst_param[i]);
5557 /* we would not do fork for scanning plugins */
5558 argv[*argc] = g_strdup("--gst-disable-registry-fork");
5561 /* check disable registry scan */
5562 if (player->ini.skip_rescan) {
5563 argv[*argc] = g_strdup("--gst-disable-registry-update");
5567 /* check disable segtrap */
5568 if (player->ini.disable_segtrap) {
5569 argv[*argc] = g_strdup("--gst-disable-segtrap");
5573 LOGD("initializing gstreamer with following parameter\n");
5574 LOGD("argc : %d\n", *argc);
5577 for (i = 0; i < arg_count; i++) {
5579 LOGD("argv[%d] : %s\n", i, argv2[i]);
5582 /* initializing gstreamer */
5583 if (!gst_init_check(argc, &argv, &err)) {
5584 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
5591 for (i = 0; i < arg_count; i++) {
5592 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
5593 MMPLAYER_FREEIF(argv2[i]);
5596 MMPLAYER_FREEIF(argv);
5597 MMPLAYER_FREEIF(argv2);
5598 MMPLAYER_FREEIF(argc);
5608 for (i = 0; i < arg_count; i++) {
5609 LOGD("free[%d] : %s\n", i, argv2[i]);
5610 MMPLAYER_FREEIF(argv2[i]);
5613 MMPLAYER_FREEIF(argv);
5614 MMPLAYER_FREEIF(argv2);
5615 MMPLAYER_FREEIF(argc);
5621 __mmplayer_destroy_streaming_ext(mm_player_t* player)
5623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5625 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
5626 _mmplayer_destroy_pd_downloader((MMHandleType)player);
5627 MMPLAYER_FREEIF(player->pd_file_save_path);
5630 return MM_ERROR_NONE;
5634 __mmplayer_check_async_state_transition(mm_player_t* player)
5636 GstState element_state = GST_STATE_VOID_PENDING;
5637 GstState element_pending_state = GST_STATE_VOID_PENDING;
5638 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5639 GstElement * element = NULL;
5640 gboolean async = FALSE;
5642 /* check player handle */
5643 MMPLAYER_RETURN_IF_FAIL(player &&
5645 player->pipeline->mainbin &&
5646 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5649 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5651 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5652 LOGD("don't need to check the pipeline state");
5656 MMPLAYER_PRINT_STATE(player);
5658 /* wait for state transition */
5659 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5660 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
5662 if (ret == GST_STATE_CHANGE_FAILURE) {
5663 LOGE(" [%s] state : %s pending : %s \n",
5664 GST_ELEMENT_NAME(element),
5665 gst_element_state_get_name(element_state),
5666 gst_element_state_get_name(element_pending_state));
5668 /* dump state of all element */
5669 __mmplayer_dump_pipeline_state(player);
5674 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
5679 _mmplayer_destroy(MMHandleType handle)
5681 mm_player_t* player = MM_PLAYER_CAST(handle);
5685 /* check player handle */
5686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5688 /* destroy can called at anytime */
5689 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5691 /* check async state transition */
5692 __mmplayer_check_async_state_transition(player);
5694 __mmplayer_destroy_streaming_ext(player);
5696 /* release next play thread */
5697 if (player->next_play_thread) {
5698 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
5699 player->next_play_thread_exit = TRUE;
5700 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
5701 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
5703 LOGD("waitting for next play thread exit\n");
5704 g_thread_join(player->next_play_thread);
5705 g_mutex_clear(&player->next_play_thread_mutex);
5706 g_cond_clear(&player->next_play_thread_cond);
5707 LOGD("next play thread released\n");
5710 _mmplayer_release_video_capture(player);
5712 /* de-initialize resource manager */
5713 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
5714 player->resource_manager))
5715 LOGE("failed to deinitialize resource manager\n");
5717 /* release pipeline */
5718 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
5719 LOGE("failed to destory pipeline\n");
5720 return MM_ERROR_PLAYER_INTERNAL;
5723 g_queue_free(player->bus_msg_q);
5725 /* release subtitle info lock and cond */
5726 g_mutex_clear(&player->subtitle_info_mutex);
5727 g_cond_clear(&player->subtitle_info_cond);
5729 __mmplayer_release_dump_list(player->dump_list);
5731 /* release miscellaneous information */
5732 __mmplayer_release_misc(player);
5734 /* release miscellaneous information.
5735 these info needs to be released after pipeline is destroyed. */
5736 __mmplayer_release_misc_post(player);
5738 /* release attributes */
5739 _mmplayer_deconstruct_attribute(handle);
5742 g_mutex_clear(&player->fsink_lock);
5745 g_mutex_clear(&player->update_tag_lock);
5747 /* release video bo lock and cond */
5748 g_mutex_clear(&player->video_bo_mutex);
5749 g_cond_clear(&player->video_bo_cond);
5751 /* release media stream callback lock */
5752 g_mutex_clear(&player->media_stream_cb_lock);
5756 return MM_ERROR_NONE;
5760 __mmplayer_realize_streaming_ext(mm_player_t* player)
5762 int ret = MM_ERROR_NONE;
5765 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5767 if (MMPLAYER_IS_HTTP_PD(player)) {
5768 gboolean bret = FALSE;
5770 player->pd_downloader = _mmplayer_create_pd_downloader();
5771 if (!player->pd_downloader) {
5772 LOGE("Unable to create PD Downloader...");
5773 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
5776 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
5778 if (FALSE == bret) {
5779 LOGE("Unable to create PD Downloader...");
5780 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
5789 _mmplayer_realize(MMHandleType hplayer)
5791 mm_player_t* player = (mm_player_t*)hplayer;
5794 MMHandleType attrs = 0;
5795 int ret = MM_ERROR_NONE;
5799 /* check player handle */
5800 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
5802 /* check current state */
5803 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5805 attrs = MMPLAYER_GET_ATTRS(player);
5807 LOGE("fail to get attributes.\n");
5808 return MM_ERROR_PLAYER_INTERNAL;
5810 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5811 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5813 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5814 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
5816 if (ret != MM_ERROR_NONE) {
5817 LOGE("failed to parse profile\n");
5822 if (uri && (strstr(uri, "es_buff://"))) {
5823 if (strstr(uri, "es_buff://push_mode"))
5824 player->es_player_push_mode = TRUE;
5826 player->es_player_push_mode = FALSE;
5829 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5830 LOGW("mms protocol is not supported format.\n");
5831 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5834 if (MMPLAYER_IS_STREAMING(player))
5835 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5837 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5839 player->smooth_streaming = FALSE;
5840 player->videodec_linked = 0;
5841 player->videosink_linked = 0;
5842 player->audiodec_linked = 0;
5843 player->audiosink_linked = 0;
5844 player->textsink_linked = 0;
5845 player->is_external_subtitle_present = FALSE;
5846 player->is_external_subtitle_added_now = FALSE;
5847 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5848 player->video360_metadata.is_spherical = -1;
5849 player->is_openal_plugin_used = FALSE;
5850 player->demux_pad_index = 0;
5851 player->subtitle_language_list = NULL;
5852 player->is_subtitle_force_drop = FALSE;
5853 player->last_multiwin_status = FALSE;
5855 __mmplayer_track_initialize(player);
5856 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5858 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5859 player->streamer = __mm_player_streaming_create();
5860 __mm_player_streaming_initialize(player->streamer);
5863 /* realize pipeline */
5864 ret = __mmplayer_gst_realize(player);
5865 if (ret != MM_ERROR_NONE)
5866 LOGE("fail to realize the player.\n");
5868 ret = __mmplayer_realize_streaming_ext(player);
5870 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5878 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
5881 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5883 /* destroy can called at anytime */
5884 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
5885 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
5888 return MM_ERROR_NONE;
5892 _mmplayer_unrealize(MMHandleType hplayer)
5894 mm_player_t* player = (mm_player_t*)hplayer;
5895 int ret = MM_ERROR_NONE;
5899 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5901 MMPLAYER_CMD_UNLOCK(player);
5902 /* destroy the gst bus msg thread which is created during realize.
5903 this funct have to be called before getting cmd lock. */
5904 __mmplayer_bus_msg_thread_destroy(player);
5905 MMPLAYER_CMD_LOCK(player);
5907 /* check current state */
5908 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5910 /* check async state transition */
5911 __mmplayer_check_async_state_transition(player);
5913 __mmplayer_unrealize_streaming_ext(player);
5915 /* unrealize pipeline */
5916 ret = __mmplayer_gst_unrealize(player);
5918 /* set asm stop if success */
5919 if (MM_ERROR_NONE == ret) {
5920 if (!player->interrupted_by_resource) {
5921 if (player->video_decoder_resource != NULL) {
5922 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5923 player->video_decoder_resource);
5924 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5925 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
5927 player->video_decoder_resource = NULL;
5930 if (player->video_overlay_resource != NULL) {
5931 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5932 player->video_overlay_resource);
5933 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5934 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
5936 player->video_overlay_resource = NULL;
5939 ret = mm_resource_manager_commit(player->resource_manager);
5940 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5941 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
5944 LOGE("failed and don't change asm state to stop");
5952 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5954 mm_player_t* player = (mm_player_t*)hplayer;
5956 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5958 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5962 _mmplayer_get_state(MMHandleType hplayer, int* state)
5964 mm_player_t *player = (mm_player_t*)hplayer;
5966 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5968 *state = MMPLAYER_CURRENT_STATE(player);
5970 return MM_ERROR_NONE;
5975 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5977 mm_player_t* player = (mm_player_t*) hplayer;
5978 GstElement* vol_element = NULL;
5983 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5985 LOGD("volume [L]=%f:[R]=%f\n",
5986 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5988 /* invalid factor range or not */
5989 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5990 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5991 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5992 return MM_ERROR_INVALID_ARGUMENT;
5996 /* not support to set other value into each channel */
5997 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5998 return MM_ERROR_INVALID_ARGUMENT;
6000 /* Save volume to handle. Currently the first array element will be saved. */
6001 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
6003 /* check pipeline handle */
6004 if (!player->pipeline || !player->pipeline->audiobin) {
6005 LOGD("audiobin is not created yet\n");
6006 LOGD("but, current stored volume will be set when it's created.\n");
6008 /* NOTE : stored volume will be used in create_audiobin
6009 * returning MM_ERROR_NONE here makes application to able to
6010 * set volume at anytime.
6012 return MM_ERROR_NONE;
6015 /* setting volume to volume element */
6016 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6019 LOGD("volume is set [%f]\n", player->sound.volume);
6020 g_object_set(vol_element, "volume", player->sound.volume, NULL);
6025 return MM_ERROR_NONE;
6030 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
6032 mm_player_t* player = (mm_player_t*) hplayer;
6037 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6038 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
6040 /* returning stored volume */
6041 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
6042 volume->level[i] = player->sound.volume;
6046 return MM_ERROR_NONE;
6050 _mmplayer_set_mute(MMHandleType hplayer, int mute)
6052 mm_player_t* player = (mm_player_t*) hplayer;
6053 GstElement* vol_element = NULL;
6057 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6059 /* mute value shoud 0 or 1 */
6060 if (mute != 0 && mute != 1) {
6061 LOGE("bad mute value\n");
6063 /* FIXIT : definitly, we need _BAD_PARAM error code */
6064 return MM_ERROR_INVALID_ARGUMENT;
6067 player->sound.mute = mute;
6069 /* just hold mute value if pipeline is not ready */
6070 if (!player->pipeline || !player->pipeline->audiobin) {
6071 LOGD("pipeline is not ready. holding mute value\n");
6072 return MM_ERROR_NONE;
6075 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
6077 /* NOTE : volume will only created when the bt is enabled */
6079 LOGD("mute : %d\n", mute);
6080 g_object_set(vol_element, "mute", mute, NULL);
6082 LOGD("volume elemnet is not created. using volume in audiosink\n");
6086 return MM_ERROR_NONE;
6090 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
6092 mm_player_t* player = (mm_player_t*) hplayer;
6096 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6097 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
6099 /* just hold mute value if pipeline is not ready */
6100 if (!player->pipeline || !player->pipeline->audiobin) {
6101 LOGD("pipeline is not ready. returning stored value\n");
6102 *pmute = player->sound.mute;
6103 return MM_ERROR_NONE;
6106 *pmute = player->sound.mute;
6110 return MM_ERROR_NONE;
6114 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
6116 mm_player_t* player = (mm_player_t*) hplayer;
6120 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6122 player->video_stream_changed_cb = callback;
6123 player->video_stream_changed_cb_user_param = user_param;
6124 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
6128 return MM_ERROR_NONE;
6132 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
6134 mm_player_t* player = (mm_player_t*) hplayer;
6138 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6140 player->audio_stream_changed_cb = callback;
6141 player->audio_stream_changed_cb_user_param = user_param;
6142 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
6146 return MM_ERROR_NONE;
6150 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
6152 mm_player_t* player = (mm_player_t*) hplayer;
6156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6158 player->audio_stream_render_cb_ex = callback;
6159 player->audio_stream_cb_user_param = user_param;
6160 player->audio_stream_sink_sync = sync;
6161 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);
6165 return MM_ERROR_NONE;
6169 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
6171 mm_player_t* player = (mm_player_t*) hplayer;
6175 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6177 if (callback && !player->bufmgr)
6178 player->bufmgr = tbm_bufmgr_init(-1);
6180 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
6181 player->video_stream_cb = callback;
6182 player->video_stream_cb_user_param = user_param;
6184 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
6188 return MM_ERROR_NONE;
6192 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
6194 mm_player_t* player = (mm_player_t*) hplayer;
6198 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6200 player->audio_stream_cb = callback;
6201 player->audio_stream_cb_user_param = user_param;
6202 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
6206 return MM_ERROR_NONE;
6210 __mmplayer_start_streaming_ext(mm_player_t *player)
6212 gint ret = MM_ERROR_NONE;
6215 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6217 if (MMPLAYER_IS_HTTP_PD(player)) {
6218 if (!player->pd_downloader) {
6219 ret = __mmplayer_realize_streaming_ext(player);
6221 if (ret != MM_ERROR_NONE) {
6222 LOGE("failed to realize streaming ext\n");
6227 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
6228 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
6230 LOGE("ERROR while starting PD...\n");
6231 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6233 ret = MM_ERROR_NONE;
6242 _mmplayer_start(MMHandleType hplayer)
6244 mm_player_t* player = (mm_player_t*) hplayer;
6245 gint ret = MM_ERROR_NONE;
6249 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6251 /* check current state */
6252 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
6254 /* PD - start streaming */
6255 ret = __mmplayer_start_streaming_ext(player);
6256 if (ret != MM_ERROR_NONE) {
6257 LOGE("failed to start streaming ext 0x%X", ret);
6261 /* start pipeline */
6262 ret = __mmplayer_gst_start(player);
6263 if (ret != MM_ERROR_NONE)
6264 LOGE("failed to start player.\n");
6266 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
6267 LOGD("force playing start even during buffering");
6268 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
6276 /* NOTE: post "not supported codec message" to application
6277 * when one codec is not found during AUTOPLUGGING in MSL.
6278 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
6279 * And, if any codec is not found, don't send message here.
6280 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
6283 __mmplayer_handle_missed_plugin(mm_player_t* player)
6285 MMMessageParamType msg_param;
6286 memset(&msg_param, 0, sizeof(MMMessageParamType));
6287 gboolean post_msg_direct = FALSE;
6291 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6293 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
6294 player->not_supported_codec, player->can_support_codec);
6296 if (player->not_found_demuxer) {
6297 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6298 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
6300 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6301 MMPLAYER_FREEIF(msg_param.data);
6303 return MM_ERROR_NONE;
6306 if (player->not_supported_codec) {
6307 if (player->can_support_codec) {
6308 // There is one codec to play
6309 post_msg_direct = TRUE;
6311 if (player->pipeline->audiobin) // Some content has only PCM data in container.
6312 post_msg_direct = TRUE;
6315 if (post_msg_direct) {
6316 MMMessageParamType msg_param;
6317 memset(&msg_param, 0, sizeof(MMMessageParamType));
6319 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
6320 LOGW("not found AUDIO codec, posting error code to application.\n");
6322 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6323 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6324 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
6325 LOGW("not found VIDEO codec, posting error code to application.\n");
6327 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
6328 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
6331 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6333 MMPLAYER_FREEIF(msg_param.data);
6335 return MM_ERROR_NONE;
6337 // no any supported codec case
6338 LOGW("not found any codec, posting error code to application.\n");
6340 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
6341 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
6342 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
6344 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
6345 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
6348 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6350 MMPLAYER_FREEIF(msg_param.data);
6356 return MM_ERROR_NONE;
6359 static void __mmplayer_check_pipeline(mm_player_t* player)
6361 GstState element_state = GST_STATE_VOID_PENDING;
6362 GstState element_pending_state = GST_STATE_VOID_PENDING;
6364 int ret = MM_ERROR_NONE;
6366 if (player->gapless.reconfigure) {
6367 LOGW("pipeline is under construction.\n");
6369 MMPLAYER_PLAYBACK_LOCK(player);
6370 MMPLAYER_PLAYBACK_UNLOCK(player);
6372 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6374 /* wait for state transition */
6375 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
6377 if (ret == GST_STATE_CHANGE_FAILURE)
6378 LOGE("failed to change pipeline state within %d sec\n", timeout);
6382 /* NOTE : it should be able to call 'stop' anytime*/
6384 _mmplayer_stop(MMHandleType hplayer)
6386 mm_player_t* player = (mm_player_t*)hplayer;
6387 int ret = MM_ERROR_NONE;
6391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6393 /* check current state */
6394 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
6396 /* check pipline building state */
6397 __mmplayer_check_pipeline(player);
6398 __mmplayer_reset_gapless_state(player);
6400 /* NOTE : application should not wait for EOS after calling STOP */
6401 __mmplayer_cancel_eos_timer(player);
6403 __mmplayer_unrealize_streaming_ext(player);
6406 player->seek_state = MMPLAYER_SEEK_NONE;
6409 ret = __mmplayer_gst_stop(player);
6411 if (ret != MM_ERROR_NONE)
6412 LOGE("failed to stop player.\n");
6420 _mmplayer_pause(MMHandleType hplayer)
6422 mm_player_t* player = (mm_player_t*)hplayer;
6423 gint64 pos_nsec = 0;
6424 gboolean async = FALSE;
6425 gint ret = MM_ERROR_NONE;
6429 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6431 /* check current state */
6432 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
6434 /* check pipline building state */
6435 __mmplayer_check_pipeline(player);
6437 switch (MMPLAYER_CURRENT_STATE(player)) {
6438 case MM_PLAYER_STATE_READY:
6440 /* check prepare async or not.
6441 * In the case of streaming playback, it's recommned to avoid blocking wait.
6443 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6444 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
6446 /* Changing back sync of rtspsrc to async */
6447 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
6448 LOGD("async prepare working mode for rtsp");
6454 case MM_PLAYER_STATE_PLAYING:
6456 /* NOTE : store current point to overcome some bad operation
6457 *(returning zero when getting current position in paused state) of some
6460 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
6461 LOGW("getting current position failed in paused\n");
6463 player->last_position = pos_nsec;
6465 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
6466 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
6467 This causes problem is position calculation during normal pause resume scenarios also.
6468 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
6469 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
6470 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
6471 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
6477 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
6478 LOGD("doing async pause in case of ms buff src");
6482 /* pause pipeline */
6483 ret = __mmplayer_gst_pause(player, async);
6485 if (ret != MM_ERROR_NONE)
6486 LOGE("failed to pause player. ret : 0x%x\n", ret);
6488 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
6489 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
6490 LOGE("failed to update display_rotation");
6498 /* in case of streaming, pause could take long time.*/
6500 _mmplayer_abort_pause(MMHandleType hplayer)
6502 mm_player_t* player = (mm_player_t*)hplayer;
6503 int ret = MM_ERROR_NONE;
6507 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
6509 player->pipeline->mainbin,
6510 MM_ERROR_PLAYER_NOT_INITIALIZED);
6512 LOGD("set the pipeline state to READY");
6514 /* set state to READY */
6515 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
6516 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
6517 if (ret != MM_ERROR_NONE) {
6518 LOGE("fail to change state to READY");
6519 return MM_ERROR_PLAYER_INTERNAL;
6522 LOGD("succeeded in changing state to READY");
6528 _mmplayer_resume(MMHandleType hplayer)
6530 mm_player_t* player = (mm_player_t*)hplayer;
6531 int ret = MM_ERROR_NONE;
6532 gboolean async = FALSE;
6536 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6538 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
6539 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
6540 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
6544 /* Changing back sync mode rtspsrc to async */
6545 LOGD("async resume for rtsp case");
6549 /* check current state */
6550 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
6552 ret = __mmplayer_gst_resume(player, async);
6553 if (ret != MM_ERROR_NONE)
6554 LOGE("failed to resume player.\n");
6556 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
6557 LOGD("force resume even during buffering");
6558 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
6567 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
6569 mm_player_t* player = (mm_player_t*)hplayer;
6570 gint64 pos_nsec = 0;
6571 int ret = MM_ERROR_NONE;
6573 signed long long start = 0, stop = 0;
6574 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6577 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6578 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
6580 /* The sound of video is not supported under 0.0 and over 2.0. */
6581 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
6582 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
6585 _mmplayer_set_mute(hplayer, mute);
6587 if (player->playback_rate == rate)
6588 return MM_ERROR_NONE;
6590 /* If the position is reached at start potion during fast backward, EOS is posted.
6591 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
6593 player->playback_rate = rate;
6595 current_state = MMPLAYER_CURRENT_STATE(player);
6597 if (current_state != MM_PLAYER_STATE_PAUSED)
6598 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
6600 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
6602 if ((current_state == MM_PLAYER_STATE_PAUSED)
6603 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
6604 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
6605 pos_nsec = player->last_position;
6610 stop = GST_CLOCK_TIME_NONE;
6612 start = GST_CLOCK_TIME_NONE;
6616 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
6617 player->playback_rate,
6619 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
6620 GST_SEEK_TYPE_SET, start,
6621 GST_SEEK_TYPE_SET, stop)) {
6622 LOGE("failed to set speed playback\n");
6623 return MM_ERROR_PLAYER_SEEK;
6626 LOGD("succeeded to set speed playback as %0.1f\n", rate);
6630 return MM_ERROR_NONE;;
6634 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
6636 mm_player_t* player = (mm_player_t*)hplayer;
6637 int ret = MM_ERROR_NONE;
6641 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6643 /* check pipline building state */
6644 __mmplayer_check_pipeline(player);
6646 ret = __mmplayer_gst_set_position(player, position, FALSE);
6654 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
6656 mm_player_t* player = (mm_player_t*)hplayer;
6657 int ret = MM_ERROR_NONE;
6659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6661 ret = __mmplayer_gst_get_position(player, position);
6667 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
6669 mm_player_t* player = (mm_player_t*)hplayer;
6670 int ret = MM_ERROR_NONE;
6672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6673 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
6675 *duration = player->duration;
6680 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
6682 mm_player_t* player = (mm_player_t*)hplayer;
6683 int ret = MM_ERROR_NONE;
6685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6687 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
6693 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
6695 mm_player_t* player = (mm_player_t*)hplayer;
6696 int ret = MM_ERROR_NONE;
6700 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6702 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
6710 __mmplayer_is_midi_type(gchar* str_caps)
6712 if ((g_strrstr(str_caps, "audio/midi")) ||
6713 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
6714 (g_strrstr(str_caps, "application/x-smaf")) ||
6715 (g_strrstr(str_caps, "audio/x-imelody")) ||
6716 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
6717 (g_strrstr(str_caps, "audio/xmf")) ||
6718 (g_strrstr(str_caps, "audio/mxmf"))) {
6727 __mmplayer_is_only_mp3_type(gchar *str_caps)
6729 if (g_strrstr(str_caps, "application/x-id3") ||
6730 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
6736 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
6738 GstStructure* caps_structure = NULL;
6739 gint samplerate = 0;
6743 MMPLAYER_RETURN_IF_FAIL(player && caps);
6745 caps_structure = gst_caps_get_structure(caps, 0);
6747 /* set stream information */
6748 gst_structure_get_int(caps_structure, "rate", &samplerate);
6749 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
6751 gst_structure_get_int(caps_structure, "channels", &channels);
6752 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
6754 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
6758 __mmplayer_update_content_type_info(mm_player_t* player)
6761 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6763 if (__mmplayer_is_midi_type(player->type)) {
6764 player->bypass_audio_effect = TRUE;
6765 } else if (g_strrstr(player->type, "application/x-hls")) {
6766 /* If it can't know exact type when it parses uri because of redirection case,
6767 * it will be fixed by typefinder or when doing autoplugging.
6769 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6770 if (player->streamer) {
6771 player->streamer->is_adaptive_streaming = TRUE;
6772 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6773 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
6775 } else if (g_strrstr(player->type, "application/dash+xml")) {
6776 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6777 if (player->streamer) {
6778 player->streamer->is_adaptive_streaming = TRUE;
6779 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6783 LOGD("uri type : %d", player->profile.uri_type);
6788 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
6789 GstCaps *caps, gpointer data)
6791 mm_player_t* player = (mm_player_t*)data;
6796 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6798 /* store type string */
6799 MMPLAYER_FREEIF(player->type);
6800 player->type = gst_caps_to_string(caps);
6802 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
6803 player, player->type, probability, gst_caps_get_size(caps));
6806 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6807 (g_strrstr(player->type, "audio/x-raw-int"))) {
6808 LOGE("not support media format\n");
6810 if (player->msg_posted == FALSE) {
6811 MMMessageParamType msg_param;
6812 memset(&msg_param, 0, sizeof(MMMessageParamType));
6814 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6815 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6817 /* don't post more if one was sent already */
6818 player->msg_posted = TRUE;
6823 __mmplayer_update_content_type_info(player);
6825 pad = gst_element_get_static_pad(tf, "src");
6827 LOGE("fail to get typefind src pad.\n");
6831 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
6832 gboolean async = FALSE;
6833 LOGE("failed to autoplug %s\n", player->type);
6835 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6837 if (async && player->msg_posted == FALSE)
6838 __mmplayer_handle_missed_plugin(player);
6844 gst_object_unref(GST_OBJECT(pad));
6852 __mmplayer_create_decodebin(mm_player_t* player)
6854 GstElement *decodebin = NULL;
6858 /* create decodebin */
6859 decodebin = gst_element_factory_make("decodebin", NULL);
6862 LOGE("fail to create decodebin\n");
6866 /* raw pad handling signal */
6867 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6868 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
6870 /* no-more-pad pad handling signal */
6871 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6872 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6874 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6875 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6877 /* This signal is emitted when a pad for which there is no further possible
6878 decoding is added to the decodebin.*/
6879 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6880 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6882 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6883 before looking for any elements that can handle that stream.*/
6884 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6885 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6887 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6888 before looking for any elements that can handle that stream.*/
6889 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6890 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
6892 /* This signal is emitted once decodebin has finished decoding all the data.*/
6893 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6894 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6896 /* This signal is emitted when a element is added to the bin.*/
6897 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6898 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
6905 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
6907 MMPlayerGstElement* mainbin = NULL;
6908 GstElement* decodebin = NULL;
6909 GstElement* queue2 = NULL;
6910 GstPad* sinkpad = NULL;
6911 GstPad* qsrcpad = NULL;
6912 gint64 dur_bytes = 0L;
6914 guint max_buffer_size_bytes = 0;
6915 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6918 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6920 mainbin = player->pipeline->mainbin;
6922 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
6923 (MMPLAYER_IS_HTTP_STREAMING(player))) {
6924 LOGD("creating http streaming buffering queue(queue2)\n");
6926 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6927 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
6929 queue2 = gst_element_factory_make("queue2", "queue2");
6931 LOGE("failed to create buffering queue element\n");
6935 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6936 LOGE("failed to add buffering queue\n");
6940 sinkpad = gst_element_get_static_pad(queue2, "sink");
6941 qsrcpad = gst_element_get_static_pad(queue2, "src");
6943 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6944 LOGE("failed to link buffering queue");
6948 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6949 LOGE("fail to get duration");
6951 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6953 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6955 if (dur_bytes > 0) {
6956 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
6957 type = MUXED_BUFFER_TYPE_FILE;
6959 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6960 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6966 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
6967 * skip the pull mode(file or ring buffering) setting. */
6968 if (!g_strrstr(player->type, "video/mpegts")) {
6969 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
6970 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
6972 __mm_player_streaming_set_queue2(player->streamer,
6975 max_buffer_size_bytes,
6976 player->ini.http_buffering_time,
6977 1.0, /* no meaning */
6978 player->ini.http_buffering_limit, /* no meaning */
6980 player->http_file_buffering_path,
6981 (guint64)dur_bytes);
6984 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
6985 LOGE("failed to sync queue2 state with parent\n");
6991 gst_object_unref(GST_OBJECT(sinkpad));
6993 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6994 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6998 /* create decodebin */
6999 decodebin = __mmplayer_create_decodebin(player);
7002 LOGE("can not create autoplug element\n");
7006 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
7007 LOGE("failed to add decodebin\n");
7011 /* to force caps on the decodebin element and avoid reparsing stuff by
7012 * typefind. It also avoids a deadlock in the way typefind activates pads in
7013 * the state change */
7014 g_object_set(decodebin, "sink-caps", caps, NULL);
7016 sinkpad = gst_element_get_static_pad(decodebin, "sink");
7018 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
7019 LOGE("failed to link decodebin\n");
7023 gst_object_unref(GST_OBJECT(sinkpad));
7025 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
7026 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
7028 /* set decodebin property about buffer in streaming playback. *
7029 * in case of HLS/DASH, it does not need to have big buffer *
7030 * because it is kind of adaptive streaming. */
7031 if (!MMPLAYER_IS_HTTP_PD(player) &&
7032 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
7033 gdouble high_percent = 0.0;
7035 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
7036 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
7038 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
7039 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
7041 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
7042 "high-percent", (gint)high_percent,
7043 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
7044 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
7045 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
7046 "max-size-buffers", 0, NULL); // disable or automatic
7049 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
7050 LOGE("failed to sync decodebin state with parent\n");
7061 gst_object_unref(GST_OBJECT(sinkpad));
7064 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
7065 * You need to explicitly set elements to the NULL state before
7066 * dropping the final reference, to allow them to clean up.
7068 gst_element_set_state(queue2, GST_STATE_NULL);
7070 /* And, it still has a parent "player".
7071 * You need to let the parent manage the object instead of unreffing the object directly.
7073 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
7074 gst_object_unref(queue2);
7079 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
7080 * You need to explicitly set elements to the NULL state before
7081 * dropping the final reference, to allow them to clean up.
7083 gst_element_set_state(decodebin, GST_STATE_NULL);
7085 /* And, it still has a parent "player".
7086 * You need to let the parent manage the object instead of unreffing the object directly.
7089 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
7090 gst_object_unref(decodebin);
7098 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
7102 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7103 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
7105 LOGD("class : %s, mime : %s \n", factory_class, mime);
7107 /* add missing plugin */
7108 /* NOTE : msl should check missing plugin for image mime type.
7109 * Some motion jpeg clips can have playable audio track.
7110 * So, msl have to play audio after displaying popup written video format not supported.
7112 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
7113 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
7114 LOGD("not found demuxer\n");
7115 player->not_found_demuxer = TRUE;
7116 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
7122 if (!g_strrstr(factory_class, "Demuxer")) {
7123 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
7124 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
7125 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
7127 /* check that clip have multi tracks or not */
7128 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
7129 LOGD("video plugin is already linked\n");
7131 LOGW("add VIDEO to missing plugin\n");
7132 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
7133 player->unlinked_video_mime = g_strdup_printf("%s", mime);
7135 } else if (g_str_has_prefix(mime, "audio")) {
7136 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
7137 LOGD("audio plugin is already linked\n");
7139 LOGW("add AUDIO to missing plugin\n");
7140 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
7141 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
7149 return MM_ERROR_NONE;
7154 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
7156 mm_player_t* player = (mm_player_t*)data;
7160 MMPLAYER_RETURN_IF_FAIL(player);
7162 /* remove fakesink. */
7163 if (!__mmplayer_gst_remove_fakesink(player,
7164 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
7165 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
7166 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
7167 * source element are not same. To overcome this situation, this function will called
7168 * several places and several times. Therefore, this is not an error case.
7173 LOGD("[handle: %p] pipeline has completely constructed", player);
7175 if ((player->ini.async_start) &&
7176 (player->msg_posted == FALSE) &&
7177 (player->cmd >= MMPLAYER_COMMAND_START))
7178 __mmplayer_handle_missed_plugin(player);
7180 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
7184 __mmplayer_check_profile(void)
7187 static int profile_tv = -1;
7189 if (__builtin_expect(profile_tv != -1, 1))
7192 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
7193 switch (*profileName) {
7208 __mmplayer_get_next_uri(mm_player_t *player)
7210 MMPlayerParseProfile profile;
7212 guint num_of_list = 0;
7215 num_of_list = g_list_length(player->uri_info.uri_list);
7216 uri_idx = player->uri_info.uri_idx;
7218 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
7219 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
7220 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
7222 LOGW("next uri does not exist");
7226 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
7227 LOGE("failed to parse profile");
7231 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
7232 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
7233 LOGW("uri type is not supported(%d)", profile.uri_type);
7237 LOGD("success to find next uri %d", uri_idx);
7241 if (uri_idx == num_of_list) {
7242 LOGE("failed to find next uri");
7246 player->uri_info.uri_idx = uri_idx;
7247 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
7249 if (mmf_attrs_commit(player->attrs)) {
7250 LOGE("failed to commit");
7254 SECURE_LOGD("next playback uri: %s", uri);
7259 __mmplayer_verify_next_play_path(mm_player_t *player)
7261 #define REPEAT_COUNT_INFINITELY -1
7262 #define REPEAT_COUNT_MIN 2
7264 MMHandleType attrs = 0;
7265 gint mode = MM_PLAYER_PD_MODE_NONE;
7269 guint num_of_list = 0;
7270 int profile_tv = -1;
7274 LOGD("checking for next play option");
7276 if (player->pipeline->textbin) {
7277 LOGE("subtitle path is enabled. gapless play is not supported.\n");
7281 attrs = MMPLAYER_GET_ATTRS(player);
7283 LOGE("fail to get attributes.\n");
7287 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
7289 /* gapless playback is not supported in case of video at TV profile. */
7290 profile_tv = __mmplayer_check_profile();
7291 if (profile_tv && video) {
7292 LOGW("not support video gapless playback");
7296 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
7303 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
7304 LOGE("failed to get play count");
7306 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
7307 LOGE("failed to get gapless mode");
7309 /* check repeat count in case of audio */
7311 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
7312 LOGW("gapless is disabled");
7316 num_of_list = g_list_length(player->uri_info.uri_list);
7318 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
7320 if (num_of_list == 0) {
7321 /* audio looping path */
7322 if (count >= REPEAT_COUNT_MIN) {
7323 /* decrease play count */
7324 /* we succeeded to rewind. update play count and then wait for next EOS */
7327 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
7329 /* commit attribute */
7330 if (mmf_attrs_commit(attrs))
7331 LOGE("failed to commit attribute");
7332 } else if (count != REPEAT_COUNT_INFINITELY) {
7333 LOGD("there is no next uri and no repeat");
7337 LOGD("looping cnt %d", count);
7339 /* gapless playback path */
7340 if (!__mmplayer_get_next_uri(player)) {
7341 LOGE("failed to get next uri");
7349 LOGE("unable to play next path. EOS will be posted soon");
7354 __mmplayer_initialize_next_play(mm_player_t *player)
7360 player->smooth_streaming = FALSE;
7361 player->videodec_linked = 0;
7362 player->audiodec_linked = 0;
7363 player->videosink_linked = 0;
7364 player->audiosink_linked = 0;
7365 player->textsink_linked = 0;
7366 player->is_external_subtitle_present = FALSE;
7367 player->is_external_subtitle_added_now = FALSE;
7368 player->not_supported_codec = MISSING_PLUGIN_NONE;
7369 player->can_support_codec = FOUND_PLUGIN_NONE;
7370 player->pending_seek.is_pending = FALSE;
7371 player->pending_seek.pos = 0;
7372 player->msg_posted = FALSE;
7373 player->has_many_types = FALSE;
7374 player->no_more_pad = FALSE;
7375 player->not_found_demuxer = 0;
7376 player->seek_state = MMPLAYER_SEEK_NONE;
7377 player->max_audio_channels = 0;
7378 player->is_subtitle_force_drop = FALSE;
7379 player->play_subtitle = FALSE;
7380 player->adjust_subtitle_pos = 0;
7382 player->total_bitrate = 0;
7383 player->total_maximum_bitrate = 0;
7385 __mmplayer_track_initialize(player);
7386 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7388 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7389 player->bitrate[i] = 0;
7390 player->maximum_bitrate[i] = 0;
7393 if (player->v_stream_caps) {
7394 gst_caps_unref(player->v_stream_caps);
7395 player->v_stream_caps = NULL;
7398 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7400 /* clean found parsers */
7401 if (player->parsers) {
7402 GList *parsers = player->parsers;
7403 for (; parsers; parsers = g_list_next(parsers)) {
7404 gchar *name = parsers->data;
7405 MMPLAYER_FREEIF(name);
7407 g_list_free(player->parsers);
7408 player->parsers = NULL;
7411 /* clean found audio decoders */
7412 if (player->audio_decoders) {
7413 GList *a_dec = player->audio_decoders;
7414 for (; a_dec; a_dec = g_list_next(a_dec)) {
7415 gchar *name = a_dec->data;
7416 MMPLAYER_FREEIF(name);
7418 g_list_free(player->audio_decoders);
7419 player->audio_decoders = NULL;
7426 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
7428 MMPlayerGstElement *mainbin = NULL;
7429 MMMessageParamType msg_param = {0,};
7430 GstElement *element = NULL;
7431 MMHandleType attrs = 0;
7433 enum MainElementID elemId = MMPLAYER_M_NUM;
7437 if (!player || !player->pipeline || !player->pipeline->mainbin) {
7438 LOGE("player is not initialized");
7442 mainbin = player->pipeline->mainbin;
7443 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
7445 attrs = MMPLAYER_GET_ATTRS(player);
7447 LOGE("fail to get attributes");
7451 /* Initialize Player values */
7452 __mmplayer_initialize_next_play(player);
7454 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
7456 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
7457 LOGE("failed to parse profile");
7458 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
7462 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
7463 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
7464 LOGE("dash or hls is not supportable");
7465 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
7469 element = __mmplayer_gst_build_source(player);
7471 LOGE("no source element was created");
7475 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
7476 LOGE("failed to add source element to pipeline");
7477 gst_object_unref(GST_OBJECT(element));
7482 /* take source element */
7483 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
7484 mainbin[MMPLAYER_M_SRC].gst = element;
7488 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7489 if (player->streamer == NULL) {
7490 player->streamer = __mm_player_streaming_create();
7491 __mm_player_streaming_initialize(player->streamer);
7494 elemId = MMPLAYER_M_TYPEFIND;
7495 element = gst_element_factory_make("typefind", "typefinder");
7496 __mmplayer_add_signal_connection(player, G_OBJECT(element),
7497 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
7499 elemId = MMPLAYER_M_AUTOPLUG;
7500 element = __mmplayer_create_decodebin(player);
7503 /* check autoplug element is OK */
7505 LOGE("can not create element(%d)", elemId);
7509 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
7510 LOGE("failed to add sinkbin to pipeline");
7511 gst_object_unref(GST_OBJECT(element));
7516 mainbin[elemId].id = elemId;
7517 mainbin[elemId].gst = element;
7519 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
7520 LOGE("Failed to link src - autoplug(or typefind)");
7524 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
7525 LOGE("Failed to change state of src element");
7529 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
7530 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
7531 LOGE("Failed to change state of decodebin");
7535 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
7536 LOGE("Failed to change state of src element");
7541 player->gapless.stream_changed = TRUE;
7542 player->gapless.running = TRUE;
7548 MMPLAYER_PLAYBACK_UNLOCK(player);
7550 if (!player->msg_posted) {
7551 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7552 player->msg_posted = TRUE;
7559 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
7561 mm_player_selector_t *selector = &player->selector[type];
7562 MMPlayerGstElement *sinkbin = NULL;
7563 enum MainElementID selectorId = MMPLAYER_M_NUM;
7564 enum MainElementID sinkId = MMPLAYER_M_NUM;
7565 GstPad *srcpad = NULL;
7566 GstPad *sinkpad = NULL;
7567 gboolean send_notice = FALSE;
7570 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7572 LOGD("type %d", type);
7575 case MM_PLAYER_TRACK_TYPE_AUDIO:
7576 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
7577 sinkId = MMPLAYER_A_BIN;
7578 sinkbin = player->pipeline->audiobin;
7580 case MM_PLAYER_TRACK_TYPE_VIDEO:
7581 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
7582 sinkId = MMPLAYER_V_BIN;
7583 sinkbin = player->pipeline->videobin;
7586 case MM_PLAYER_TRACK_TYPE_TEXT:
7587 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
7588 sinkId = MMPLAYER_T_BIN;
7589 sinkbin = player->pipeline->textbin;
7592 LOGE("requested type is not supportable");
7597 if (player->pipeline->mainbin[selectorId].gst) {
7600 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
7602 if (selector->event_probe_id != 0)
7603 gst_pad_remove_probe(srcpad, selector->event_probe_id);
7604 selector->event_probe_id = 0;
7606 if ((sinkbin) && (sinkbin[sinkId].gst)) {
7607 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
7609 if (srcpad && sinkpad) {
7610 /* after getting drained signal there is no data flows, so no need to do pad_block */
7611 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
7612 gst_pad_unlink(srcpad, sinkpad);
7614 /* send custom event to sink pad to handle it at video sink */
7616 LOGD("send custom event to sinkpad");
7617 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
7618 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
7619 gst_pad_send_event(sinkpad, event);
7623 gst_object_unref(sinkpad);
7626 gst_object_unref(srcpad);
7629 LOGD("selector release");
7631 /* release and unref requests pad from the selector */
7632 for (n = 0; n < selector->channels->len; n++) {
7633 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
7634 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
7636 g_ptr_array_set_size(selector->channels, 0);
7638 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
7639 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
7641 player->pipeline->mainbin[selectorId].gst = NULL;
7649 __mmplayer_deactivate_old_path(mm_player_t *player)
7652 MMPLAYER_RETURN_IF_FAIL(player);
7654 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
7655 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
7656 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
7657 LOGE("deactivate selector error");
7661 __mmplayer_track_destroy(player);
7662 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7664 if (player->streamer) {
7665 __mm_player_streaming_deinitialize(player->streamer);
7666 __mm_player_streaming_destroy(player->streamer);
7667 player->streamer = NULL;
7670 MMPLAYER_PLAYBACK_LOCK(player);
7671 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
7678 if (!player->msg_posted) {
7679 MMMessageParamType msg = {0,};
7682 msg.code = MM_ERROR_PLAYER_INTERNAL;
7683 LOGE("next_uri_play> deactivate error");
7685 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
7686 player->msg_posted = TRUE;
7691 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
7693 int result = MM_ERROR_NONE;
7694 mm_player_t* player = (mm_player_t*) hplayer;
7697 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7700 player->http_file_buffering_path = (gchar*)file_path;
7701 LOGD("temp file path: %s\n", player->http_file_buffering_path);
7707 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
7709 int result = MM_ERROR_NONE;
7710 mm_player_t* player = (mm_player_t*) hplayer;
7713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7715 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
7716 if (mmf_attrs_commit(player->attrs)) {
7717 LOGE("failed to commit the original uri.\n");
7718 result = MM_ERROR_PLAYER_INTERNAL;
7720 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
7721 LOGE("failed to add the original uri in the uri list.\n");
7728 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
7730 mm_player_t* player = (mm_player_t*) hplayer;
7731 guint num_of_list = 0;
7735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7736 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
7738 if (player->pipeline && player->pipeline->textbin) {
7739 LOGE("subtitle path is enabled.\n");
7740 return MM_ERROR_PLAYER_INVALID_STATE;
7743 num_of_list = g_list_length(player->uri_info.uri_list);
7745 if (is_first_path == TRUE) {
7746 if (num_of_list == 0) {
7747 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
7748 LOGD("add original path : %s", uri);
7750 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
7751 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
7753 LOGD("change original path : %s", uri);
7756 MMHandleType attrs = 0;
7757 attrs = MMPLAYER_GET_ATTRS(player);
7759 if (num_of_list == 0) {
7760 char *original_uri = NULL;
7763 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
7765 if (!original_uri) {
7766 LOGE("there is no original uri.");
7767 return MM_ERROR_PLAYER_INVALID_STATE;
7770 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
7771 player->uri_info.uri_idx = 0;
7773 LOGD("add original path at first : %s(%d)", original_uri);
7777 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
7778 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
7782 return MM_ERROR_NONE;
7785 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
7787 mm_player_t* player = (mm_player_t*) hplayer;
7788 char *next_uri = NULL;
7789 guint num_of_list = 0;
7792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7794 num_of_list = g_list_length(player->uri_info.uri_list);
7796 if (num_of_list > 0) {
7797 gint uri_idx = player->uri_info.uri_idx;
7799 if (uri_idx < num_of_list-1)
7804 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
7805 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
7807 *uri = g_strdup(next_uri);
7811 return MM_ERROR_NONE;
7815 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
7816 GstCaps *caps, gpointer data)
7818 mm_player_t* player = (mm_player_t*)data;
7819 const gchar* klass = NULL;
7820 const gchar* mime = NULL;
7821 gchar* caps_str = NULL;
7823 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
7824 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7825 caps_str = gst_caps_to_string(caps);
7827 LOGW("unknown type of caps : %s from %s",
7828 caps_str, GST_ELEMENT_NAME(elem));
7830 MMPLAYER_FREEIF(caps_str);
7832 /* There is no available codec. */
7833 __mmplayer_check_not_supported_codec(player, klass, mime);
7837 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
7838 GstCaps * caps, gpointer data)
7840 mm_player_t* player = (mm_player_t*)data;
7841 const char* mime = NULL;
7842 gboolean ret = TRUE;
7844 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7845 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7847 if (g_str_has_prefix(mime, "audio")) {
7848 GstStructure* caps_structure = NULL;
7849 gint samplerate = 0;
7851 gchar *caps_str = NULL;
7853 caps_structure = gst_caps_get_structure(caps, 0);
7854 gst_structure_get_int(caps_structure, "rate", &samplerate);
7855 gst_structure_get_int(caps_structure, "channels", &channels);
7857 if ((channels > 0 && samplerate == 0)) {
7858 LOGD("exclude audio...");
7862 caps_str = gst_caps_to_string(caps);
7863 /* set it directly because not sent by TAG */
7864 if (g_strrstr(caps_str, "mobile-xmf"))
7865 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
7866 MMPLAYER_FREEIF(caps_str);
7867 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
7868 MMMessageParamType msg_param;
7869 memset(&msg_param, 0, sizeof(MMMessageParamType));
7870 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
7871 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7872 LOGD("video file is not supported on this device");
7874 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7875 LOGD("already video linked");
7878 LOGD("found new stream");
7885 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
7887 int ret = MM_ERROR_NONE;
7889 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7891 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7892 GstStructure* str = NULL;
7894 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7896 LOGD("audio codec type: %d", codec_type);
7897 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7898 /* sw codec will be skipped */
7899 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7900 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7901 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7902 ret = MM_ERROR_PLAYER_INTERNAL;
7906 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7907 /* hw codec will be skipped */
7908 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7909 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7910 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7911 ret = MM_ERROR_PLAYER_INTERNAL;
7916 str = gst_caps_get_structure(caps, 0);
7918 gst_structure_get_int(str, "channels", &channels);
7920 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
7921 if (player->max_audio_channels < channels)
7922 player->max_audio_channels = channels;
7924 /* set stream information */
7925 if (!player->audiodec_linked)
7926 __mmplayer_set_audio_attrs(player, caps);
7928 /* update codec info */
7929 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7930 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7931 player->audiodec_linked = 1;
7933 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7935 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7937 LOGD("video codec type: %d", codec_type);
7938 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7939 /* sw codec is skipped */
7940 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7941 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7942 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7943 ret = MM_ERROR_PLAYER_INTERNAL;
7947 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7948 /* hw codec is skipped */
7949 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7950 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7951 ret = MM_ERROR_PLAYER_INTERNAL;
7956 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7957 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7959 /* mark video decoder for acquire */
7960 if (player->video_decoder_resource == NULL) {
7961 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7962 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7963 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7964 &player->video_decoder_resource)
7965 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7966 LOGE("could not mark video_decoder resource for acquire");
7967 ret = MM_ERROR_PLAYER_INTERNAL;
7971 LOGW("video decoder resource is already acquired, skip it.");
7972 ret = MM_ERROR_PLAYER_INTERNAL;
7976 player->interrupted_by_resource = FALSE;
7977 /* acquire resources for video playing */
7978 if (mm_resource_manager_commit(player->resource_manager)
7979 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7980 LOGE("could not acquire resources for video decoding\n");
7981 ret = MM_ERROR_PLAYER_INTERNAL;
7986 /* update codec info */
7987 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7988 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7989 player->videodec_linked = 1;
7997 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7998 GstCaps* caps, GstElementFactory* factory, gpointer data)
8000 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
8001 We are defining our own and will be removed when it actually exposed */
8003 GST_AUTOPLUG_SELECT_TRY,
8004 GST_AUTOPLUG_SELECT_EXPOSE,
8005 GST_AUTOPLUG_SELECT_SKIP
8006 } GstAutoplugSelectResult;
8008 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
8009 mm_player_t* player = (mm_player_t*)data;
8011 gchar* factory_name = NULL;
8012 gchar* caps_str = NULL;
8013 const gchar* klass = NULL;
8016 factory_name = GST_OBJECT_NAME(factory);
8017 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
8018 caps_str = gst_caps_to_string(caps);
8020 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
8022 /* store type string */
8023 if (player->type == NULL) {
8024 player->type = gst_caps_to_string(caps);
8025 __mmplayer_update_content_type_info(player);
8028 /* filtering exclude keyword */
8029 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
8030 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
8031 LOGW("skipping [%s] by exculde keyword [%s]\n",
8032 factory_name, player->ini.exclude_element_keyword[idx]);
8034 result = GST_AUTOPLUG_SELECT_SKIP;
8039 /* exclude webm format */
8040 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
8041 * because webm format is not supportable.
8042 * If webm is disabled in "autoplug-continue", there is no state change
8043 * failure or error because the decodebin will expose the pad directly.
8044 * It make MSL invoke _prepare_async_callback.
8045 * So, we need to disable webm format in "autoplug-select" */
8046 if (caps_str && strstr(caps_str, "webm")) {
8047 LOGW("webm is not supported");
8048 result = GST_AUTOPLUG_SELECT_SKIP;
8052 /* check factory class for filtering */
8053 /* NOTE : msl don't need to use image plugins.
8054 * So, those plugins should be skipped for error handling.
8056 if (g_strrstr(klass, "Codec/Decoder/Image")) {
8057 LOGD("skipping [%s] by not required\n", factory_name);
8058 result = GST_AUTOPLUG_SELECT_SKIP;
8062 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
8063 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
8064 // TO CHECK : subtitle if needed, add subparse exception.
8065 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
8066 result = GST_AUTOPLUG_SELECT_SKIP;
8070 if (g_strrstr(factory_name, "mpegpsdemux")) {
8071 LOGD("skipping PS container - not support\n");
8072 result = GST_AUTOPLUG_SELECT_SKIP;
8076 if (g_strrstr(factory_name, "mssdemux"))
8077 player->smooth_streaming = TRUE;
8079 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
8080 (g_strrstr(klass, "Codec/Decoder/Video"))) {
8083 GstStructure *str = NULL;
8084 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
8086 /* don't make video because of not required */
8087 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
8088 (player->set_mode.media_packet_video_stream == FALSE)) {
8089 LOGD("no video because it's not required. -> return expose");
8090 result = GST_AUTOPLUG_SELECT_EXPOSE;
8094 /* get w/h for omx state-tune */
8095 /* FIXME: deprecated? */
8096 str = gst_caps_get_structure(caps, 0);
8097 gst_structure_get_int(str, "width", &width);
8100 if (player->v_stream_caps) {
8101 gst_caps_unref(player->v_stream_caps);
8102 player->v_stream_caps = NULL;
8105 player->v_stream_caps = gst_caps_copy(caps);
8106 LOGD("take caps for video state tune");
8107 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
8111 if (g_strrstr(klass, "Codec/Decoder")) {
8112 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
8113 LOGD("skipping %s codec", factory_name);
8114 result = GST_AUTOPLUG_SELECT_SKIP;
8120 MMPLAYER_FREEIF(caps_str);
8126 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
8129 //mm_player_t* player = (mm_player_t*)data;
8130 GstCaps* caps = NULL;
8132 LOGD("[Decodebin2] pad-removed signal\n");
8134 caps = gst_pad_query_caps(new_pad, NULL);
8136 gchar* caps_str = NULL;
8137 caps_str = gst_caps_to_string(caps);
8139 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
8141 MMPLAYER_FREEIF(caps_str);
8142 gst_caps_unref(caps);
8147 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
8149 mm_player_t* player = (mm_player_t*)data;
8150 GstIterator *iter = NULL;
8151 GValue item = { 0, };
8153 gboolean done = FALSE;
8154 gboolean is_all_drained = TRUE;
8157 MMPLAYER_RETURN_IF_FAIL(player);
8159 LOGD("__mmplayer_gst_decode_drained");
8161 if (player->use_deinterleave == TRUE) {
8162 LOGD("group playing mode.");
8166 if (!MMPLAYER_CMD_TRYLOCK(player)) {
8167 LOGW("Fail to get cmd lock");
8171 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
8172 !__mmplayer_verify_next_play_path(player)) {
8173 LOGD("decoding is finished.");
8174 __mmplayer_reset_gapless_state(player);
8175 MMPLAYER_CMD_UNLOCK(player);
8179 player->gapless.reconfigure = TRUE;
8181 /* check decodebin src pads whether they received EOS or not */
8182 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
8185 switch (gst_iterator_next(iter, &item)) {
8186 case GST_ITERATOR_OK:
8187 pad = g_value_get_object(&item);
8188 if (pad && !GST_PAD_IS_EOS(pad)) {
8189 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
8190 is_all_drained = FALSE;
8193 g_value_reset(&item);
8195 case GST_ITERATOR_RESYNC:
8196 gst_iterator_resync(iter);
8198 case GST_ITERATOR_ERROR:
8199 case GST_ITERATOR_DONE:
8204 g_value_unset(&item);
8205 gst_iterator_free(iter);
8207 if (!is_all_drained) {
8208 LOGD("Wait util the all pads get EOS.");
8209 MMPLAYER_CMD_UNLOCK(player);
8214 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
8215 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
8217 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
8218 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
8219 __mmplayer_deactivate_old_path(player);
8220 MMPLAYER_CMD_UNLOCK(player);
8226 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
8228 mm_player_t* player = (mm_player_t*)data;
8229 const gchar* klass = NULL;
8230 gchar* factory_name = NULL;
8232 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
8233 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8235 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
8237 if (__mmplayer_add_dump_buffer_probe(player, element))
8238 LOGD("add buffer probe");
8241 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
8242 gchar* selected = NULL;
8243 selected = g_strdup(GST_ELEMENT_NAME(element));
8244 player->audio_decoders = g_list_append(player->audio_decoders, selected);
8248 if (g_strrstr(klass, "Parser")) {
8249 gchar* selected = NULL;
8251 selected = g_strdup(factory_name);
8252 player->parsers = g_list_append(player->parsers, selected);
8255 if (g_strrstr(klass, "Demuxer/Adaptive")) {
8256 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
8257 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
8259 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
8260 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
8262 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8263 "max-bandwidth", player->adaptive_info.limit.bandwidth,
8264 "max-video-width", player->adaptive_info.limit.width,
8265 "max-video-height", player->adaptive_info.limit.height, NULL);
8267 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
8268 /* FIXIT : first value will be overwritten if there's more
8269 * than 1 demuxer/parser
8272 //LOGD("plugged element is demuxer. take it\n");
8273 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
8274 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
8276 /*Added for multi audio support */ // Q. del?
8277 if (g_strrstr(klass, "Demux")) {
8278 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
8279 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
8283 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
8284 int surface_type = 0;
8286 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
8289 // to support trust-zone only
8290 if (g_strrstr(factory_name, "asfdemux")) {
8291 LOGD("set file-location %s\n", player->profile.uri);
8292 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
8294 if (player->video_hub_download_mode == TRUE)
8295 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
8296 } else if (g_strrstr(factory_name, "legacyh264parse")) {
8297 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
8298 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
8299 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
8300 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
8301 (__mmplayer_is_only_mp3_type(player->type))) {
8302 LOGD("[mpegaudioparse] set streaming pull mode.");
8303 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
8305 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
8306 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
8309 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
8310 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
8311 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
8313 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
8314 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
8316 if (!MMPLAYER_IS_HTTP_PD(player) &&
8317 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
8318 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
8319 (MMPLAYER_IS_DASH_STREAMING(player)))) {
8320 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
8321 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
8322 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
8330 gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
8333 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8335 if (MMPLAYER_IS_STREAMING(player))
8338 /* This callback can be set to music player only. */
8339 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
8340 LOGW("audio callback is not supported for video");
8344 if (player->audio_stream_cb) {
8347 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
8350 LOGE("failed to get sink pad from audiosink to probe data\n");
8353 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
8354 __mmplayer_audio_stream_probe, player, NULL);
8356 gst_object_unref(pad);
8360 LOGE("There is no audio callback to configure.\n");
8370 __mmplayer_release_misc(mm_player_t* player)
8373 bool cur_mode = player->set_mode.rich_audio;
8376 MMPLAYER_RETURN_IF_FAIL(player);
8378 player->video_stream_cb = NULL;
8379 player->video_stream_cb_user_param = NULL;
8380 player->video_stream_prerolled = FALSE;
8382 player->audio_stream_cb = NULL;
8383 player->audio_stream_render_cb_ex = NULL;
8384 player->audio_stream_cb_user_param = NULL;
8385 player->audio_stream_sink_sync = false;
8387 player->video_stream_changed_cb = NULL;
8388 player->video_stream_changed_cb_user_param = NULL;
8390 player->audio_stream_changed_cb = NULL;
8391 player->audio_stream_changed_cb_user_param = NULL;
8393 player->sent_bos = FALSE;
8394 player->playback_rate = DEFAULT_PLAYBACK_RATE;
8396 player->seek_state = MMPLAYER_SEEK_NONE;
8398 player->total_bitrate = 0;
8399 player->total_maximum_bitrate = 0;
8401 player->not_found_demuxer = 0;
8403 player->last_position = 0;
8404 player->duration = 0;
8405 player->http_content_size = 0;
8406 player->not_supported_codec = MISSING_PLUGIN_NONE;
8407 player->can_support_codec = FOUND_PLUGIN_NONE;
8408 player->pending_seek.is_pending = FALSE;
8409 player->pending_seek.pos = 0;
8410 player->msg_posted = FALSE;
8411 player->has_many_types = FALSE;
8412 player->max_audio_channels = 0;
8413 player->video_share_api_delta = 0;
8414 player->video_share_clock_delta = 0;
8415 player->is_subtitle_force_drop = FALSE;
8416 player->play_subtitle = FALSE;
8417 player->adjust_subtitle_pos = 0;
8418 player->last_multiwin_status = FALSE;
8419 player->has_closed_caption = FALSE;
8420 player->set_mode.media_packet_video_stream = FALSE;
8421 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
8422 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
8424 player->set_mode.rich_audio = cur_mode;
8426 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
8427 player->bitrate[i] = 0;
8428 player->maximum_bitrate[i] = 0;
8431 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
8433 /* remove media stream cb(appsrc cb) */
8434 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
8435 player->media_stream_buffer_status_cb[i] = NULL;
8436 player->media_stream_seek_data_cb[i] = NULL;
8437 player->buffer_cb_user_param[i] = NULL;
8438 player->seek_cb_user_param[i] = NULL;
8440 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
8442 /* free memory related to audio effect */
8443 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
8445 if (player->adaptive_info.var_list) {
8446 g_list_free_full(player->adaptive_info.var_list, g_free);
8447 player->adaptive_info.var_list = NULL;
8450 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8451 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8452 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
8454 /* Reset video360 settings to their defaults in case if the pipeline is to be
8457 player->video360_metadata.is_spherical = -1;
8458 player->is_openal_plugin_used = FALSE;
8460 player->is_content_spherical = FALSE;
8461 player->is_video360_enabled = TRUE;
8462 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
8463 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
8464 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
8465 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
8466 player->video360_zoom = 1.0f;
8467 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
8468 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
8470 player->sound.rg_enable = false;
8472 __mmplayer_initialize_video_roi(player);
8477 __mmplayer_release_misc_post(mm_player_t* player)
8479 char *original_uri = NULL;
8482 /* player->pipeline is already released before. */
8484 MMPLAYER_RETURN_IF_FAIL(player);
8486 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
8488 /* clean found parsers */
8489 if (player->parsers) {
8490 GList *parsers = player->parsers;
8491 for (; parsers; parsers = g_list_next(parsers)) {
8492 gchar *name = parsers->data;
8493 MMPLAYER_FREEIF(name);
8495 g_list_free(player->parsers);
8496 player->parsers = NULL;
8499 /* clean found audio decoders */
8500 if (player->audio_decoders) {
8501 GList *a_dec = player->audio_decoders;
8502 for (; a_dec; a_dec = g_list_next(a_dec)) {
8503 gchar *name = a_dec->data;
8504 MMPLAYER_FREEIF(name);
8506 g_list_free(player->audio_decoders);
8507 player->audio_decoders = NULL;
8510 /* clean the uri list except original uri */
8511 if (player->uri_info.uri_list) {
8512 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
8514 if (player->attrs) {
8515 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
8516 LOGD("restore original uri = %s\n", original_uri);
8518 if (mmf_attrs_commit(player->attrs))
8519 LOGE("failed to commit the original uri.\n");
8522 GList *uri_list = player->uri_info.uri_list;
8523 for (; uri_list; uri_list = g_list_next(uri_list)) {
8524 gchar *uri = uri_list->data;
8525 MMPLAYER_FREEIF(uri);
8527 g_list_free(player->uri_info.uri_list);
8528 player->uri_info.uri_list = NULL;
8531 /* clear the audio stream buffer list */
8532 __mmplayer_audio_stream_clear_buffer(player, FALSE);
8534 /* clear the video stream bo list */
8535 __mmplayer_video_stream_destroy_bo_list(player);
8536 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8538 if (player->profile.input_mem.buf) {
8539 free(player->profile.input_mem.buf);
8540 player->profile.input_mem.buf = NULL;
8542 player->profile.input_mem.len = 0;
8543 player->profile.input_mem.offset = 0;
8545 player->uri_info.uri_idx = 0;
8549 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
8551 GstElement *element = NULL;
8554 LOGD("creating %s to plug\n", name);
8556 element = gst_element_factory_make(name, NULL);
8558 LOGE("failed to create queue\n");
8562 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
8563 LOGE("failed to set state READY to %s\n", name);
8564 gst_object_unref(element);
8568 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
8569 LOGE("failed to add %s\n", name);
8570 gst_object_unref(element);
8574 sinkpad = gst_element_get_static_pad(element, "sink");
8576 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
8577 LOGE("failed to link %s\n", name);
8578 gst_object_unref(sinkpad);
8579 gst_object_unref(element);
8583 LOGD("linked %s to pipeline successfully\n", name);
8585 gst_object_unref(sinkpad);
8591 __mmplayer_check_subtitle(mm_player_t* player)
8593 MMHandleType attrs = 0;
8594 char *subtitle_uri = NULL;
8598 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8600 /* get subtitle attribute */
8601 attrs = MMPLAYER_GET_ATTRS(player);
8605 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8606 if (!subtitle_uri || !strlen(subtitle_uri))
8609 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
8610 player->is_external_subtitle_present = TRUE;
8618 __mmplayer_can_extract_pcm(mm_player_t* player)
8620 MMHandleType attrs = 0;
8621 gboolean sound_extraction = FALSE;
8623 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8625 attrs = MMPLAYER_GET_ATTRS(player);
8627 LOGE("fail to get attributes.");
8631 /* get sound_extraction property */
8632 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
8634 if (!sound_extraction) {
8635 LOGD("checking pcm extraction mode : %d ", sound_extraction);
8643 __mmplayer_cancel_eos_timer(mm_player_t* player)
8645 MMPLAYER_RETURN_IF_FAIL(player);
8647 if (player->eos_timer) {
8648 LOGD("cancel eos timer");
8649 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8650 player->eos_timer = 0;
8657 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
8661 MMPLAYER_RETURN_IF_FAIL(player);
8662 MMPLAYER_RETURN_IF_FAIL(sink);
8664 player->sink_elements =
8665 g_list_append(player->sink_elements, sink);
8671 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
8675 MMPLAYER_RETURN_IF_FAIL(player);
8676 MMPLAYER_RETURN_IF_FAIL(sink);
8678 player->sink_elements =
8679 g_list_remove(player->sink_elements, sink);
8685 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
8686 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
8688 MMPlayerSignalItem* item = NULL;
8691 MMPLAYER_RETURN_IF_FAIL(player);
8693 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8694 LOGE("invalid signal type [%d]", type);
8698 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
8700 LOGE("cannot connect signal [%s]", signal);
8705 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8706 player->signals[type] = g_list_append(player->signals[type], item);
8712 /* NOTE : be careful with calling this api. please refer to below glib comment
8713 * glib comment : Note that there is a bug in GObject that makes this function much
8714 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8715 * will no longer be called, but, the signal handler is not currently disconnected.
8716 * If the instance is itself being freed at the same time than this doesn't matter,
8717 * since the signal will automatically be removed, but if instance persists,
8718 * then the signal handler will leak. You should not remove the signal yourself
8719 * because in a future versions of GObject, the handler will automatically be
8722 * It's possible to work around this problem in a way that will continue to work
8723 * with future versions of GObject by checking that the signal handler is still
8724 * connected before disconnected it:
8726 * if (g_signal_handler_is_connected(instance, id))
8727 * g_signal_handler_disconnect(instance, id);
8730 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
8732 GList* sig_list = NULL;
8733 MMPlayerSignalItem* item = NULL;
8737 MMPLAYER_RETURN_IF_FAIL(player);
8739 LOGD("release signals type : %d", type);
8741 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8742 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8743 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8744 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8745 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8746 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8750 sig_list = player->signals[type];
8752 for (; sig_list; sig_list = sig_list->next) {
8753 item = sig_list->data;
8755 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
8756 if (g_signal_handler_is_connected(item->obj, item->sig))
8757 g_signal_handler_disconnect(item->obj, item->sig);
8760 MMPLAYER_FREEIF(item);
8763 g_list_free(player->signals[type]);
8764 player->signals[type] = NULL;
8771 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
8773 mm_player_t* player = 0;
8774 int prev_display_surface_type = 0;
8775 void *prev_display_overlay = NULL;
8779 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8780 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
8782 player = MM_PLAYER_CAST(handle);
8784 /* check video sinkbin is created */
8785 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
8786 LOGE("Videosink is already created");
8787 return MM_ERROR_NONE;
8790 LOGD("videosink element is not yet ready");
8792 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8793 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8795 return MM_ERROR_INVALID_ARGUMENT;
8798 /* load previous attributes */
8799 if (player->attrs) {
8800 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8801 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
8802 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8803 if (prev_display_surface_type == surface_type) {
8804 LOGD("incoming display surface type is same as previous one, do nothing..");
8806 return MM_ERROR_NONE;
8809 LOGE("failed to load attributes");
8811 return MM_ERROR_PLAYER_INTERNAL;
8814 /* videobin is not created yet, so we just set attributes related to display surface */
8815 LOGD("store display attribute for given surface type(%d)", surface_type);
8816 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
8817 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
8818 if (mmf_attrs_commit(player->attrs)) {
8819 LOGE("failed to commit attribute");
8821 return MM_ERROR_PLAYER_INTERNAL;
8825 return MM_ERROR_NONE;
8828 /* Note : if silent is true, then subtitle would not be displayed. :*/
8829 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8831 mm_player_t* player = (mm_player_t*) hplayer;
8835 /* check player handle */
8836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8838 player->set_mode.subtitle_off = silent;
8840 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
8844 return MM_ERROR_NONE;
8847 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
8849 MMPlayerGstElement* mainbin = NULL;
8850 MMPlayerGstElement* textbin = NULL;
8851 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8852 GstState current_state = GST_STATE_VOID_PENDING;
8853 GstState element_state = GST_STATE_VOID_PENDING;
8854 GstState element_pending_state = GST_STATE_VOID_PENDING;
8856 GstEvent *event = NULL;
8857 int result = MM_ERROR_NONE;
8859 GstClock *curr_clock = NULL;
8860 GstClockTime base_time, start_time, curr_time;
8865 /* check player handle */
8866 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8868 player->pipeline->mainbin &&
8869 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8871 mainbin = player->pipeline->mainbin;
8872 textbin = player->pipeline->textbin;
8874 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8876 // sync clock with current pipeline
8877 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8878 curr_time = gst_clock_get_time(curr_clock);
8880 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8881 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8883 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8884 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8886 if (current_state > GST_STATE_READY) {
8887 // sync state with current pipeline
8888 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8889 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8890 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8892 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8893 if (GST_STATE_CHANGE_FAILURE == ret) {
8894 LOGE("fail to state change.\n");
8895 result = MM_ERROR_PLAYER_INTERNAL;
8900 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8901 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8904 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8905 gst_object_unref(curr_clock);
8908 // seek to current position
8909 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8910 result = MM_ERROR_PLAYER_INVALID_STATE;
8911 LOGE("gst_element_query_position failed, invalid state\n");
8915 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8916 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);
8918 __mmplayer_gst_send_event_to_sink(player, event);
8920 result = MM_ERROR_PLAYER_INTERNAL;
8921 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8925 /* sync state with current pipeline */
8926 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8927 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8928 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8930 return MM_ERROR_NONE;
8933 /* release text pipeline resource */
8934 player->textsink_linked = 0;
8936 /* release signal */
8937 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8939 /* release textbin with it's childs */
8940 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8941 MMPLAYER_FREEIF(player->pipeline->textbin);
8942 player->pipeline->textbin = NULL;
8944 /* release subtitle elem */
8945 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8946 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8952 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
8954 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8955 GstState current_state = GST_STATE_VOID_PENDING;
8957 MMHandleType attrs = 0;
8958 MMPlayerGstElement* mainbin = NULL;
8959 MMPlayerGstElement* textbin = NULL;
8961 gchar* subtitle_uri = NULL;
8962 int result = MM_ERROR_NONE;
8963 const gchar *charset = NULL;
8967 /* check player handle */
8968 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8970 player->pipeline->mainbin &&
8971 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8972 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8974 mainbin = player->pipeline->mainbin;
8975 textbin = player->pipeline->textbin;
8977 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8978 if (current_state < GST_STATE_READY) {
8979 result = MM_ERROR_PLAYER_INVALID_STATE;
8980 LOGE("Pipeline is not in proper state\n");
8984 attrs = MMPLAYER_GET_ATTRS(player);
8986 LOGE("cannot get content attribute\n");
8987 result = MM_ERROR_PLAYER_INTERNAL;
8991 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8992 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8993 LOGE("subtitle uri is not proper filepath\n");
8994 result = MM_ERROR_PLAYER_INVALID_URI;
8998 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8999 LOGE("failed to get storage info of subtitle path");
9000 result = MM_ERROR_PLAYER_INVALID_URI;
9004 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
9005 LOGD("new subtitle file path is [%s]\n", filepath);
9007 if (!strcmp(filepath, subtitle_uri)) {
9008 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
9011 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
9012 if (mmf_attrs_commit(player->attrs)) {
9013 LOGE("failed to commit.\n");
9018 //gst_pad_set_blocked_async(src-srcpad, TRUE)
9019 MMPLAYER_SUBTITLE_INFO_LOCK(player);
9020 player->subtitle_language_list = NULL;
9021 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
9023 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
9024 if (ret != GST_STATE_CHANGE_SUCCESS) {
9025 LOGE("failed to change state of textbin to READY");
9026 result = MM_ERROR_PLAYER_INTERNAL;
9030 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
9031 if (ret != GST_STATE_CHANGE_SUCCESS) {
9032 LOGE("failed to change state of subparse to READY");
9033 result = MM_ERROR_PLAYER_INTERNAL;
9037 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
9038 if (ret != GST_STATE_CHANGE_SUCCESS) {
9039 LOGE("failed to change state of filesrc to READY");
9040 result = MM_ERROR_PLAYER_INTERNAL;
9044 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
9046 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
9048 charset = util_get_charset(filepath);
9050 LOGD("detected charset is %s\n", charset);
9051 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
9054 result = _mmplayer_sync_subtitle_pipeline(player);
9061 /* API to switch between external subtitles */
9062 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
9064 int result = MM_ERROR_NONE;
9065 mm_player_t* player = (mm_player_t*)hplayer;
9070 /* check player handle */
9071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9073 /* filepath can be null in idle state */
9075 /* check file path */
9076 if ((path = strstr(filepath, "file://")))
9077 result = util_exist_file_path(path + 7);
9079 result = util_exist_file_path(filepath);
9081 if (result != MM_ERROR_NONE) {
9082 LOGE("invalid subtitle path 0x%X", result);
9083 return result; /* file not found or permission denied */
9087 if (!player->pipeline) {
9089 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
9090 if (mmf_attrs_commit(player->attrs)) {
9091 LOGE("failed to commit"); /* subtitle path will not be created */
9092 return MM_ERROR_PLAYER_INTERNAL;
9095 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
9096 /* check filepath */
9097 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
9099 if (!__mmplayer_check_subtitle(player)) {
9100 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
9101 if (mmf_attrs_commit(player->attrs)) {
9102 LOGE("failed to commit");
9103 return MM_ERROR_PLAYER_INTERNAL;
9106 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
9107 LOGE("fail to create text pipeline");
9108 return MM_ERROR_PLAYER_INTERNAL;
9111 result = _mmplayer_sync_subtitle_pipeline(player);
9113 result = __mmplayer_change_external_subtitle_language(player, filepath);
9116 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
9117 player->is_external_subtitle_added_now = TRUE;
9119 MMPLAYER_SUBTITLE_INFO_LOCK(player);
9120 if (!player->subtitle_language_list) {
9121 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
9122 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
9123 LOGW("subtitle language list is not updated yet");
9125 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
9133 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
9135 int result = MM_ERROR_NONE;
9136 gchar* change_pad_name = NULL;
9137 GstPad* sinkpad = NULL;
9138 MMPlayerGstElement* mainbin = NULL;
9139 enum MainElementID elemId = MMPLAYER_M_NUM;
9140 GstCaps* caps = NULL;
9141 gint total_track_num = 0;
9145 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
9146 MM_ERROR_PLAYER_NOT_INITIALIZED);
9148 LOGD("Change Track(%d) to %d\n", type, index);
9150 mainbin = player->pipeline->mainbin;
9152 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
9153 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
9154 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
9155 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
9157 /* Changing Video Track is not supported. */
9158 LOGE("Track Type Error\n");
9162 if (mainbin[elemId].gst == NULL) {
9163 result = MM_ERROR_PLAYER_NO_OP;
9164 LOGD("Req track doesn't exist\n");
9168 total_track_num = player->selector[type].total_track_num;
9169 if (total_track_num <= 0) {
9170 result = MM_ERROR_PLAYER_NO_OP;
9171 LOGD("Language list is not available \n");
9175 if ((index < 0) || (index >= total_track_num)) {
9176 result = MM_ERROR_INVALID_ARGUMENT;
9177 LOGD("Not a proper index : %d \n", index);
9181 /*To get the new pad from the selector*/
9182 change_pad_name = g_strdup_printf("sink_%u", index);
9183 if (change_pad_name == NULL) {
9184 result = MM_ERROR_PLAYER_INTERNAL;
9185 LOGD("Pad does not exists\n");
9189 LOGD("new active pad name: %s\n", change_pad_name);
9191 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
9192 if (sinkpad == NULL) {
9193 LOGD("sinkpad is NULL");
9194 result = MM_ERROR_PLAYER_INTERNAL;
9198 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
9199 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
9201 caps = gst_pad_get_current_caps(sinkpad);
9202 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9205 gst_object_unref(sinkpad);
9207 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
9208 __mmplayer_set_audio_attrs(player, caps);
9212 MMPLAYER_FREEIF(change_pad_name);
9216 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
9218 int result = MM_ERROR_NONE;
9219 mm_player_t* player = NULL;
9220 MMPlayerGstElement* mainbin = NULL;
9222 gint current_active_index = 0;
9224 GstState current_state = GST_STATE_VOID_PENDING;
9225 GstEvent* event = NULL;
9230 player = (mm_player_t*)hplayer;
9231 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9233 if (!player->pipeline) {
9234 LOGE("Track %d pre setting -> %d\n", type, index);
9236 player->selector[type].active_pad_index = index;
9240 mainbin = player->pipeline->mainbin;
9242 current_active_index = player->selector[type].active_pad_index;
9244 /*If index is same as running index no need to change the pad*/
9245 if (current_active_index == index)
9248 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
9249 result = MM_ERROR_PLAYER_INVALID_STATE;
9253 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
9254 if (current_state < GST_STATE_PAUSED) {
9255 result = MM_ERROR_PLAYER_INVALID_STATE;
9256 LOGW("Pipeline not in porper state\n");
9260 result = __mmplayer_change_selector_pad(player, type, index);
9261 if (result != MM_ERROR_NONE) {
9262 LOGE("change selector pad error\n");
9266 player->selector[type].active_pad_index = index;
9268 if (current_state == GST_STATE_PLAYING) {
9269 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);
9271 __mmplayer_gst_send_event_to_sink(player, event);
9273 result = MM_ERROR_PLAYER_INTERNAL;
9282 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
9284 mm_player_t* player = (mm_player_t*) hplayer;
9288 /* check player handle */
9289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9291 *silent = player->set_mode.subtitle_off;
9293 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
9297 return MM_ERROR_NONE;
9301 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
9303 mm_player_t* player = (mm_player_t*) hplayer;
9305 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9307 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
9308 MMPLAYER_PRINT_STATE(player);
9309 LOGE("wrong-state : can't set the download mode to parse");
9310 return MM_ERROR_PLAYER_INVALID_STATE;
9313 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
9314 player->video_hub_download_mode = mode;
9316 return MM_ERROR_NONE;
9320 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
9322 mm_player_t* player = (mm_player_t*) hplayer;
9324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9326 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
9327 player->sync_handler = enable;
9329 return MM_ERROR_NONE;
9333 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
9334 gint64 video_time, gint64 media_clock, gint64 audio_time)
9336 mm_player_t* player = (mm_player_t*) hplayer;
9337 MMPlayerGstElement* mainbin = NULL;
9338 GstClockTime start_time_audio = 0, start_time_video = 0;
9339 GstClockTimeDiff base_time = 0, new_base_time = 0;
9340 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9341 gint64 api_delta = 0;
9342 gint64 position = 0, position_delta = 0;
9343 gint64 adj_base_time = 0;
9344 GstClock *curr_clock = NULL;
9345 GstClockTime curr_time = 0;
9346 gboolean query_ret = TRUE;
9347 int result = MM_ERROR_NONE;
9351 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9352 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
9353 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
9355 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
9356 clock, clock_delta, video_time, media_clock, audio_time); */
9358 if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
9359 LOGD("skip setting master clock. %lld", video_time);
9363 mainbin = player->pipeline->mainbin;
9365 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
9366 curr_time = gst_clock_get_time(curr_clock);
9368 current_state = MMPLAYER_CURRENT_STATE(player);
9370 if (current_state == MM_PLAYER_STATE_PLAYING)
9371 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
9373 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
9375 position = player->last_position;
9376 LOGD("query fail. %"G_GINT64_FORMAT, position);
9379 clock *= GST_USECOND;
9380 clock_delta *= GST_USECOND;
9382 api_delta = clock - curr_time;
9383 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
9384 player->video_share_api_delta = api_delta;
9386 clock_delta += (api_delta - player->video_share_api_delta);
9388 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
9389 player->video_share_clock_delta = (gint64)clock_delta;
9391 position_delta = (position/GST_USECOND) - video_time;
9392 position_delta *= GST_USECOND;
9394 adj_base_time = position_delta;
9395 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
9398 gint64 new_play_time = 0;
9399 gint64 network_delay = 0;
9401 video_time *= GST_USECOND;
9403 network_delay = clock_delta - player->video_share_clock_delta;
9404 new_play_time = video_time + network_delay;
9406 adj_base_time = position - new_play_time;
9408 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
9409 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
9410 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
9413 /* Adjust Current Stream Time with base_time of sink
9414 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
9415 * 2. Set new base time
9416 * if adj_base_time is positive value, the stream time will be decreased.
9417 * 3. If seek event is occurred, the start time will be reset. */
9418 if ((player->pipeline->audiobin) &&
9419 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
9420 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
9422 if (start_time_audio != GST_CLOCK_TIME_NONE) {
9423 LOGD("audio sink : gst_element_set_start_time -> NONE");
9424 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
9427 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
9430 if ((player->pipeline->videobin) &&
9431 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
9432 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
9434 if (start_time_video != GST_CLOCK_TIME_NONE) {
9435 LOGD("video sink : gst_element_set_start_time -> NONE");
9436 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
9439 // if videobin exist, get base_time from videobin.
9440 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
9443 new_base_time = base_time + adj_base_time;
9445 if ((player->pipeline->audiobin) &&
9446 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
9447 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
9449 if ((player->pipeline->videobin) &&
9450 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
9451 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
9460 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
9462 mm_player_t* player = (mm_player_t*) hplayer;
9463 MMPlayerGstElement* mainbin = NULL;
9464 GstClock *curr_clock = NULL;
9465 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
9466 gint64 position = 0;
9467 gboolean query_ret = TRUE;
9471 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
9472 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
9473 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
9475 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
9476 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
9477 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
9479 mainbin = player->pipeline->mainbin;
9481 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
9483 current_state = MMPLAYER_CURRENT_STATE(player);
9485 if (current_state != MM_PLAYER_STATE_PAUSED)
9486 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
9488 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
9490 position = player->last_position;
9492 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
9494 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
9497 gst_object_unref(curr_clock);
9501 return MM_ERROR_NONE;
9505 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
9507 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9508 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
9510 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
9511 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
9515 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
9516 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
9517 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
9518 mm_player_dump_t *dump_s;
9519 dump_s = g_malloc(sizeof(mm_player_dump_t));
9521 if (dump_s == NULL) {
9522 LOGE("malloc fail");
9526 dump_s->dump_element_file = NULL;
9527 dump_s->dump_pad = NULL;
9528 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
9530 if (dump_s->dump_pad) {
9531 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
9532 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]);
9533 dump_s->dump_element_file = fopen(dump_file_name, "w+");
9534 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);
9535 /* add list for removed buffer probe and close FILE */
9536 player->dump_list = g_list_append(player->dump_list, dump_s);
9537 LOGD("%s sink pad added buffer probe for dump", factory_name);
9542 LOGE("failed to get %s sink pad added", factory_name);
9551 static GstPadProbeReturn
9552 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
9554 FILE *dump_data = (FILE *) u_data;
9556 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
9557 GstMapInfo probe_info = GST_MAP_INFO_INIT;
9559 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
9561 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
9563 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
9565 fwrite(probe_info.data, 1, probe_info.size , dump_data);
9567 return GST_PAD_PROBE_OK;
9571 __mmplayer_release_dump_list(GList *dump_list)
9574 GList *d_list = dump_list;
9575 for (; d_list; d_list = g_list_next(d_list)) {
9576 mm_player_dump_t *dump_s = d_list->data;
9577 if (dump_s->dump_pad) {
9578 if (dump_s->probe_handle_id)
9579 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
9581 if (dump_s->dump_element_file) {
9582 fclose(dump_s->dump_element_file);
9583 dump_s->dump_element_file = NULL;
9585 MMPLAYER_FREEIF(dump_s);
9587 g_list_free(dump_list);
9593 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
9595 mm_player_t* player = (mm_player_t*) hplayer;
9599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9600 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
9602 *exist = player->has_closed_caption;
9606 return MM_ERROR_NONE;
9609 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
9613 // LOGD("unref internal gst buffer %p", buffer);
9614 gst_buffer_unref((GstBuffer *)buffer);
9621 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
9623 mm_player_t* player = (mm_player_t*) hplayer;
9627 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9629 player->pcm_samplerate = samplerate;
9630 player->pcm_channel = channel;
9633 return MM_ERROR_NONE;
9636 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
9638 mm_player_t* player = (mm_player_t*) hplayer;
9642 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9643 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
9645 if (MMPLAYER_IS_HTTP_PD(player))
9646 *timeout = player->ini.live_state_change_timeout*2;
9647 else if (MMPLAYER_IS_STREAMING(player))
9648 *timeout = player->ini.live_state_change_timeout;
9650 *timeout = player->ini.localplayback_state_change_timeout;
9652 LOGD("timeout = %d\n", *timeout);
9655 return MM_ERROR_NONE;
9658 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
9660 mm_player_t* player = (mm_player_t*) hplayer;
9664 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9665 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
9667 *num = player->video_num_buffers;
9668 *extra_num = player->video_extra_num_buffers;
9670 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
9673 return MM_ERROR_NONE;
9677 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
9681 MMPLAYER_RETURN_IF_FAIL(player);
9683 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
9685 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
9686 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
9687 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
9688 player->storage_info[i].id = -1;
9689 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
9691 if (path_type != MMPLAYER_PATH_MAX)
9699 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
9701 int ret = MM_ERROR_NONE;
9702 mm_player_t* player = (mm_player_t*)hplayer;
9703 MMMessageParamType msg_param = {0, };
9706 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9708 LOGW("state changed storage %d:%d", id, state);
9710 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
9711 return MM_ERROR_NONE;
9713 /* FIXME: text path should be handled seperately. */
9714 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
9715 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
9716 LOGW("external storage is removed");
9718 if (player->msg_posted == FALSE) {
9719 memset(&msg_param, 0, sizeof(MMMessageParamType));
9720 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
9721 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
9722 player->msg_posted = TRUE;
9725 /* unrealize the player */
9726 ret = _mmplayer_unrealize(hplayer);
9727 if (ret != MM_ERROR_NONE)
9728 LOGE("failed to unrealize");
9735 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
9737 int ret = MM_ERROR_NONE;
9738 mm_player_t* player = (mm_player_t*) hplayer;
9739 int idx = 0, total = 0;
9740 gchar *result = NULL, *tmp = NULL;
9743 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9744 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
9746 total = *num = g_list_length(player->adaptive_info.var_list);
9748 LOGW("There is no stream variant info.");
9752 result = g_strdup("");
9753 for (idx = 0 ; idx < total ; idx++) {
9754 VariantData *v_data = NULL;
9755 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9758 gchar data[64] = {0};
9759 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9761 tmp = g_strconcat(result, data, NULL);
9765 LOGW("There is no variant data in %d", idx);
9770 *var_info = (char *)result;
9772 LOGD("variant info %d:%s", *num, *var_info);
9777 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9779 int ret = MM_ERROR_NONE;
9780 mm_player_t* player = (mm_player_t*) hplayer;
9783 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9785 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9787 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9788 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9789 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9791 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9792 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9793 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9794 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9796 /* FIXME: seek to current position for applying new variant limitation */
9804 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9806 int ret = MM_ERROR_NONE;
9807 mm_player_t* player = (mm_player_t*) hplayer;
9810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9811 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9813 *bandwidth = player->adaptive_info.limit.bandwidth;
9814 *width = player->adaptive_info.limit.width;
9815 *height = player->adaptive_info.limit.height;
9817 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9823 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
9825 int ret = MM_ERROR_NONE;
9826 mm_player_t* player = (mm_player_t*) hplayer;
9829 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9831 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
9832 LOGW("buffer_ms will not be applied.");
9835 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
9837 if (player->streamer == NULL) {
9838 player->streamer = __mm_player_streaming_create();
9839 __mm_player_streaming_initialize(player->streamer);
9843 player->streamer->buffering_req.prebuffer_time = buffer_ms;
9845 if (rebuffer_ms >= 0)
9846 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
9853 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
9855 int ret = MM_ERROR_NONE;
9856 mm_player_t* player = (mm_player_t*) hplayer;
9859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9860 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9862 if (player->streamer == NULL) {
9863 player->streamer = __mm_player_streaming_create();
9864 __mm_player_streaming_initialize(player->streamer);
9867 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
9868 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9870 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
9876 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
9878 #define IDX_FIRST_SW_CODEC 0
9879 mm_player_t* player = (mm_player_t*) hplayer;
9880 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
9881 MMHandleType attrs = 0;
9884 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9886 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
9887 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
9888 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
9890 switch (stream_type) {
9891 case MM_PLAYER_STREAM_TYPE_AUDIO:
9892 /* to support audio codec selection, codec info have to be added in ini file as below.
9893 audio codec element hw = xxxx
9894 audio codec element sw = avdec */
9895 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
9896 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
9897 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
9898 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
9899 LOGE("There is no audio codec info for codec_type %d", codec_type);
9900 return MM_ERROR_PLAYER_NO_OP;
9903 case MM_PLAYER_STREAM_TYPE_VIDEO:
9904 /* to support video codec selection, codec info have to be added in ini file as below.
9905 video codec element hw = omx
9906 video codec element sw = avdec */
9907 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
9908 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
9909 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
9910 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
9911 LOGE("There is no video codec info for codec_type %d", codec_type);
9912 return MM_ERROR_PLAYER_NO_OP;
9916 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9917 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9921 LOGD("update %s codec_type to %d", attr_name, codec_type);
9923 attrs = MMPLAYER_GET_ATTRS(player);
9924 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
9926 if (mmf_attrs_commit(player->attrs)) {
9927 LOGE("failed to commit codec_type attributes");
9928 return MM_ERROR_PLAYER_INTERNAL;
9932 return MM_ERROR_NONE;
9936 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9938 mm_player_t* player = (mm_player_t*) hplayer;
9939 GstElement* rg_vol_element = NULL;
9943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9945 player->sound.rg_enable = enabled;
9947 /* just hold rgvolume enable value if pipeline is not ready */
9948 if (!player->pipeline || !player->pipeline->audiobin) {
9949 LOGD("pipeline is not ready. holding rgvolume enable value\n");
9950 return MM_ERROR_NONE;
9953 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9955 if (!rg_vol_element) {
9956 LOGD("rgvolume element is not created");
9957 return MM_ERROR_PLAYER_INTERNAL;
9961 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9963 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9967 return MM_ERROR_NONE;
9971 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9973 mm_player_t* player = (mm_player_t*) hplayer;
9974 GstElement* rg_vol_element = NULL;
9975 gboolean enable = FALSE;
9979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9980 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9982 /* just hold enable_rg value if pipeline is not ready */
9983 if (!player->pipeline || !player->pipeline->audiobin) {
9984 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
9985 *enabled = player->sound.rg_enable;
9986 return MM_ERROR_NONE;
9989 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9991 if (!rg_vol_element) {
9992 LOGD("rgvolume element is not created");
9993 return MM_ERROR_PLAYER_INTERNAL;
9996 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
10001 return MM_ERROR_NONE;
10005 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
10007 mm_player_t* player = (mm_player_t*) hplayer;
10008 MMHandleType attrs = 0;
10009 void *handle = NULL;
10010 int ret = MM_ERROR_NONE;
10014 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10016 attrs = MMPLAYER_GET_ATTRS(player);
10017 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
10019 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
10021 LOGE("Display handle is NULL, after setting window handle, set video roi area");
10022 return MM_ERROR_PLAYER_INTERNAL;
10025 player->video_roi.scale_x = scale_x;
10026 player->video_roi.scale_y = scale_y;
10027 player->video_roi.scale_width = scale_width;
10028 player->video_roi.scale_height = scale_height;
10030 /* check video sinkbin is created */
10031 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
10032 return MM_ERROR_NONE;
10034 if (!gst_video_overlay_set_video_roi_area(
10035 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
10036 scale_x, scale_y, scale_width, scale_height))
10037 ret = MM_ERROR_PLAYER_INTERNAL;
10039 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
10040 scale_x, scale_y, scale_width, scale_height);
10048 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
10050 mm_player_t* player = (mm_player_t*) hplayer;
10051 int ret = MM_ERROR_NONE;
10055 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10056 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
10058 *scale_x = player->video_roi.scale_x;
10059 *scale_y = player->video_roi.scale_y;
10060 *scale_width = player->video_roi.scale_width;
10061 *scale_height = player->video_roi.scale_height;
10063 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
10064 *scale_x, *scale_y, *scale_width, *scale_height);