4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/app/gstappsrc.h>
31 #include <gst/video/videooverlay.h>
32 #include <gst/audio/gstaudiobasesink.h>
42 #include <mm_attrs_private.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
93 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
94 (player->ini.http_use_file_buffer) && \
95 (player->http_file_buffering_path) && \
96 (strlen(player->http_file_buffering_path) > 0))
98 #define PLAYER_DISPLAY_MODE_DST_ROI 5
100 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
103 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
105 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
106 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
107 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
108 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
110 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
111 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
113 /*---------------------------------------------------------------------------
114 | LOCAL CONSTANT DEFINITIONS: |
115 ---------------------------------------------------------------------------*/
117 /*---------------------------------------------------------------------------
118 | LOCAL DATA TYPE DEFINITIONS: |
119 ---------------------------------------------------------------------------*/
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
135 static int __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int __mmplayer_gst_create_audio_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
139 static int __mmplayer_gst_element_link_bucket(GList* element_bucket);
141 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
142 static void __mmplayer_gst_decode_pad_added(GstElement* elem, GstPad* pad, gpointer data);
143 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
144 static void __mmplayer_gst_decode_callback(GstElement *decodebin, GstPad *pad, gpointer data);
145 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
146 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
147 static gint __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad, GstCaps * caps, GstElementFactory* factory, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void __mmplayer_gst_element_added(GstElement* bin, GstElement* element, gpointer data);
151 static GstElement * __mmplayer_create_decodebin(mm_player_t* player);
152 static gboolean __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps);
153 static void __mmplayer_typefind_have_type(GstElement *tf, guint probability, GstCaps *caps, gpointer data);
154 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
155 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
156 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
157 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
159 static void __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data);
160 static void __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data);
161 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static void __mmplayer_release_misc(mm_player_t* player);
163 static void __mmplayer_release_misc_post(mm_player_t* player);
164 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
165 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
166 static GstPadProbeReturn __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
168 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
169 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
172 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
173 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
174 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
175 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
176 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
177 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
178 static gpointer __mmplayer_next_play_thread(gpointer data);
179 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
180 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
181 static void __mmplayer_release_dump_list(GList *dump_list);
182 static int __gst_realize(mm_player_t* player);
183 static int __gst_unrealize(mm_player_t* player);
184 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
185 static int __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
186 static gboolean __mmplayer_can_extract_pcm(mm_player_t* player);
189 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
190 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
191 static int __mmplayer_start_streaming_ext(mm_player_t *player);
192 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
193 static int __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay);
194 static gboolean __mmplayer_verify_next_play_path(mm_player_t *player);
195 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
196 static void __mmplayer_check_pipeline(mm_player_t* player);
197 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
198 static void __mmplayer_deactivate_old_path(mm_player_t *player);
199 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name);
200 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
201 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
202 static void __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data);
203 static void __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data);
204 static void __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data);
205 static void __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data);
206 static void __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data);
207 static gboolean __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data);
208 static gboolean __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data);
209 static gboolean __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data);
210 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
211 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
212 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
213 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
215 /*===========================================================================================
217 | FUNCTION DEFINITIONS |
219 ========================================================================================== */
223 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
227 count = gst_tag_list_get_tag_size(list, tag);
229 LOGD("count = %d", count);
231 for (i = 0; i < count; i++) {
234 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
235 if (!gst_tag_list_get_string_index(list, tag, i, &str))
236 g_assert_not_reached();
238 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
241 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
243 g_print(" : %s\n", str);
250 /* This function should be called after the pipeline goes PAUSED or higher
253 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
255 static gboolean has_duration = FALSE;
256 static gboolean has_video_attrs = FALSE;
257 static gboolean has_audio_attrs = FALSE;
258 static gboolean has_bitrate = FALSE;
259 gboolean missing_only = FALSE;
260 gboolean all = FALSE;
262 GstStructure* p = NULL;
263 MMHandleType attrs = 0;
269 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
271 /* check player state here */
272 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
273 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
274 /* give warning now only */
275 LOGW("be careful. content attributes may not available in this state ");
278 /* get content attribute first */
279 attrs = MMPLAYER_GET_ATTRS(player);
281 LOGE("cannot get content attribute");
285 /* get update flag */
287 if (flag & ATTR_MISSING_ONLY) {
289 LOGD("updating missed attr only");
292 if (flag & ATTR_ALL) {
294 has_duration = FALSE;
295 has_video_attrs = FALSE;
296 has_audio_attrs = FALSE;
299 LOGD("updating all attrs");
302 if (missing_only && all) {
303 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
304 missing_only = FALSE;
307 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all) {
308 LOGD("try to update duration");
309 has_duration = FALSE;
311 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
312 player->duration = dur_nsec;
313 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
317 if (player->duration < 0) {
318 LOGW("duration is Non-Initialized !!!");
319 player->duration = 0;
322 /* update streaming service type */
323 player->streaming_type = __mmplayer_get_stream_service_type(player);
325 /* check duration is OK */
326 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
327 /* FIXIT : find another way to get duration here. */
328 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
332 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all) {
333 /* update audio params
334 NOTE : We need original audio params and it can be only obtained from src pad of audio
335 decoder. Below code only valid when we are not using 'resampler' just before
338 LOGD("try to update audio attrs");
339 has_audio_attrs = FALSE;
341 if (player->pipeline->audiobin &&
342 player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
343 GstCaps *caps_a = NULL;
345 gint samplerate = 0, channels = 0;
347 pad = gst_element_get_static_pad(
348 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
351 caps_a = gst_pad_get_current_caps(pad);
354 p = gst_caps_get_structure(caps_a, 0);
356 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
358 gst_structure_get_int(p, "rate", &samplerate);
359 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
361 gst_structure_get_int(p, "channels", &channels);
362 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
364 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
366 gst_caps_unref(caps_a);
369 has_audio_attrs = TRUE;
371 LOGW("not ready to get audio caps");
373 gst_object_unref(pad);
375 LOGW("failed to get pad from audiosink");
379 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all) {
380 LOGD("try to update video attrs");
381 has_video_attrs = FALSE;
383 if (player->pipeline->videobin &&
384 player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
385 GstCaps *caps_v = NULL;
390 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
392 caps_v = gst_pad_get_current_caps(pad);
394 /* Use v_stream_caps, if fail to get video_sink sink pad*/
395 if (!caps_v && player->v_stream_caps) {
396 caps_v = player->v_stream_caps;
397 gst_caps_ref(caps_v);
401 p = gst_caps_get_structure(caps_v, 0);
402 gst_structure_get_int(p, "width", &width);
403 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
405 gst_structure_get_int(p, "height", &height);
406 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
408 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
410 SECURE_LOGD("width : %d height : %d", width, height);
412 gst_caps_unref(caps_v);
416 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
417 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
420 has_video_attrs = TRUE;
422 LOGD("no negitiated caps from videosink");
423 gst_object_unref(pad);
426 LOGD("no videosink sink pad");
432 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all) {
435 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
436 if (player->duration) {
437 guint64 data_size = 0;
439 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
440 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
442 if (stat(path, &sb) == 0)
443 data_size = (guint64)sb.st_size;
444 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
445 data_size = player->http_content_size;
447 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
451 guint64 msec_dur = 0;
453 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
455 bitrate = data_size * 8 * 1000 / msec_dur;
456 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
457 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
461 LOGD("player duration is less than 0");
465 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
466 if (player->total_bitrate) {
467 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
475 if (mmf_attrs_commit(attrs)) {
476 LOGE("failed to update attributes\n");
485 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
487 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
491 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
493 player->pipeline->mainbin &&
494 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
495 STREAMING_SERVICE_NONE);
497 /* streaming service type if streaming */
498 if (!MMPLAYER_IS_STREAMING(player))
499 return STREAMING_SERVICE_NONE;
501 if (MMPLAYER_IS_HTTP_STREAMING(player))
502 streaming_type = (player->duration == 0) ?
503 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
505 switch (streaming_type) {
506 case STREAMING_SERVICE_LIVE:
507 LOGD("it's live streaming");
509 case STREAMING_SERVICE_VOD:
510 LOGD("it's vod streaming");
513 LOGE("should not get here");
519 return streaming_type;
523 /* this function sets the player state and also report
524 * it to applicaton by calling callback function
527 __mmplayer_set_state(mm_player_t* player, int state)
529 MMMessageParamType msg = {0, };
530 gboolean post_bos = FALSE;
532 MMPLAYER_RETURN_IF_FAIL(player);
534 if (MMPLAYER_CURRENT_STATE(player) == state) {
535 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
536 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
540 /* update player states */
541 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
542 MMPLAYER_CURRENT_STATE(player) = state;
544 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
545 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
548 MMPLAYER_PRINT_STATE(player);
550 switch (MMPLAYER_CURRENT_STATE(player)) {
551 case MM_PLAYER_STATE_NULL:
552 case MM_PLAYER_STATE_READY:
555 case MM_PLAYER_STATE_PAUSED:
557 if (!player->sent_bos) {
558 /* rtsp case, get content attrs by GstMessage */
559 if (!MMPLAYER_IS_RTSP_STREAMING(player)) {
560 /* it's first time to update all content attrs. */
561 __mmplayer_update_content_attrs(player, ATTR_ALL);
565 /* add audio callback probe if condition is satisfied */
566 if (!player->audio_cb_probe_id && player->set_mode.pcm_extraction && !player->audio_stream_render_cb_ex)
567 __mmplayer_configure_audio_callback(player);
569 /* FIXIT : handle return value */
573 case MM_PLAYER_STATE_PLAYING:
575 /* try to get content metadata */
576 if (!player->sent_bos) {
577 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
578 * c-api since c-api doesn't use _start() anymore. It may not work propery with
579 * legacy mmfw-player api */
580 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
583 if ((player->cmd == MMPLAYER_COMMAND_START) || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
584 if (!player->sent_bos)
585 __mmplayer_handle_missed_plugin(player);
588 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
589 /* initialize because auto resume is done well. */
590 player->resumed_by_rewind = FALSE;
591 player->playback_rate = 1.0;
594 if (!player->sent_bos) {
595 /* check audio codec field is set or not
596 * we can get it from typefinder or codec's caps.
598 gchar *audio_codec = NULL;
599 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
601 /* The codec format can't be sent for audio only case like amr, mid etc.
602 * Because, parser don't make related TAG.
603 * So, if it's not set yet, fill it with found data.
606 if (g_strrstr(player->type, "audio/midi"))
607 audio_codec = g_strdup("MIDI");
608 else if (g_strrstr(player->type, "audio/x-amr"))
609 audio_codec = g_strdup("AMR");
610 else if (g_strrstr(player->type, "audio/mpeg") && !g_strrstr(player->type, "mpegversion= (int)1"))
611 audio_codec = g_strdup("AAC");
613 audio_codec = g_strdup("unknown");
614 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
616 MMPLAYER_FREEIF(audio_codec);
617 if (mmf_attrs_commit(player->attrs))
618 LOGE("failed to update attributes\n");
620 LOGD("set audio codec type with caps\n");
628 case MM_PLAYER_STATE_NONE:
630 LOGW("invalid target state, there is nothing to do.\n");
635 /* post message to application */
636 if (MMPLAYER_TARGET_STATE(player) == state) {
637 /* fill the message with state of player */
638 msg.union_type = MM_MSG_UNION_STATE;
639 msg.state.previous = MMPLAYER_PREV_STATE(player);
640 msg.state.current = MMPLAYER_CURRENT_STATE(player);
642 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
644 /* state changed by resource callback */
645 if (player->interrupted_by_resource) {
646 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, NULL);
647 } else { /* state changed by usecase */
648 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
651 LOGD("intermediate state, do nothing.\n");
652 MMPLAYER_PRINT_STATE(player);
657 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
658 player->sent_bos = TRUE;
665 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
667 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
668 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
672 //LOGD("incomming command : %d \n", command);
674 current_state = MMPLAYER_CURRENT_STATE(player);
675 pending_state = MMPLAYER_PENDING_STATE(player);
677 MMPLAYER_PRINT_STATE(player);
680 case MMPLAYER_COMMAND_CREATE:
682 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
684 if (current_state == MM_PLAYER_STATE_NULL ||
685 current_state == MM_PLAYER_STATE_READY ||
686 current_state == MM_PLAYER_STATE_PAUSED ||
687 current_state == MM_PLAYER_STATE_PLAYING)
692 case MMPLAYER_COMMAND_DESTROY:
694 /* destroy can called anytime */
696 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
700 case MMPLAYER_COMMAND_REALIZE:
702 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
704 if (pending_state != MM_PLAYER_STATE_NONE) {
707 /* need ready state to realize */
708 if (current_state == MM_PLAYER_STATE_READY)
711 if (current_state != MM_PLAYER_STATE_NULL)
717 case MMPLAYER_COMMAND_UNREALIZE:
719 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
721 if (current_state == MM_PLAYER_STATE_NULL)
726 case MMPLAYER_COMMAND_START:
728 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
730 if (pending_state == MM_PLAYER_STATE_NONE) {
731 if (current_state == MM_PLAYER_STATE_PLAYING)
733 else if (current_state != MM_PLAYER_STATE_READY &&
734 current_state != MM_PLAYER_STATE_PAUSED)
736 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
738 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
739 LOGD("player is going to paused state, just change the pending state as playing");
745 case MMPLAYER_COMMAND_STOP:
747 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
749 if (current_state == MM_PLAYER_STATE_READY)
752 /* need playing/paused state to stop */
753 if (current_state != MM_PLAYER_STATE_PLAYING &&
754 current_state != MM_PLAYER_STATE_PAUSED)
759 case MMPLAYER_COMMAND_PAUSE:
761 if (MMPLAYER_IS_LIVE_STREAMING(player))
764 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
765 goto NOT_COMPLETED_SEEK;
767 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
769 if (pending_state == MM_PLAYER_STATE_NONE) {
770 if (current_state == MM_PLAYER_STATE_PAUSED)
772 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
774 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
776 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
777 if (current_state == MM_PLAYER_STATE_PAUSED)
778 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
785 case MMPLAYER_COMMAND_RESUME:
787 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
788 goto NOT_COMPLETED_SEEK;
790 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
792 if (pending_state == MM_PLAYER_STATE_NONE) {
793 if (current_state == MM_PLAYER_STATE_PLAYING)
795 else if (current_state != MM_PLAYER_STATE_PAUSED)
797 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
799 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
800 LOGD("player is going to paused state, just change the pending state as playing");
809 player->cmd = command;
811 return MM_ERROR_NONE;
814 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
815 MMPLAYER_STATE_GET_NAME(current_state), command);
816 return MM_ERROR_PLAYER_INVALID_STATE;
819 LOGW("not completed seek");
820 return MM_ERROR_PLAYER_DOING_SEEK;
823 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
824 return MM_ERROR_PLAYER_NO_OP;
827 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
828 return MM_ERROR_PLAYER_NO_OP;
831 static gpointer __mmplayer_next_play_thread(gpointer data)
833 mm_player_t* player = (mm_player_t*) data;
834 MMPlayerGstElement *mainbin = NULL;
836 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
838 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
839 while (!player->next_play_thread_exit) {
840 LOGD("next play thread started. waiting for signal.\n");
841 MMPLAYER_NEXT_PLAY_THREAD_WAIT(player);
843 LOGD("reconfigure pipeline for gapless play.\n");
845 if (player->next_play_thread_exit) {
846 if (player->gapless.reconfigure) {
847 player->gapless.reconfigure = false;
848 MMPLAYER_PLAYBACK_UNLOCK(player);
850 LOGD("exiting gapless play thread\n");
854 mainbin = player->pipeline->mainbin;
856 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
857 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
858 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
859 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
860 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
862 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
864 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
870 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
872 GSource *source = NULL;
876 source = g_main_context_find_source_by_id(context, source_id);
878 if (source != NULL) {
879 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
880 g_source_destroy(source);
886 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
888 mm_player_t* player = (mm_player_t*)hplayer;
889 GstMessage *msg = NULL;
890 GQueue *queue = NULL;
893 MMPLAYER_RETURN_IF_FAIL(player);
895 /* disconnecting bus watch */
896 if (player->bus_watcher)
897 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
898 player->bus_watcher = 0;
900 /* destroy the gst bus msg thread */
901 if (player->bus_msg_thread) {
902 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
903 player->bus_msg_thread_exit = TRUE;
904 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
905 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
907 LOGD("gst bus msg thread exit.");
908 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
909 player->bus_msg_thread = NULL;
911 g_mutex_clear(&player->bus_msg_thread_mutex);
912 g_cond_clear(&player->bus_msg_thread_cond);
915 g_mutex_lock(&player->bus_msg_q_lock);
916 queue = player->bus_msg_q;
917 while (!g_queue_is_empty(queue)) {
918 msg = (GstMessage *)g_queue_pop_head(queue);
919 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
920 gst_message_unref(msg);
922 g_mutex_unlock(&player->bus_msg_q_lock);
927 gboolean __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data)
929 mm_player_t *player = (mm_player_t *) data;
931 g_return_val_if_fail(player, FALSE);
932 g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
934 gst_message_ref(msg);
936 g_mutex_lock(&player->bus_msg_q_lock);
937 g_queue_push_tail(player->bus_msg_q, msg);
938 g_mutex_unlock(&player->bus_msg_q_lock);
940 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
941 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
942 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
946 static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
948 mm_player_t *player = (mm_player_t*)(data);
949 GstMessage *msg = NULL;
953 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
955 player->pipeline->mainbin &&
956 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
959 bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
961 LOGE("cannot get BUS from the pipeline");
965 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
967 LOGD("[handle: %p] gst bus msg thread will be started.", player);
968 while (!player->bus_msg_thread_exit) {
969 g_mutex_lock(&player->bus_msg_q_lock);
970 msg = g_queue_pop_head(player->bus_msg_q);
971 g_mutex_unlock(&player->bus_msg_q_lock);
973 MMPLAYER_BUS_MSG_THREAD_WAIT(player);
976 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
977 /* handle the gst msg */
978 __mmplayer_gst_bus_msg_callback(msg, player);
979 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
980 gst_message_unref(msg);
983 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
984 gst_object_unref(GST_OBJECT(bus));
991 __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data)
993 mm_player_t* player = (mm_player_t*) data;
997 /* NOTE : we can remove fakesink here if there's no rtp_dynamic_pad. because whenever
998 * we connect autoplugging element to the pad which is just added to rtspsrc, we increase
999 * num_dynamic_pad. and this is no-more-pad situation which means no more pad will be added.
1000 * So we can say this. if num_dynamic_pad is zero, it must be one of followings
1002 * [1] audio and video will be dumped with filesink.
1003 * [2] autoplugging is done by just using pad caps.
1004 * [3] typefinding has happend in audio but audiosink is created already before no-more-pad signal
1005 * and the video will be dumped via filesink.
1007 if (player->num_dynamic_pad == 0) {
1008 LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now\n");
1010 if (!__mmplayer_gst_remove_fakesink(player,
1011 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK]))
1012 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
1013 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
1014 * source element are not same. To overcome this situation, this function will called
1015 * several places and several times. Therefore, this is not an error case.
1020 /* create dot before error-return. for debugging */
1021 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-no-more-pad");
1023 player->no_more_pad = TRUE;
1029 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
1031 GstElement* parent = NULL;
1033 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1035 /* if we have no fakesink. this meas we are using decodebin which doesn'
1036 t need to add extra fakesink */
1037 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
1040 MMPLAYER_FSINK_LOCK(player);
1045 /* get parent of fakesink */
1046 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
1048 LOGD("fakesink already removed\n");
1052 gst_element_set_locked_state(fakesink->gst, TRUE);
1054 /* setting the state to NULL never returns async
1055 * so no need to wait for completion of state transiton
1057 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
1058 LOGE("fakesink state change failure!\n");
1059 /* FIXIT : should I return here? or try to proceed to next? */
1062 /* remove fakesink from it's parent */
1063 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
1064 LOGE("failed to remove fakesink\n");
1066 gst_object_unref(parent);
1071 gst_object_unref(parent);
1073 LOGD("state-holder removed\n");
1075 gst_element_set_locked_state(fakesink->gst, FALSE);
1077 MMPLAYER_FSINK_UNLOCK(player);
1082 gst_element_set_locked_state(fakesink->gst, FALSE);
1084 MMPLAYER_FSINK_UNLOCK(player);
1090 __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data)
1092 GstPad *sinkpad = NULL;
1093 GstCaps* caps = NULL;
1094 GstElement* new_element = NULL;
1095 GstStructure* str = NULL;
1096 const gchar* name = NULL;
1098 mm_player_t* player = (mm_player_t*) data;
1102 MMPLAYER_RETURN_IF_FAIL(element && pad);
1103 MMPLAYER_RETURN_IF_FAIL(player &&
1105 player->pipeline->mainbin);
1108 /* payload type is recognizable. increase num_dynamic and wait for sinkbin creation.
1109 * num_dynamic_pad will decreased after creating a sinkbin.
1111 player->num_dynamic_pad++;
1112 LOGD("stream count inc : %d\n", player->num_dynamic_pad);
1114 caps = gst_pad_query_caps(pad, NULL);
1116 MMPLAYER_CHECK_NULL(caps);
1118 /* clear previous result*/
1119 player->have_dynamic_pad = FALSE;
1121 str = gst_caps_get_structure(caps, 0);
1124 LOGE("cannot get structure from caps.\n");
1128 name = gst_structure_get_name(str);
1130 LOGE("cannot get mimetype from structure.\n");
1134 if (strstr(name, "video")) {
1136 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1138 if (stype == MM_DISPLAY_SURFACE_NULL || stype == MM_DISPLAY_SURFACE_REMOTE) {
1139 if (player->v_stream_caps) {
1140 gst_caps_unref(player->v_stream_caps);
1141 player->v_stream_caps = NULL;
1144 new_element = gst_element_factory_make("fakesink", NULL);
1145 player->num_dynamic_pad--;
1150 /* clear previous result*/
1151 player->have_dynamic_pad = FALSE;
1153 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
1154 LOGE("failed to autoplug for caps");
1158 /* check if there's dynamic pad*/
1159 if (player->have_dynamic_pad) {
1160 LOGE("using pad caps assums there's no dynamic pad !\n");
1164 gst_caps_unref(caps);
1169 /* excute new_element if created*/
1171 LOGD("adding new element to pipeline\n");
1173 /* set state to READY before add to bin */
1174 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_READY);
1176 /* add new element to the pipeline */
1177 if (FALSE == gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), new_element)) {
1178 LOGE("failed to add autoplug element to bin\n");
1182 /* get pad from element */
1183 sinkpad = gst_element_get_static_pad(GST_ELEMENT(new_element), "sink");
1185 LOGE("failed to get sinkpad from autoplug element\n");
1190 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1191 LOGE("failed to link autoplug element\n");
1195 gst_object_unref(sinkpad);
1198 /* run. setting PLAYING here since streamming source is live source */
1199 MMPLAYER_ELEMENT_SET_STATE(new_element, GST_STATE_PLAYING);
1203 gst_caps_unref(caps);
1209 STATE_CHANGE_FAILED:
1211 /* FIXIT : take care if new_element has already added to pipeline */
1213 gst_object_unref(GST_OBJECT(new_element));
1216 gst_object_unref(GST_OBJECT(sinkpad));
1219 gst_caps_unref(caps);
1221 /* FIXIT : how to inform this error to MSL ????? */
1222 /* FIXIT : I think we'd better to use g_idle_add() to destroy pipeline and
1223 * then post an error to application
1227 static GstPadProbeReturn
1228 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
1230 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
1231 return GST_PAD_PROBE_OK;
1234 static GstPadProbeReturn
1235 __mmplayer_gst_selector_event_probe(GstPad * pad, GstPadProbeInfo * info, gpointer data)
1237 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1238 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
1239 mm_player_t* player = (mm_player_t*)data;
1240 GstCaps* caps = NULL;
1241 GstStructure* str = NULL;
1242 const gchar* name = NULL;
1243 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1246 if (GST_EVENT_IS_DOWNSTREAM(event)) {
1247 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1248 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1249 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1250 GST_EVENT_TYPE(event) != GST_EVENT_EOS)
1252 } else if (GST_EVENT_IS_UPSTREAM(event)) {
1253 if (GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1257 caps = gst_pad_query_caps(pad, NULL);
1259 LOGE("failed to get caps from pad[%s:%s]", GST_DEBUG_PAD_NAME(pad));
1263 str = gst_caps_get_structure(caps, 0);
1265 LOGE("failed to get structure from caps");
1269 name = gst_structure_get_name(str);
1271 LOGE("failed to get name from str");
1275 if (strstr(name, "audio")) {
1276 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1277 } else if (strstr(name, "video")) {
1278 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1280 /* text track is not supportable */
1281 LOGE("invalid name %s", name);
1285 switch (GST_EVENT_TYPE(event)) {
1288 /* in case of gapless, drop eos event not to send it to sink */
1289 if (player->gapless.reconfigure && !player->msg_posted) {
1290 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1291 ret = GST_PAD_PROBE_DROP;
1295 case GST_EVENT_STREAM_START:
1297 gint64 stop_running_time = 0;
1298 gint64 position_running_time = 0;
1299 gint64 position = 0;
1302 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
1303 if ((player->gapless.update_segment[idx] == TRUE) ||
1304 !(player->selector[idx].event_probe_id)) {
1305 /* LOGW("[%d] skip", idx); */
1309 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
1311 gst_segment_to_running_time(&player->gapless.segment[idx],
1312 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
1313 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
1315 gst_segment_to_running_time(&player->gapless.segment[idx],
1316 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
1318 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
1320 gst_segment_to_running_time(&player->gapless.segment[idx],
1321 GST_FORMAT_TIME, player->duration);
1324 position_running_time =
1325 gst_segment_to_running_time(&player->gapless.segment[idx],
1326 GST_FORMAT_TIME, player->gapless.segment[idx].position);
1328 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
1329 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
1331 GST_TIME_ARGS(stop_running_time),
1332 GST_TIME_ARGS(position_running_time),
1333 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
1334 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
1336 position_running_time = MAX(position_running_time, stop_running_time);
1337 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
1338 GST_FORMAT_TIME, player->gapless.segment[idx].start);
1339 position_running_time = MAX(0, position_running_time);
1340 position = MAX(position, position_running_time);
1343 if (position != 0) {
1344 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1345 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
1346 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
1348 player->gapless.start_time[stream_type] += position;
1352 case GST_EVENT_FLUSH_STOP:
1354 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1355 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1356 player->gapless.start_time[stream_type] = 0;
1359 case GST_EVENT_SEGMENT:
1364 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1365 gst_event_copy_segment(event, &segment);
1367 if (segment.format == GST_FORMAT_TIME) {
1368 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1369 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1370 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1371 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1372 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1373 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1375 /* keep the all the segment ev to cover the seeking */
1376 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1377 player->gapless.update_segment[stream_type] = TRUE;
1379 if (!player->gapless.running)
1382 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1384 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1386 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1387 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1388 gst_event_unref(event);
1389 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1395 gdouble proportion = 0.0;
1396 GstClockTimeDiff diff = 0;
1397 GstClockTime timestamp = 0;
1398 gint64 running_time_diff = -1;
1399 GstQOSType type = 0;
1400 GstEvent *tmpev = NULL;
1402 running_time_diff = player->gapless.segment[stream_type].base;
1404 if (running_time_diff <= 0) /* don't need to adjust */
1407 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1408 gst_event_unref(event);
1410 if (timestamp < running_time_diff) {
1411 LOGW("QOS event from previous group");
1412 ret = GST_PAD_PROBE_DROP;
1416 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1417 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1418 stream_type, GST_TIME_ARGS(timestamp),
1419 GST_TIME_ARGS(running_time_diff),
1420 GST_TIME_ARGS(timestamp - running_time_diff));
1422 timestamp -= running_time_diff;
1424 /* That case is invalid for QoS events */
1425 if (diff < 0 && -diff > timestamp) {
1426 LOGW("QOS event from previous group");
1427 ret = GST_PAD_PROBE_DROP;
1431 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1432 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1442 gst_caps_unref(caps);
1447 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1449 mm_player_t* player = NULL;
1450 GstElement* pipeline = NULL;
1451 GstElement* selector = NULL;
1452 GstElement* fakesink = NULL;
1453 GstCaps* caps = NULL;
1454 GstStructure* str = NULL;
1455 const gchar* name = NULL;
1456 GstPad* sinkpad = NULL;
1457 GstPad* srcpad = NULL;
1458 gboolean first_track = FALSE;
1460 enum MainElementID elemId = MMPLAYER_M_NUM;
1461 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1464 player = (mm_player_t*)data;
1466 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1467 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1469 //LOGD("pad-added signal handling\n");
1471 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1473 /* get mimetype from caps */
1474 caps = gst_pad_query_caps(pad, NULL);
1476 LOGE("cannot get caps from pad.\n");
1480 str = gst_caps_get_structure(caps, 0);
1482 LOGE("cannot get structure from caps.\n");
1486 name = gst_structure_get_name(str);
1488 LOGE("cannot get mimetype from structure.\n");
1492 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1493 //LOGD("detected mimetype : %s\n", name);
1495 if (strstr(name, "video")) {
1498 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1499 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1501 /* don't make video because of not required, and not support multiple track */
1502 if (stype == MM_DISPLAY_SURFACE_NULL) {
1503 LOGD("no video sink by null surface");
1505 gchar *caps_str = gst_caps_to_string(caps);
1506 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1507 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1508 player->set_mode.video_zc = TRUE;
1510 MMPLAYER_FREEIF(caps_str);
1512 if (player->v_stream_caps) {
1513 gst_caps_unref(player->v_stream_caps);
1514 player->v_stream_caps = NULL;
1517 LOGD("create fakesink instead of videobin");
1520 fakesink = gst_element_factory_make("fakesink", NULL);
1521 if (fakesink == NULL) {
1522 LOGE("ERROR : fakesink create error\n");
1526 if (player->ini.set_dump_element_flag)
1527 __mmplayer_add_dump_buffer_probe(player, fakesink);
1529 player->video_fakesink = fakesink;
1531 /* store it as it's sink element */
1532 __mmplayer_add_sink(player, player->video_fakesink);
1534 gst_bin_add(GST_BIN(pipeline), fakesink);
1537 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1539 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1540 LOGW("failed to link fakesink\n");
1541 gst_object_unref(GST_OBJECT(fakesink));
1545 if (stype == MM_DISPLAY_SURFACE_REMOTE) {
1546 MMPLAYER_SIGNAL_CONNECT(player, sinkpad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1547 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
1550 if (player->set_mode.media_packet_video_stream) {
1551 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL);
1553 MMPLAYER_SIGNAL_CONNECT(player,
1555 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1557 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
1560 MMPLAYER_SIGNAL_CONNECT(player,
1562 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1564 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
1568 g_object_set(G_OBJECT(fakesink), "async", TRUE, "sync", TRUE, NULL);
1569 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1573 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1574 __mmplayer_gst_decode_callback(elem, pad, player);
1578 LOGD("video selector \n");
1579 elemId = MMPLAYER_M_V_INPUT_SELECTOR;
1580 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1582 if (strstr(name, "audio")) {
1583 gint samplerate = 0;
1586 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1587 __mmplayer_gst_decode_callback(elem, pad, player);
1591 LOGD("audio selector \n");
1592 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
1593 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1595 gst_structure_get_int(str, "rate", &samplerate);
1596 gst_structure_get_int(str, "channels", &channels);
1598 if ((channels > 0 && samplerate == 0)) {//exclude audio decoding
1600 fakesink = gst_element_factory_make("fakesink", NULL);
1601 if (fakesink == NULL) {
1602 LOGE("ERROR : fakesink create error\n");
1606 gst_bin_add(GST_BIN(pipeline), fakesink);
1609 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1611 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1612 LOGW("failed to link fakesink\n");
1613 gst_object_unref(GST_OBJECT(fakesink));
1617 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1618 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1622 } else if (strstr(name, "text")) {
1623 LOGD("text selector \n");
1624 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
1625 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1627 LOGE("wrong elem id \n");
1632 selector = player->pipeline->mainbin[elemId].gst;
1633 if (selector == NULL) {
1634 selector = gst_element_factory_make("input-selector", NULL);
1635 LOGD("Creating input-selector\n");
1636 if (selector == NULL) {
1637 LOGE("ERROR : input-selector create error\n");
1640 g_object_set(selector, "sync-streams", TRUE, NULL);
1642 player->pipeline->mainbin[elemId].id = elemId;
1643 player->pipeline->mainbin[elemId].gst = selector;
1646 // player->selector[stream_type].active_pad_index = DEFAULT_TRACK; // default
1648 srcpad = gst_element_get_static_pad(selector, "src");
1650 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1651 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1652 __mmplayer_gst_selector_blocked, NULL, NULL);
1653 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1654 __mmplayer_gst_selector_event_probe, player, NULL);
1656 gst_element_set_state(selector, GST_STATE_PAUSED);
1657 gst_bin_add(GST_BIN(pipeline), selector);
1659 LOGD("input-selector is already created.\n");
1662 LOGD("Calling request pad with selector %p \n", selector);
1663 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1665 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(sinkpad));
1667 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
1668 LOGW("failed to link selector\n");
1669 gst_object_unref(GST_OBJECT(selector));
1674 LOGD("this is first track --> active track \n");
1675 g_object_set(selector, "active-pad", sinkpad, NULL);
1678 _mmplayer_track_update_info(player, stream_type, sinkpad);
1685 gst_caps_unref(caps);
1688 gst_object_unref(GST_OBJECT(sinkpad));
1693 gst_object_unref(GST_OBJECT(srcpad));
1700 static void __mmplayer_handle_text_decode_path(mm_player_t* player, GstElement* text_selector)
1702 GstPad* srcpad = NULL;
1703 MMHandleType attrs = 0;
1704 gint active_index = 0;
1706 // [link] input-selector :: textbin
1707 srcpad = gst_element_get_static_pad(text_selector, "src");
1709 LOGE("failed to get srcpad from selector\n");
1713 LOGD("got pad %s:%s from text selector\n", GST_DEBUG_PAD_NAME(srcpad));
1715 active_index = player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index;
1716 if ((active_index != DEFAULT_TRACK) &&
1717 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_TEXT, active_index) != MM_ERROR_NONE)) {
1718 LOGW("failed to change text track\n");
1719 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].active_pad_index = DEFAULT_TRACK;
1722 player->no_more_pad = TRUE;
1723 __mmplayer_gst_decode_callback(text_selector, srcpad, player);
1725 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1726 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id) {
1727 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id);
1728 player->selector[MM_PLAYER_TRACK_TYPE_TEXT].block_id = 0;
1731 LOGD("Total text tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1733 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1734 player->has_closed_caption = TRUE;
1736 attrs = MMPLAYER_GET_ATTRS(player);
1738 mm_attrs_set_int_by_name(attrs, "content_text_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num);
1739 if (mmf_attrs_commit(attrs))
1740 LOGE("failed to commit.\n");
1742 LOGE("cannot get content attribute");
1745 gst_object_unref(GST_OBJECT(srcpad));
1751 __mmplayer_gst_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1753 mm_player_t* player = (mm_player_t*)data;
1754 GstElement* selector = NULL;
1755 GstElement* queue = NULL;
1757 GstPad* srcpad = NULL;
1758 GstPad* sinkpad = NULL;
1759 GstCaps* caps = NULL;
1760 gchar* caps_str = NULL;
1763 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1765 caps = gst_pad_get_current_caps(pad);
1766 caps_str = gst_caps_to_string(caps);
1767 LOGD("deinterleave new caps : %s\n", caps_str);
1768 MMPLAYER_FREEIF(caps_str);
1769 gst_caps_unref(caps);
1771 if ((queue = __mmplayer_element_create_and_link(player, pad, "queue")) == NULL) {
1772 LOGE("ERROR : queue create error\n");
1776 g_object_set(G_OBJECT(queue),
1777 "max-size-buffers", 10,
1778 "max-size-bytes", 0,
1779 "max-size-time", (guint64)0,
1782 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1785 LOGE("there is no audio channel selector.\n");
1789 srcpad = gst_element_get_static_pad(queue, "src");
1790 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1792 LOGD("link(%s:%s - %s:%s)\n", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
1794 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1795 LOGW("failed to link deinterleave - selector\n");
1799 gst_element_set_state(queue, GST_STATE_PAUSED);
1800 player->audio_mode.total_track_num++;
1805 gst_object_unref(GST_OBJECT(srcpad));
1810 gst_object_unref(GST_OBJECT(sinkpad));
1819 __mmplayer_gst_deinterleave_no_more_pads(GstElement *elem, gpointer data)
1821 mm_player_t* player = NULL;
1822 GstElement* selector = NULL;
1823 GstPad* sinkpad = NULL;
1824 gint active_index = 0;
1825 gchar* change_pad_name = NULL;
1826 GstCaps* caps = NULL; // no need to unref
1827 gint default_audio_ch = 0;
1830 player = (mm_player_t*) data;
1832 selector = player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst;
1835 LOGE("there is no audio channel selector.\n");
1839 active_index = player->audio_mode.active_pad_index;
1841 if (active_index != default_audio_ch) {
1842 gint audio_ch = default_audio_ch;
1844 /*To get the new pad from the selector*/
1845 change_pad_name = g_strdup_printf("sink%d", active_index);
1846 if (change_pad_name != NULL) {
1847 sinkpad = gst_element_get_static_pad(selector, change_pad_name);
1848 if (sinkpad != NULL) {
1849 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
1850 g_object_set(selector, "active-pad", sinkpad, NULL);
1852 audio_ch = active_index;
1854 caps = gst_pad_get_current_caps(sinkpad);
1855 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1857 __mmplayer_set_audio_attrs(player, caps);
1858 gst_caps_unref(caps);
1860 MMPLAYER_FREEIF(change_pad_name);
1863 player->audio_mode.active_pad_index = audio_ch;
1864 LOGD("audio LR info(0:stereo) = %d\n", player->audio_mode.active_pad_index);
1870 gst_object_unref(sinkpad);
1877 __mmplayer_gst_build_deinterleave_path(GstElement *elem, GstPad *pad, gpointer data)
1879 mm_player_t* player = NULL;
1880 MMPlayerGstElement *mainbin = NULL;
1882 GstElement* tee = NULL;
1883 GstElement* stereo_queue = NULL;
1884 GstElement* mono_queue = NULL;
1885 GstElement* conv = NULL;
1886 GstElement* filter = NULL;
1887 GstElement* deinterleave = NULL;
1888 GstElement* selector = NULL;
1890 GstPad* srcpad = NULL;
1891 GstPad* selector_srcpad = NULL;
1892 GstPad* sinkpad = NULL;
1893 GstCaps* caps = NULL;
1894 gulong block_id = 0;
1899 player = (mm_player_t*) data;
1901 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1902 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1904 mainbin = player->pipeline->mainbin;
1907 if ((tee = __mmplayer_element_create_and_link(player, pad, "tee")) == NULL) {
1908 LOGE("ERROR : tee create error\n");
1912 mainbin[MMPLAYER_M_A_TEE].id = MMPLAYER_M_A_TEE;
1913 mainbin[MMPLAYER_M_A_TEE].gst = tee;
1915 gst_element_set_state(tee, GST_STATE_PAUSED);
1918 srcpad = gst_element_get_request_pad(tee, "src_%u");
1919 if ((stereo_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1920 LOGE("ERROR : stereo queue create error\n");
1924 g_object_set(G_OBJECT(stereo_queue),
1925 "max-size-buffers", 10,
1926 "max-size-bytes", 0,
1927 "max-size-time", (guint64)0,
1930 player->pipeline->mainbin[MMPLAYER_M_A_Q1].id = MMPLAYER_M_A_Q1;
1931 player->pipeline->mainbin[MMPLAYER_M_A_Q1].gst = stereo_queue;
1934 gst_object_unref(GST_OBJECT(srcpad));
1938 srcpad = gst_element_get_request_pad(tee, "src_%u");
1940 if ((mono_queue = __mmplayer_element_create_and_link(player, srcpad, "queue")) == NULL) {
1941 LOGE("ERROR : mono queue create error\n");
1945 g_object_set(G_OBJECT(mono_queue),
1946 "max-size-buffers", 10,
1947 "max-size-bytes", 0,
1948 "max-size-time", (guint64)0,
1951 player->pipeline->mainbin[MMPLAYER_M_A_Q2].id = MMPLAYER_M_A_Q2;
1952 player->pipeline->mainbin[MMPLAYER_M_A_Q2].gst = mono_queue;
1954 gst_element_set_state(stereo_queue, GST_STATE_PAUSED);
1955 gst_element_set_state(mono_queue, GST_STATE_PAUSED);
1958 srcpad = gst_element_get_static_pad(mono_queue, "src");
1959 if ((conv = __mmplayer_element_create_and_link(player, srcpad, "audioconvert")) == NULL) {
1960 LOGE("ERROR : audioconvert create error\n");
1964 player->pipeline->mainbin[MMPLAYER_M_A_CONV].id = MMPLAYER_M_A_CONV;
1965 player->pipeline->mainbin[MMPLAYER_M_A_CONV].gst = conv;
1969 gst_object_unref(GST_OBJECT(srcpad));
1972 srcpad = gst_element_get_static_pad(conv, "src");
1974 if ((filter = __mmplayer_element_create_and_link(player, srcpad, "capsfilter")) == NULL) {
1975 LOGE("ERROR : capsfilter create error\n");
1979 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].id = MMPLAYER_M_A_FILTER;
1980 player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst = filter;
1982 caps = gst_caps_from_string("audio/x-raw-int, "
1983 "width = (int) 16, "
1984 "depth = (int) 16, "
1985 "channels = (int) 2");
1987 g_object_set(GST_ELEMENT(player->pipeline->mainbin[MMPLAYER_M_A_FILTER].gst), "caps", caps, NULL);
1988 gst_caps_unref(caps);
1990 gst_element_set_state(conv, GST_STATE_PAUSED);
1991 gst_element_set_state(filter, GST_STATE_PAUSED);
1995 gst_object_unref(GST_OBJECT(srcpad));
1998 srcpad = gst_element_get_static_pad(filter, "src");
2000 if ((deinterleave = __mmplayer_element_create_and_link(player, srcpad, "deinterleave")) == NULL) {
2001 LOGE("ERROR : deinterleave create error\n");
2005 g_object_set(deinterleave, "keep-positions", TRUE, NULL);
2007 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
2008 G_CALLBACK(__mmplayer_gst_deinterleave_pad_added), player);
2010 MMPLAYER_SIGNAL_CONNECT(player, deinterleave, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
2011 G_CALLBACK(__mmplayer_gst_deinterleave_no_more_pads), player);
2013 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].id = MMPLAYER_M_A_DEINTERLEAVE;
2014 player->pipeline->mainbin[MMPLAYER_M_A_DEINTERLEAVE].gst = deinterleave;
2017 selector = gst_element_factory_make("input-selector", "audio-channel-selector");
2018 if (selector == NULL) {
2019 LOGE("ERROR : audio-selector create error\n");
2023 g_object_set(selector, "sync-streams", TRUE, NULL);
2024 gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), selector);
2026 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].id = MMPLAYER_M_A_SELECTOR;
2027 player->pipeline->mainbin[MMPLAYER_M_A_SELECTOR].gst = selector;
2029 selector_srcpad = gst_element_get_static_pad(selector, "src");
2031 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
2033 gst_pad_add_probe(selector_srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2034 __mmplayer_gst_selector_blocked, NULL, NULL);
2037 gst_object_unref(GST_OBJECT(srcpad));
2041 srcpad = gst_element_get_static_pad(stereo_queue, "src");
2042 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
2044 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
2045 LOGW("failed to link queue_stereo - selector\n");
2049 player->audio_mode.total_track_num++;
2051 g_object_set(selector, "active-pad", sinkpad, NULL);
2052 gst_element_set_state(deinterleave, GST_STATE_PAUSED);
2053 gst_element_set_state(selector, GST_STATE_PAUSED);
2055 __mmplayer_gst_decode_callback(selector, selector_srcpad, player);
2059 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(selector_srcpad));
2060 if (block_id != 0) {
2061 gst_pad_remove_probe(selector_srcpad, block_id);
2066 gst_object_unref(GST_OBJECT(sinkpad));
2071 gst_object_unref(GST_OBJECT(srcpad));
2075 if (selector_srcpad) {
2076 gst_object_unref(GST_OBJECT(selector_srcpad));
2077 selector_srcpad = NULL;
2085 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
2087 mm_player_t* player = NULL;
2088 GstPad* srcpad = NULL;
2089 GstElement* video_selector = NULL;
2090 GstElement* audio_selector = NULL;
2091 GstElement* text_selector = NULL;
2092 MMHandleType attrs = 0;
2093 gint active_index = 0;
2094 gint64 dur_bytes = 0L;
2096 player = (mm_player_t*) data;
2098 LOGD("no-more-pad signal handling\n");
2100 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
2101 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
2102 LOGW("no need to go more");
2104 if (player->gapless.reconfigure) {
2105 player->gapless.reconfigure = FALSE;
2106 MMPLAYER_PLAYBACK_UNLOCK(player);
2112 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
2113 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
2114 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
2115 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
2116 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
2118 if (NULL == player->streamer) {
2119 LOGW("invalid state for buffering");
2123 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
2124 guint buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
2126 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
2127 LOGD("[Decodebin2] set use-buffering on Q2(pre buffer time: %d ms, buffer size : %d)\n", init_buffering_time, buffer_bytes);
2129 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
2131 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
2132 LOGE("fail to get duration.\n");
2134 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
2135 * use file information was already set on Q2 when it was created. */
2136 __mm_player_streaming_set_queue2(player->streamer,
2137 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
2138 TRUE, /* use_buffering */
2140 init_buffering_time,
2141 1.0, /* low percent */
2142 player->ini.http_buffering_limit, /* high percent */
2143 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
2145 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
2148 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
2149 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
2150 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
2151 if (video_selector) {
2152 // [link] input-selector :: videobin
2153 srcpad = gst_element_get_static_pad(video_selector, "src");
2155 LOGE("failed to get srcpad from video selector\n");
2159 LOGD("got pad %s:%s from video selector\n", GST_DEBUG_PAD_NAME(srcpad));
2160 if (!text_selector && !audio_selector)
2161 player->no_more_pad = TRUE;
2163 __mmplayer_gst_decode_callback(video_selector, srcpad, player);
2165 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2166 if (player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id) {
2167 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id);
2168 player->selector[MM_PLAYER_TRACK_TYPE_VIDEO].block_id = 0;
2172 if (audio_selector) {
2173 active_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index;
2174 if ((active_index != DEFAULT_TRACK) &&
2175 (__mmplayer_change_selector_pad(player, MM_PLAYER_TRACK_TYPE_AUDIO, active_index) != MM_ERROR_NONE)) {
2176 LOGW("failed to change audio track\n");
2177 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index = DEFAULT_TRACK;
2180 // [link] input-selector :: audiobin
2181 srcpad = gst_element_get_static_pad(audio_selector, "src");
2183 LOGE("failed to get srcpad from selector\n");
2187 LOGD("got pad %s:%s from selector\n", GST_DEBUG_PAD_NAME(srcpad));
2189 player->no_more_pad = TRUE;
2191 if ((player->use_deinterleave == TRUE) && (player->max_audio_channels >= 2)) {
2192 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2193 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
2194 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
2195 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
2198 __mmplayer_gst_build_deinterleave_path(audio_selector, srcpad, player);
2200 __mmplayer_gst_decode_callback(audio_selector, srcpad, player);
2202 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
2203 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id) {
2204 gst_pad_remove_probe(srcpad, player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id);
2205 player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].block_id = 0;
2209 LOGD("Total audio tracks = %d \n", player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
2211 attrs = MMPLAYER_GET_ATTRS(player);
2213 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", (gint)player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num);
2214 if (mmf_attrs_commit(attrs))
2215 LOGE("failed to commit.\n");
2217 LOGE("cannot get content attribute");
2219 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
2220 LOGD("There is no audio track : remove audiobin");
2222 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
2223 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
2225 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
2226 MMPLAYER_FREEIF(player->pipeline->audiobin);
2229 if (player->num_dynamic_pad == 0)
2230 __mmplayer_pipeline_complete(NULL, player);
2233 if (!MMPLAYER_IS_MS_BUFF_SRC(player)) {
2235 __mmplayer_handle_text_decode_path(player, text_selector);
2242 gst_object_unref(GST_OBJECT(srcpad));
2246 if (player->gapless.reconfigure) {
2247 player->gapless.reconfigure = FALSE;
2248 MMPLAYER_PLAYBACK_UNLOCK(player);
2253 __mmplayer_gst_decode_callback(GstElement *elem, GstPad *pad, gpointer data)
2255 mm_player_t* player = NULL;
2256 MMHandleType attrs = 0;
2257 GstElement* pipeline = NULL;
2258 GstCaps* caps = NULL;
2259 gchar* caps_str = NULL;
2260 GstStructure* str = NULL;
2261 const gchar* name = NULL;
2262 GstPad* sinkpad = NULL;
2263 GstElement* sinkbin = NULL;
2264 gboolean reusing = FALSE;
2265 GstElement *text_selector = NULL;
2268 player = (mm_player_t*) data;
2270 MMPLAYER_RETURN_IF_FAIL(elem && pad);
2271 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2273 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
2275 attrs = MMPLAYER_GET_ATTRS(player);
2277 LOGE("cannot get content attribute\n");
2281 /* get mimetype from caps */
2282 caps = gst_pad_query_caps(pad, NULL);
2284 LOGE("cannot get caps from pad.\n");
2287 caps_str = gst_caps_to_string(caps);
2289 str = gst_caps_get_structure(caps, 0);
2291 LOGE("cannot get structure from caps.\n");
2295 name = gst_structure_get_name(str);
2297 LOGE("cannot get mimetype from structure.\n");
2301 //LOGD("detected mimetype : %s\n", name);
2303 if (strstr(name, "audio")) {
2304 if (player->pipeline->audiobin == NULL) {
2305 if (MM_ERROR_NONE != __mmplayer_gst_create_audio_pipeline(player)) {
2306 LOGE("failed to create audiobin. continuing without audio\n");
2310 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2311 LOGD("creating audiosink bin success\n");
2314 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
2315 LOGD("reusing audiobin\n");
2316 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2319 if (player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].total_track_num <= 0) // should not update if content have multi audio tracks
2320 mm_attrs_set_int_by_name(attrs, "content_audio_track_num", 1);
2322 player->audiosink_linked = 1;
2324 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2326 LOGE("failed to get pad from sinkbin\n");
2329 } else if (strstr(name, "video")) {
2330 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
2331 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
2332 player->set_mode.video_zc = TRUE;
2334 if (player->pipeline->videobin == NULL) {
2335 /* NOTE : not make videobin because application dose not want to play it even though file has video stream. */
2336 /* get video surface type */
2337 int surface_type = 0;
2338 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2339 LOGD("display_surface_type(%d)\n", surface_type);
2341 if (surface_type == MM_DISPLAY_SURFACE_NULL) {
2342 LOGD("not make videobin because it dose not want\n");
2346 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
2347 /* mark video overlay for acquire */
2348 if (player->video_overlay_resource == NULL) {
2349 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
2350 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2351 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2352 &player->video_overlay_resource)
2353 != MM_RESOURCE_MANAGER_ERROR_NONE) {
2354 LOGE("could not mark video_overlay resource for acquire\n");
2360 player->interrupted_by_resource = FALSE;
2361 /* acquire resources for video overlay */
2362 if (mm_resource_manager_commit(player->resource_manager) !=
2363 MM_RESOURCE_MANAGER_ERROR_NONE) {
2364 LOGE("could not acquire resources for video playing\n");
2368 if (MM_ERROR_NONE != __mmplayer_gst_create_video_pipeline(player, caps, surface_type)) {
2369 LOGE("failed to create videobin. continuing without video\n");
2373 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2374 LOGD("creating videosink bin success\n");
2377 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
2378 LOGD("re-using videobin\n");
2379 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2382 player->videosink_linked = 1;
2384 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "sink");
2386 LOGE("failed to get pad from sinkbin\n");
2389 } else if (strstr(name, "text")) {
2390 if (player->pipeline->textbin == NULL) {
2391 MMPlayerGstElement* mainbin = NULL;
2393 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
2394 LOGE("failed to create text sink bin. continuing without text\n");
2398 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2399 LOGD("creating textsink bin success\n");
2401 /* FIXIT : track number shouldn't be hardcoded */
2402 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
2404 player->textsink_linked = 1;
2405 LOGI("player->textsink_linked set to 1\n");
2407 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), "text_sink");
2409 LOGE("failed to get pad from sinkbin\n");
2413 mainbin = player->pipeline->mainbin;
2415 if (!mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst) {
2416 /* input selector */
2417 text_selector = gst_element_factory_make("input-selector", "subtitle_inselector");
2418 if (!text_selector) {
2419 LOGE("failed to create subtitle input selector element\n");
2422 g_object_set(text_selector, "sync-streams", TRUE, NULL);
2424 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].id = MMPLAYER_M_T_INPUT_SELECTOR;
2425 mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst = text_selector;
2428 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_READY)) {
2429 LOGE("failed to set state(READY) to sinkbin\n");
2433 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), text_selector)) {
2434 LOGW("failed to add subtitle input selector\n");
2438 LOGD("created element input-selector");
2441 LOGD("already having subtitle input selector");
2442 text_selector = mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
2445 if (!player->textsink_linked) {
2446 LOGD("re-using textbin\n");
2449 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
2451 player->textsink_linked = 1;
2452 LOGI("player->textsink_linked set to 1\n");
2454 LOGD("ignoring internal subtutle since external subtitle is available");
2457 LOGW("unknown type of elementary stream!ignoring it...\n");
2464 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_READY)) {
2465 LOGE("failed to set state(READY) to sinkbin\n");
2469 /* Added for multi audio support to avoid adding audio bin again*/
2471 if (FALSE == gst_bin_add(GST_BIN(pipeline), sinkbin)) {
2472 LOGE("failed to add sinkbin to pipeline\n");
2478 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2479 LOGE("failed to get pad from sinkbin\n");
2485 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(sinkbin, GST_STATE_PAUSED)) {
2486 LOGE("failed to set state(PAUSED) to sinkbin\n");
2490 if (text_selector) {
2491 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(text_selector, GST_STATE_PAUSED)) {
2492 LOGE("failed to set state(PAUSED) to sinkbin\n");
2498 gst_object_unref(sinkpad);
2502 LOGD("[handle: %p] linking sink bin success", player);
2504 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
2505 * streaming task. if the task blocked, then buffer will not flow to the next element
2506 *(autoplugging element). so this is special hack for streaming. please try to remove it
2508 /* dec stream count. we can remove fakesink if it's zero */
2509 if (player->num_dynamic_pad)
2510 player->num_dynamic_pad--;
2512 LOGD("no more pads: %d stream count dec : %d(num of dynamic pad)\n", player->no_more_pad, player->num_dynamic_pad);
2514 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
2515 __mmplayer_pipeline_complete(NULL, player);
2519 MMPLAYER_FREEIF(caps_str);
2522 gst_caps_unref(caps);
2525 gst_object_unref(GST_OBJECT(sinkpad));
2527 /* flusing out new attributes */
2528 if (mmf_attrs_commit(attrs))
2529 LOGE("failed to comit attributes\n");
2535 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int rotation_angle, int *value)
2537 int pro_value = 0; // in the case of expection, default will be returned.
2538 int dest_angle = rotation_angle;
2539 int rotation_type = -1;
2541 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
2542 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
2543 MMPLAYER_RETURN_VAL_IF_FAIL(rotation_angle >= 0, FALSE);
2545 if (rotation_angle >= 360)
2546 dest_angle = rotation_angle - 360;
2548 /* chech if supported or not */
2549 if (dest_angle % 90) {
2550 LOGD("not supported rotation angle = %d", rotation_angle);
2556 * custom_convert - none (B)
2557 * videoflip - none (C)
2559 if (player->set_mode.video_zc) {
2560 if (player->pipeline->videobin[MMPLAYER_V_CONV].gst) // B
2561 rotation_type = ROTATION_USING_CUSTOM;
2563 rotation_type = ROTATION_USING_SINK;
2565 int surface_type = 0;
2566 rotation_type = ROTATION_USING_FLIP;
2568 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
2569 LOGD("check display surface type attribute: %d", surface_type);
2571 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY)
2572 rotation_type = ROTATION_USING_SINK;
2574 rotation_type = ROTATION_USING_FLIP; //C
2576 LOGD("using %d type for rotation", rotation_type);
2579 /* get property value for setting */
2580 switch (rotation_type) {
2581 case ROTATION_USING_SINK: // tizenwlsink
2583 switch (dest_angle) {
2587 pro_value = 3; // clockwise 90
2593 pro_value = 1; // counter-clockwise 90
2598 case ROTATION_USING_CUSTOM:
2600 gchar *ename = NULL;
2601 ename = GST_OBJECT_NAME(gst_element_get_factory(player->pipeline->videobin[MMPLAYER_V_CONV].gst));
2603 if (g_strrstr(ename, "fimcconvert")) {
2604 switch (dest_angle) {
2608 pro_value = 90; // clockwise 90
2614 pro_value = 270; // counter-clockwise 90
2620 case ROTATION_USING_FLIP: // videoflip
2622 switch (dest_angle) {
2626 pro_value = 1; // clockwise 90
2632 pro_value = 3; // counter-clockwise 90
2639 LOGD("setting rotation property value : %d, used rotation type : %d", pro_value, rotation_type);
2647 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
2649 /* check video sinkbin is created */
2650 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
2652 player->pipeline->videobin &&
2653 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
2654 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2655 MM_ERROR_PLAYER_NOT_INITIALIZED);
2657 return MM_ERROR_NONE;
2661 __mmplayer_get_video_angle(mm_player_t* player, int *user_angle, int *org_angle)
2663 int user_angle_type = 0;
2664 gchar *org_orient = NULL;
2665 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
2668 LOGE("cannot get content attribute");
2669 return MM_ERROR_PLAYER_INTERNAL;
2673 /* update user roation */
2674 mm_attrs_get_int_by_name(attrs, "display_rotation", &user_angle_type);
2676 /* get angle with user type */
2677 switch (user_angle_type) {
2678 case MM_DISPLAY_ROTATION_NONE:
2681 case MM_DISPLAY_ROTATION_90: /* counter-clockwise 90 */
2684 case MM_DISPLAY_ROTATION_180:
2687 case MM_DISPLAY_ROTATION_270: /* clockwise 90 */
2691 LOGW("wrong angle type : %d", user_angle_type);
2694 LOGD("check user angle: %d", *user_angle);
2698 /* get original orientation */
2699 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
2702 if (!strcmp(org_orient, "rotate-90"))
2704 else if (!strcmp(org_orient, "rotate-180"))
2706 else if (!strcmp(org_orient, "rotate-270"))
2709 LOGD("original rotation is %s", org_orient);
2711 LOGD("content_video_orientation get fail");
2714 LOGD("check orientation: %d", *org_angle);
2717 return MM_ERROR_NONE;
2721 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
2723 int rotation_value = 0;
2724 int org_angle = 0; // current supported angle values are 0, 90, 180, 270
2728 /* check video sinkbin is created */
2729 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2732 __mmplayer_get_video_angle(player, &user_angle, &org_angle);
2734 /* get rotation value to set */
2735 __mmplayer_get_property_value_for_rotation(player, org_angle+user_angle, &rotation_value);
2736 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2737 LOGD("set video param : rotate %d", rotation_value);
2741 __mmplayer_video_param_set_display_visible(mm_player_t* player)
2743 MMHandleType attrs = 0;
2747 /* check video sinkbin is created */
2748 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2751 attrs = MMPLAYER_GET_ATTRS(player);
2752 MMPLAYER_RETURN_IF_FAIL(attrs);
2754 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2755 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2756 LOGD("set video param : visible %d", visible);
2760 __mmplayer_video_param_set_display_method(mm_player_t* player)
2762 MMHandleType attrs = 0;
2763 int display_method = 0;
2766 /* check video sinkbin is created */
2767 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2770 attrs = MMPLAYER_GET_ATTRS(player);
2771 MMPLAYER_RETURN_IF_FAIL(attrs);
2773 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2774 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2775 LOGD("set video param : method %d", display_method);
2779 __mmplayer_video_param_set_roi_area(mm_player_t* player)
2781 MMHandleType attrs = 0;
2782 void *handle = NULL;
2786 int win_roi_width = 0;
2787 int win_roi_height = 0;
2790 /* check video sinkbin is created */
2791 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2794 attrs = MMPLAYER_GET_ATTRS(player);
2795 MMPLAYER_RETURN_IF_FAIL(attrs);
2797 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2800 /* It should be set after setting window */
2801 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2802 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2803 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2804 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2806 /* After setting window handle, set display roi area */
2807 gst_video_overlay_set_display_roi_area(
2808 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2809 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2810 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2811 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2816 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
2818 MMHandleType attrs = 0;
2819 void *handle = NULL;
2821 /* check video sinkbin is created */
2822 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2825 attrs = MMPLAYER_GET_ATTRS(player);
2826 MMPLAYER_RETURN_IF_FAIL(attrs);
2828 /* common case if using overlay surface */
2829 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2832 /* default is using wl_surface_id */
2833 unsigned int wl_surface_id = 0;
2834 wl_surface_id = *(int*)handle;
2835 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
2836 gst_video_overlay_set_wl_window_wl_surface_id(
2837 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2840 /* FIXIT : is it error case? */
2841 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2846 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
2848 bool update_all_param = FALSE;
2851 /* check video sinkbin is created */
2852 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2853 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2855 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2856 LOGE("can not find tizenwlsink");
2857 return MM_ERROR_PLAYER_INTERNAL;
2860 LOGD("param_name : %s", param_name);
2861 if (!g_strcmp0(param_name, "update_all_param"))
2862 update_all_param = TRUE;
2864 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2865 __mmplayer_video_param_set_display_overlay(player);
2866 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2867 __mmplayer_video_param_set_display_method(player);
2868 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2869 __mmplayer_video_param_set_display_visible(player);
2870 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2871 __mmplayer_video_param_set_display_rotation(player);
2872 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2873 __mmplayer_video_param_set_roi_area(player);
2875 return MM_ERROR_NONE;
2879 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2881 MMHandleType attrs = 0;
2882 int surface_type = 0;
2883 int ret = MM_ERROR_NONE;
2887 /* check video sinkbin is created */
2888 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2889 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2891 attrs = MMPLAYER_GET_ATTRS(player);
2893 LOGE("cannot get content attribute");
2894 return MM_ERROR_PLAYER_INTERNAL;
2896 LOGD("param_name : %s", param_name);
2898 /* update display surface */
2899 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2900 LOGD("check display surface type attribute: %d", surface_type);
2902 /* configuring display */
2903 switch (surface_type) {
2904 case MM_DISPLAY_SURFACE_OVERLAY:
2906 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2907 if (ret != MM_ERROR_NONE)
2915 return MM_ERROR_NONE;
2919 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2921 gboolean disable_overlay = FALSE;
2922 mm_player_t* player = (mm_player_t*) hplayer;
2923 int ret = MM_ERROR_NONE;
2926 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2927 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2928 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2929 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2931 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2932 LOGW("Display control is not supported");
2933 return MM_ERROR_PLAYER_INTERNAL;
2936 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2938 if (audio_only == (bool)disable_overlay) {
2939 LOGE("It's the same with current setting: (%d)", audio_only);
2940 return MM_ERROR_NONE;
2944 LOGE("disable overlay");
2945 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2947 /* release overlay resource */
2948 if (player->video_overlay_resource != NULL) {
2949 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2950 player->video_overlay_resource);
2951 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2952 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2955 player->video_overlay_resource = NULL;
2958 ret = mm_resource_manager_commit(player->resource_manager);
2959 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2960 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2964 /* mark video overlay for acquire */
2965 if (player->video_overlay_resource == NULL) {
2966 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2967 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2968 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2969 &player->video_overlay_resource);
2970 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2971 LOGE("could not prepare for video_overlay resource\n");
2976 player->interrupted_by_resource = FALSE;
2977 /* acquire resources for video overlay */
2978 ret = mm_resource_manager_commit(player->resource_manager);
2979 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2980 LOGE("could not acquire resources for video playing\n");
2984 LOGD("enable overlay");
2985 __mmplayer_video_param_set_display_overlay(player);
2986 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2991 return MM_ERROR_NONE;
2995 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2997 mm_player_t* player = (mm_player_t*) hplayer;
2998 gboolean disable_overlay = FALSE;
3002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3003 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
3004 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
3005 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3006 MM_ERROR_PLAYER_NO_OP); /* invalid op */
3008 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
3009 LOGW("Display control is not supported");
3010 return MM_ERROR_PLAYER_INTERNAL;
3013 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
3015 *paudio_only = (bool)(disable_overlay);
3017 LOGD("audio_only : %d", *paudio_only);
3021 return MM_ERROR_NONE;
3025 __mmplayer_gst_element_link_bucket(GList* element_bucket)
3027 GList* bucket = element_bucket;
3028 MMPlayerGstElement* element = NULL;
3029 MMPlayerGstElement* prv_element = NULL;
3030 gint successful_link_count = 0;
3034 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
3036 prv_element = (MMPlayerGstElement*)bucket->data;
3037 bucket = bucket->next;
3039 for (; bucket; bucket = bucket->next) {
3040 element = (MMPlayerGstElement*)bucket->data;
3042 if (element && element->gst) {
3043 /* If next element is audio appsrc then make a separate audio pipeline */
3044 if (!strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "audio_appsrc") ||
3045 !strcmp(GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), "subtitle_appsrc")) {
3046 prv_element = element;
3050 if (prv_element && prv_element->gst) {
3051 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
3052 LOGD("linking [%s] to [%s] success\n",
3053 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
3054 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
3055 successful_link_count++;
3057 LOGD("linking [%s] to [%s] failed\n",
3058 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
3059 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
3065 prv_element = element;
3070 return successful_link_count;
3074 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
3076 GList* bucket = element_bucket;
3077 MMPlayerGstElement* element = NULL;
3078 int successful_add_count = 0;
3082 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
3083 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
3085 for (; bucket; bucket = bucket->next) {
3086 element = (MMPlayerGstElement*)bucket->data;
3088 if (element && element->gst) {
3089 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
3090 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
3091 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
3092 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
3095 successful_add_count++;
3101 return successful_add_count;
3104 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data)
3106 mm_player_t* player = (mm_player_t*) data;
3107 GstCaps *caps = NULL;
3108 GstStructure *str = NULL;
3113 MMPLAYER_RETURN_IF_FAIL(pad)
3114 MMPLAYER_RETURN_IF_FAIL(unused)
3115 MMPLAYER_RETURN_IF_FAIL(data)
3117 caps = gst_pad_get_current_caps(pad);
3121 str = gst_caps_get_structure(caps, 0);
3125 name = gst_structure_get_name(str);
3129 LOGD("name = %s\n", name);
3131 if (strstr(name, "audio")) {
3132 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
3134 if (player->audio_stream_changed_cb) {
3135 LOGE("call the audio stream changed cb\n");
3136 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
3138 } else if (strstr(name, "video")) {
3139 if ((name = gst_structure_get_string(str, "format")))
3140 player->set_mode.video_zc = name[0] == 'S';
3142 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
3144 if (player->video_stream_changed_cb) {
3145 LOGE("call the video stream changed cb\n");
3146 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
3153 gst_caps_unref(caps);
3163 * This function is to create audio pipeline for playing.
3165 * @param player [in] handle of player
3167 * @return This function returns zero on success.
3169 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_pipeline
3171 /* macro for code readability. just for sinkbin-creation functions */
3172 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
3174 x_bin[x_id].id = x_id;\
3175 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
3176 if (!x_bin[x_id].gst) {\
3177 LOGE("failed to create %s \n", x_factory);\
3180 if (x_player->ini.set_dump_element_flag)\
3181 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
3184 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
3188 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
3193 MMPLAYER_RETURN_IF_FAIL(player);
3195 if (player->audio_stream_buff_list) {
3196 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
3197 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
3200 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
3201 __mmplayer_audio_stream_send_data(player, tmp);
3204 g_free(tmp->pcm_data);
3208 g_list_free(player->audio_stream_buff_list);
3209 player->audio_stream_buff_list = NULL;
3216 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
3218 MMPlayerAudioStreamDataType audio_stream = { 0, };
3221 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
3223 audio_stream.bitrate = a_buffer->bitrate;
3224 audio_stream.channel = a_buffer->channel;
3225 audio_stream.depth = a_buffer->depth;
3226 audio_stream.is_little_endian = a_buffer->is_little_endian;
3227 audio_stream.channel_mask = a_buffer->channel_mask;
3228 audio_stream.data_size = a_buffer->data_size;
3229 audio_stream.data = a_buffer->pcm_data;
3231 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
3232 player->audio_stream_render_cb_ex(&audio_stream, player->audio_stream_cb_user_param);
3238 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3240 mm_player_t* player = (mm_player_t*) data;
3245 gint endianness = 0;
3246 guint64 channel_mask = 0;
3247 void *a_data = NULL;
3249 mm_player_audio_stream_buff_t *a_buffer = NULL;
3250 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3254 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb_ex);
3256 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3257 a_data = mapinfo.data;
3258 a_size = mapinfo.size;
3260 GstCaps *caps = gst_pad_get_current_caps(pad);
3261 GstStructure *structure = gst_caps_get_structure(caps, 0);
3263 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
3264 gst_structure_get_int(structure, "rate", &rate);
3265 gst_structure_get_int(structure, "channels", &channel);
3266 gst_structure_get_int(structure, "depth", &depth);
3267 gst_structure_get_int(structure, "endianness", &endianness);
3268 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
3269 gst_caps_unref(GST_CAPS(caps));
3271 /* In case of the sync is false, use buffer list. *
3272 * The num of buffer list depends on the num of audio channels */
3273 if (player->audio_stream_buff_list) {
3274 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
3275 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
3277 if (channel_mask == tmp->channel_mask) {
3278 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
3279 if (tmp->data_size + a_size < tmp->buff_size) {
3280 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
3281 tmp->data_size += a_size;
3283 /* send data to client */
3284 __mmplayer_audio_stream_send_data(player, tmp);
3286 if (a_size > tmp->buff_size) {
3287 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
3288 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
3289 if (tmp->pcm_data == NULL) {
3290 LOGE("failed to realloc data.");
3293 tmp->buff_size = a_size;
3295 memset(tmp->pcm_data, 0x00, tmp->buff_size);
3296 memcpy(tmp->pcm_data, a_data, a_size);
3297 tmp->data_size = a_size;
3302 LOGE("data is empty in list.");
3308 /* create new audio stream data */
3309 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
3310 if (a_buffer == NULL) {
3311 LOGE("failed to alloc data.");
3314 a_buffer->bitrate = rate;
3315 a_buffer->channel = channel;
3316 a_buffer->depth = depth;
3317 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
3318 a_buffer->channel_mask = channel_mask;
3319 a_buffer->data_size = a_size;
3321 if (!player->audio_stream_sink_sync) {
3322 /* If sync is FALSE, use buffer list to reduce the IPC. */
3323 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
3324 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
3325 if (a_buffer->pcm_data == NULL) {
3326 LOGE("failed to alloc data.");
3330 memcpy(a_buffer->pcm_data, a_data, a_size);
3331 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
3332 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
3334 /* If sync is TRUE, send data directly. */
3335 a_buffer->pcm_data = a_data;
3336 __mmplayer_audio_stream_send_data(player, a_buffer);
3341 gst_buffer_unmap(buffer, &mapinfo);
3346 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
3348 mm_player_t* player = (mm_player_t*)data;
3349 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
3350 GstPad* sinkpad = NULL;
3351 GstElement *queue = NULL, *sink = NULL;
3354 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
3356 queue = gst_element_factory_make("queue", NULL);
3357 if (queue == NULL) {
3358 LOGD("fail make queue\n");
3362 sink = gst_element_factory_make("fakesink", NULL);
3364 LOGD("fail make fakesink\n");
3368 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
3370 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
3371 LOGW("failed to link queue & sink\n");
3375 sinkpad = gst_element_get_static_pad(queue, "sink");
3377 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
3378 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
3382 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
3384 gst_object_unref(sinkpad);
3385 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
3386 g_object_set(sink, "signal-handoffs", TRUE, NULL);
3388 gst_element_set_state(sink, GST_STATE_PAUSED);
3389 gst_element_set_state(queue, GST_STATE_PAUSED);
3391 MMPLAYER_SIGNAL_CONNECT(player,
3393 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3395 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3402 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
3404 gst_object_unref(GST_OBJECT(queue));
3408 gst_object_unref(GST_OBJECT(sink));
3412 gst_object_unref(GST_OBJECT(sinkpad));
3419 void __mmplayer_gst_set_audiosink_property(mm_player_t* player, MMHandleType attrs)
3421 #define MAX_PROPS_LEN 128
3422 gint latency_mode = 0;
3423 gchar *stream_type = NULL;
3424 gchar *latency = NULL;
3426 gchar stream_props[MAX_PROPS_LEN] = {0,};
3427 GstStructure *props = NULL;
3430 * It should be set after player creation through attribute.
3431 * But, it can not be changed during playing.
3434 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
3435 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
3438 LOGE("stream_type is null.\n");
3440 if (player->sound.focus_id)
3441 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
3442 stream_type, stream_id, player->sound.focus_id);
3444 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
3445 stream_type, stream_id);
3446 props = gst_structure_from_string(stream_props, NULL);
3447 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
3448 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].\n",
3449 stream_type, stream_id, player->sound.focus_id, stream_props);
3450 gst_structure_free(props);
3453 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
3455 switch (latency_mode) {
3456 case AUDIO_LATENCY_MODE_LOW:
3457 latency = g_strndup("low", 3);
3459 case AUDIO_LATENCY_MODE_MID:
3460 latency = g_strndup("mid", 3);
3462 case AUDIO_LATENCY_MODE_HIGH:
3463 latency = g_strndup("high", 4);
3467 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
3471 LOGD("audiosink property - latency=%s \n", latency);
3479 __mmplayer_gst_create_audio_pipeline(mm_player_t* player)
3481 MMPlayerGstElement* first_element = NULL;
3482 MMPlayerGstElement* audiobin = NULL;
3483 MMHandleType attrs = 0;
3485 GstPad *ghostpad = NULL;
3486 GList* element_bucket = NULL;
3487 gboolean link_audio_sink_now = TRUE;
3493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3496 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
3498 LOGE("failed to allocate memory for audiobin\n");
3499 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3502 attrs = MMPLAYER_GET_ATTRS(player);
3505 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3506 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3507 if (!audiobin[MMPLAYER_A_BIN].gst) {
3508 LOGE("failed to create audiobin\n");
3513 player->pipeline->audiobin = audiobin;
3515 player->set_mode.pcm_extraction = __mmplayer_can_extract_pcm(player);
3517 /* Adding audiotp plugin for reverse trickplay feature */
3518 // MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TP, "audiotp", "audio trickplay", TRUE, player);
3521 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
3523 /* replaygain volume */
3524 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
3525 if (player->sound.rg_enable)
3526 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
3528 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
3531 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
3533 if (player->set_mode.pcm_extraction) {
3534 // pcm extraction only and no sound output
3535 if (player->audio_stream_render_cb_ex) {
3536 char *caps_str = NULL;
3537 GstCaps* caps = NULL;
3538 gchar *format = NULL;
3541 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3543 mm_attrs_get_string_by_name(player->attrs, "pcm_audioformat", &format);
3545 LOGD("contents : format: %s samplerate : %d pcm_channel: %d", format, player->pcm_samplerate, player->pcm_channel);
3547 caps = gst_caps_new_simple("audio/x-raw",
3548 "format", G_TYPE_STRING, format,
3549 "rate", G_TYPE_INT, player->pcm_samplerate,
3550 "channels", G_TYPE_INT, player->pcm_channel,
3552 caps_str = gst_caps_to_string(caps);
3553 LOGD("new caps : %s\n", caps_str);
3555 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3558 gst_caps_unref(caps);
3559 MMPLAYER_FREEIF(caps_str);
3561 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
3563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3564 /* raw pad handling signal */
3565 MMPLAYER_SIGNAL_CONNECT(player,
3566 (audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
3567 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
3568 G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), player);
3570 int dst_samplerate = 0;
3571 int dst_channels = 0;
3573 char *caps_str = NULL;
3574 GstCaps* caps = NULL;
3576 /* get conf. values */
3577 mm_attrs_multiple_get(player->attrs,
3579 "pcm_extraction_samplerate", &dst_samplerate,
3580 "pcm_extraction_channels", &dst_channels,
3581 "pcm_extraction_depth", &dst_depth,
3585 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
3586 caps = gst_caps_new_simple("audio/x-raw",
3587 "rate", G_TYPE_INT, dst_samplerate,
3588 "channels", G_TYPE_INT, dst_channels,
3589 "depth", G_TYPE_INT, dst_depth,
3591 caps_str = gst_caps_to_string(caps);
3592 LOGD("new caps : %s\n", caps_str);
3594 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3597 gst_caps_unref(caps);
3598 MMPLAYER_FREEIF(caps_str);
3601 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "fakesink", TRUE, player);
3604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", FALSE, NULL);
3608 //GstCaps* caps = NULL;
3611 /* for logical volume control */
3612 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
3613 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
3615 if (player->sound.mute) {
3616 LOGD("mute enabled\n");
3617 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
3622 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audiocapsfilter", TRUE, player);
3623 caps = gst_caps_from_string("audio/x-raw-int, "
3624 "endianness = (int) LITTLE_ENDIAN, "
3625 "signed = (boolean) true, "
3626 "width = (int) 16, "
3627 "depth = (int) 16");
3628 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
3629 gst_caps_unref(caps);
3632 /* check if multi-channels */
3633 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
3634 GstPad *srcpad = NULL;
3635 GstCaps *caps = NULL;
3637 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
3638 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
3639 //MMPLAYER_LOG_GST_CAPS_TYPE(caps);
3640 GstStructure *str = gst_caps_get_structure(caps, 0);
3642 gst_structure_get_int(str, "channels", &channels);
3643 gst_caps_unref(caps);
3645 gst_object_unref(srcpad);
3649 /* audio effect element. if audio effect is enabled */
3650 if ((strcmp(player->ini.audioeffect_element, ""))
3652 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
3655 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
3657 if ((!player->bypass_audio_effect)
3658 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
3659 if (MM_AUDIO_EFFECT_TYPE_CUSTOM == player->audio_effect_info.effect_type) {
3660 if (!_mmplayer_audio_effect_custom_apply(player))
3661 LOGI("apply audio effect(custom) setting success\n");
3665 if ((strcmp(player->ini.audioeffect_element_custom, ""))
3666 && (player->set_mode.rich_audio))
3667 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
3670 /* create audio sink */
3671 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
3672 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
3673 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
3675 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
3676 if (player->is_360_feature_enabled &&
3677 player->is_content_spherical &&
3679 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
3680 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
3681 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
3683 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
3685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", link_audio_sink_now, player);
3687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", link_audio_sink_now, player);
3688 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
3689 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
3690 gst_caps_unref(acaps);
3692 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", link_audio_sink_now, player);
3693 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
3694 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
3695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
3697 player->is_openal_plugin_used = TRUE;
3699 if (player->video360_yaw_radians <= M_PI &&
3700 player->video360_yaw_radians >= -M_PI &&
3701 player->video360_pitch_radians <= M_PI_2 &&
3702 player->video360_pitch_radians >= -M_PI_2) {
3703 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3704 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3705 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3706 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
3708 "source-orientation-y", player->video360_metadata.init_view_heading,
3709 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
3712 if (player->is_360_feature_enabled && player->is_content_spherical)
3713 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.\n");
3714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", link_audio_sink_now, player);
3718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
3719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
3722 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
3723 (player->videodec_linked && player->ini.use_system_clock)) {
3724 LOGD("system clock will be used.\n");
3725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
3728 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
3729 __mmplayer_gst_set_audiosink_property(player, attrs);
3732 if (audiobin[MMPLAYER_A_SINK].gst) {
3733 GstPad *sink_pad = NULL;
3734 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
3735 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3736 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
3737 gst_object_unref(GST_OBJECT(sink_pad));
3740 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3742 /* adding created elements to bin */
3743 LOGD("adding created elements to bin\n");
3744 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket)) {
3745 LOGE("failed to add elements\n");
3749 /* linking elements in the bucket by added order. */
3750 LOGD("Linking elements in the bucket by added order.\n");
3751 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3752 LOGE("failed to link elements\n");
3756 /* get first element's sinkpad for creating ghostpad */
3757 first_element = (MMPlayerGstElement *)element_bucket->data;
3758 if (!first_element) {
3759 LOGE("failed to get first elem\n");
3763 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3765 LOGE("failed to get pad from first element of audiobin\n");
3769 ghostpad = gst_ghost_pad_new("sink", pad);
3771 LOGE("failed to create ghostpad\n");
3775 if (FALSE == gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3776 LOGE("failed to add ghostpad to audiobin\n");
3780 gst_object_unref(pad);
3782 g_list_free(element_bucket);
3785 return MM_ERROR_NONE;
3789 LOGD("ERROR : releasing audiobin\n");
3792 gst_object_unref(GST_OBJECT(pad));
3795 gst_object_unref(GST_OBJECT(ghostpad));
3798 g_list_free(element_bucket);
3800 /* release element which are not added to bin */
3801 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3802 /* NOTE : skip bin */
3803 if (audiobin[i].gst) {
3804 GstObject* parent = NULL;
3805 parent = gst_element_get_parent(audiobin[i].gst);
3808 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3809 audiobin[i].gst = NULL;
3811 gst_object_unref(GST_OBJECT(parent));
3815 /* release audiobin with it's childs */
3816 if (audiobin[MMPLAYER_A_BIN].gst)
3817 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3819 MMPLAYER_FREEIF(audiobin);
3821 player->pipeline->audiobin = NULL;
3823 return MM_ERROR_PLAYER_INTERNAL;
3826 static GstPadProbeReturn
3827 __mmplayer_audio_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3829 mm_player_t* player = (mm_player_t*) u_data;
3830 GstBuffer *pad_buffer = gst_pad_probe_info_get_buffer(info);
3831 GstMapInfo probe_info = GST_MAP_INFO_INIT;
3833 gst_buffer_map(pad_buffer, &probe_info, GST_MAP_READ);
3835 if (player->audio_stream_cb && probe_info.size && probe_info.data)
3836 player->audio_stream_cb((void *)probe_info.data, probe_info.size, player->audio_stream_cb_user_param);
3838 return GST_PAD_PROBE_OK;
3841 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
3843 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3846 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
3848 int ret = MM_ERROR_NONE;
3850 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3851 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3853 MMPLAYER_VIDEO_BO_LOCK(player);
3855 if (player->video_bo_list) {
3856 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3857 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3858 if (tmp && tmp->bo == bo) {
3860 LOGD("release bo %p", bo);
3861 tbm_bo_unref(tmp->bo);
3862 MMPLAYER_VIDEO_BO_UNLOCK(player);
3863 MMPLAYER_VIDEO_BO_SIGNAL(player);
3868 /* hw codec is running or the list was reset for DRC. */
3869 LOGW("there is no bo list.");
3871 MMPLAYER_VIDEO_BO_UNLOCK(player);
3873 LOGW("failed to find bo %p", bo);
3878 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
3883 MMPLAYER_RETURN_IF_FAIL(player);
3885 MMPLAYER_VIDEO_BO_LOCK(player);
3886 if (player->video_bo_list) {
3887 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3888 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3889 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3892 tbm_bo_unref(tmp->bo);
3896 g_list_free(player->video_bo_list);
3897 player->video_bo_list = NULL;
3899 player->video_bo_size = 0;
3900 MMPLAYER_VIDEO_BO_UNLOCK(player);
3907 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
3910 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3911 gboolean ret = TRUE;
3913 /* check DRC, if it is, destroy the prev bo list to create again */
3914 if (player->video_bo_size != size) {
3915 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3916 __mmplayer_video_stream_destroy_bo_list(player);
3917 player->video_bo_size = size;
3920 MMPLAYER_VIDEO_BO_LOCK(player);
3922 if ((!player->video_bo_list) ||
3923 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3925 /* create bo list */
3927 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3929 if (player->video_bo_list) {
3930 /* if bo list did not created all, try it again. */
3931 idx = g_list_length(player->video_bo_list);
3932 LOGD("bo list exist(len: %d)", idx);
3935 for (; idx < player->ini.num_of_video_bo; idx++) {
3936 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3938 LOGE("Fail to alloc bo_info.");
3941 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3943 LOGE("Fail to tbm_bo_alloc.");
3947 bo_info->using = FALSE;
3948 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3951 /* update video num buffers */
3952 player->video_num_buffers = idx;
3953 if (idx == player->ini.num_of_video_bo)
3954 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3957 MMPLAYER_VIDEO_BO_UNLOCK(player);
3961 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3965 /* get bo from list*/
3966 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3967 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3968 if (tmp && (tmp->using == FALSE)) {
3969 LOGD("found bo %p to use", tmp->bo);
3971 MMPLAYER_VIDEO_BO_UNLOCK(player);
3972 return tbm_bo_ref(tmp->bo);
3976 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3977 MMPLAYER_VIDEO_BO_UNLOCK(player);
3981 if (player->ini.video_bo_timeout <= 0) {
3982 MMPLAYER_VIDEO_BO_WAIT(player);
3984 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3985 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3992 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3994 mm_player_t* player = (mm_player_t*)data;
3996 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3998 /* send prerolled pkt */
3999 player->video_stream_prerolled = FALSE;
4001 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
4003 /* not to send prerolled pkt again */
4004 player->video_stream_prerolled = TRUE;
4008 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4010 mm_player_t* player = (mm_player_t*)data;
4011 GstCaps *caps = NULL;
4012 MMPlayerVideoStreamDataType *stream = NULL;
4013 MMVideoBuffer *video_buffer = NULL;
4014 GstMemory *dataBlock = NULL;
4015 GstMemory *metaBlock = NULL;
4016 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4017 GstStructure *structure = NULL;
4018 const gchar *string_format = NULL;
4019 unsigned int fourcc = 0;
4022 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
4024 if (player->video_stream_prerolled) {
4025 player->video_stream_prerolled = FALSE;
4026 LOGD("skip the prerolled pkt not to send it again");
4030 caps = gst_pad_get_current_caps(pad);
4032 LOGE("Caps is NULL.");
4036 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
4038 /* clear stream data structure */
4039 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
4041 LOGE("failed to alloc mem for video data");
4045 structure = gst_caps_get_structure(caps, 0);
4046 gst_structure_get_int(structure, "width", &(stream->width));
4047 gst_structure_get_int(structure, "height", &(stream->height));
4048 string_format = gst_structure_get_string(structure, "format");
4050 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
4051 stream->format = util_get_pixtype(fourcc);
4052 gst_caps_unref(caps);
4055 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
4058 LOGD("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
4059 GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format);
4062 if (stream->width == 0 || stream->height == 0 || stream->format == MM_PIXEL_FORMAT_INVALID) {
4063 LOGE("Wrong condition!!");
4067 /* set size and timestamp */
4068 dataBlock = gst_buffer_peek_memory(buffer, 0);
4069 stream->length_total = gst_memory_get_sizes(dataBlock, NULL, NULL);
4070 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
4072 /* check zero-copy */
4073 if (player->set_mode.video_zc &&
4074 player->set_mode.media_packet_video_stream &&
4075 gst_buffer_n_memory(buffer) > 1) {
4076 metaBlock = gst_buffer_peek_memory(buffer, 1);
4077 gst_memory_map(metaBlock, &mapinfo, GST_MAP_READ);
4078 video_buffer = (MMVideoBuffer *)mapinfo.data;
4081 if (video_buffer) { /* hw codec */
4083 if (video_buffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
4086 /* copy pointer of tbm bo, stride, elevation */
4087 while (i < MM_VIDEO_BUFFER_PLANE_MAX && video_buffer->handle.bo[i]) {
4088 stream->bo[i] = tbm_bo_ref(video_buffer->handle.bo[i]);
4092 LOGE("Not support video buffer format");
4095 memcpy(stream->stride, video_buffer->stride_width,
4096 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4097 memcpy(stream->elevation, video_buffer->stride_height,
4098 sizeof(int) * MM_VIDEO_BUFFER_PLANE_MAX);
4100 /* will be released, by calling _mm_player_video_stream_internal_buffer_unref() */
4101 stream->internal_buffer = gst_buffer_ref(buffer);
4102 } else { /* sw codec */
4106 int ret = TBM_SURFACE_ERROR_NONE;
4107 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
4108 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
4110 unsigned char *src = NULL;
4111 unsigned char *dest = NULL;
4112 tbm_bo_handle thandle;
4113 tbm_surface_h surface;
4114 tbm_surface_info_s info;
4117 gst_ret = gst_memory_map(dataBlock, &mapinfo, GST_MAP_READWRITE);
4119 LOGE("fail to gst_memory_map");
4124 if (stream->format == MM_PIXEL_FORMAT_I420) {
4125 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
4127 ret = tbm_surface_get_info(surface, &info);
4129 if (ret != TBM_SURFACE_ERROR_NONE) {
4130 tbm_surface_destroy(surface);
4133 tbm_surface_destroy(surface);
4135 src_stride[0] = GST_ROUND_UP_4(stream->width);
4136 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width>>1);
4137 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
4138 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height)>>1));
4139 stream->stride[0] = info.planes[0].stride;
4140 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
4141 stream->stride[1] = info.planes[1].stride;
4142 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
4143 stream->stride[2] = info.planes[2].stride;
4144 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
4145 size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
4146 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
4147 stream->stride[0] = stream->width * 4;
4148 stream->elevation[0] = stream->height;
4149 size = stream->stride[0] * stream->height;
4151 LOGE("Not support format %d", stream->format);
4155 stream->bo[0] = __mmplayer_video_stream_get_bo(player, size);
4156 if (!stream->bo[0]) {
4157 LOGE("Fail to tbm_bo_alloc!!");
4161 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
4162 if (thandle.ptr && mapinfo.data) {
4163 if (stream->format == MM_PIXEL_FORMAT_I420) {
4164 for (i = 0; i < 3; i++) {
4165 src = mapinfo.data + src_offset[i];
4166 dest = thandle.ptr + info.planes[i].offset;
4169 for (j = 0; j < stream->height>>k; j++) {
4170 memcpy(dest, src, stream->width>>k);
4171 src += src_stride[i];
4172 dest += stream->stride[i];
4175 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
4176 memcpy(thandle.ptr, mapinfo.data, size);
4178 LOGE("Not support format %d", stream->format);
4182 LOGE("data pointer is wrong. dest : %p, src : %p",
4183 thandle.ptr, mapinfo.data);
4186 tbm_bo_unmap(stream->bo[0]);
4189 if (player->video_stream_cb) { /* This has been already checked at the entry */
4190 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
4191 LOGE("failed to send video stream data.");
4197 gst_memory_unmap(metaBlock, &mapinfo);
4199 gst_memory_unmap(dataBlock, &mapinfo);
4204 LOGE("release video stream resource.");
4207 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
4209 tbm_bo_unref(stream->bo[i]);
4211 gst_memory_unmap(metaBlock, &mapinfo);
4213 /* unref gst buffer */
4214 if (stream->internal_buffer)
4215 gst_buffer_unref(stream->internal_buffer);
4216 } else if (dataBlock) {
4218 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
4219 gst_memory_unmap(dataBlock, &mapinfo);
4227 __mmplayer_gst_create_video_filters(mm_player_t* player, GList** bucket)
4229 gchar* video_csc = "videoconvert"; /* default colorspace converter */
4230 GList* element_bucket = NULL;
4232 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4236 if (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical)) {
4237 LOGD("do not need to add video filters.");
4238 return MM_ERROR_NONE;
4241 /* in case of sw codec except 360 playback,
4242 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
4243 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
4244 LOGD("using video converter: %s", video_csc);
4246 /* set video rotator */
4247 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
4249 *bucket = element_bucket;
4251 return MM_ERROR_NONE;
4253 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
4254 g_list_free(element_bucket);
4258 return MM_ERROR_PLAYER_INTERNAL;
4262 * This function is to create video pipeline.
4264 * @param player [in] handle of player
4265 * caps [in] src caps of decoder
4266 * surface_type [in] surface type for video rendering
4268 * @return This function returns zero on success.
4270 * @see __mmplayer_gst_create_audio_pipeline, __mmplayer_gst_create_midi_pipeline
4274 * - video overlay surface(arm/x86) : tizenwlsink
4277 __mmplayer_gst_create_video_pipeline(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
4281 GList*element_bucket = NULL;
4282 MMPlayerGstElement* first_element = NULL;
4283 MMPlayerGstElement* videobin = NULL;
4284 gchar *videosink_element = NULL;
4288 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4291 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
4293 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4295 player->pipeline->videobin = videobin;
4297 attrs = MMPLAYER_GET_ATTRS(player);
4299 LOGE("cannot get content attribute");
4300 return MM_ERROR_PLAYER_INTERNAL;
4304 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
4305 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
4306 if (!videobin[MMPLAYER_V_BIN].gst) {
4307 LOGE("failed to create videobin");
4311 int enable_video_decoded_cb = 0;
4312 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable_video_decoded_cb);
4314 if (player->is_360_feature_enabled && player->is_content_spherical) {
4315 LOGD("video360 elem will be added.");
4317 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_360, "video360",
4318 "video-360", TRUE, player);
4320 /* Set spatial media metadata and/or user settings to the element.
4322 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4323 "projection-type", player->video360_metadata.projection_type, NULL);
4325 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4326 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
4328 if (player->video360_metadata.full_pano_width_pixels &&
4329 player->video360_metadata.full_pano_height_pixels &&
4330 player->video360_metadata.cropped_area_image_width &&
4331 player->video360_metadata.cropped_area_image_height) {
4332 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4333 "projection-bounds-top", player->video360_metadata.cropped_area_top,
4334 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
4335 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
4336 "projection-bounds-left", player->video360_metadata.cropped_area_left,
4337 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
4338 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
4342 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
4343 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4344 "horizontal-fov", player->video360_horizontal_fov,
4345 "vertical-fov", player->video360_vertical_fov, NULL);
4348 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
4349 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4350 "zoom", 1.0f / player->video360_zoom, NULL);
4353 if (player->video360_yaw_radians <= M_PI &&
4354 player->video360_yaw_radians >= -M_PI &&
4355 player->video360_pitch_radians <= M_PI_2 &&
4356 player->video360_pitch_radians >= -M_PI_2) {
4357 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4358 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
4359 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
4360 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
4361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4362 "pose-yaw", player->video360_metadata.init_view_heading,
4363 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
4366 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
4367 "passthrough", !player->is_video360_enabled, NULL);
4370 /* set video sink */
4371 switch (surface_type) {
4372 case MM_DISPLAY_SURFACE_OVERLAY:
4373 if (__mmplayer_gst_create_video_filters(player, &element_bucket) != MM_ERROR_NONE)
4375 if (strlen(player->ini.videosink_element_overlay) > 0)
4376 videosink_element = player->ini.videosink_element_overlay;
4380 case MM_DISPLAY_SURFACE_NULL:
4381 if (strlen(player->ini.videosink_element_fake) > 0)
4382 videosink_element = player->ini.videosink_element_fake;
4386 case MM_DISPLAY_SURFACE_REMOTE:
4387 if (strlen(player->ini.videosink_element_fake) > 0)
4388 videosink_element = player->ini.videosink_element_fake;
4393 LOGE("unidentified surface type");
4396 LOGD("surface_type %d, selected videosink name: %s", surface_type, videosink_element);
4398 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_element, "videosink", TRUE, player);
4400 /* additional setting for sink plug-in */
4401 switch (surface_type) {
4402 case MM_DISPLAY_SURFACE_OVERLAY:
4404 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
4406 LOGD("selected videosink name: %s", videosink_element);
4408 /* support shard memory with S/W codec on HawkP */
4409 if (strncmp(videosink_element, "tizenwlsink", strlen(videosink_element)) == 0) {
4410 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
4411 "use-tbm", use_tbm, NULL);
4417 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4420 LOGD("disable last-sample");
4421 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4425 if (player->set_mode.media_packet_video_stream) {
4427 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
4429 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
4431 MMPLAYER_SIGNAL_CONNECT(player,
4432 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4433 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4435 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
4438 MMPLAYER_SIGNAL_CONNECT(player,
4439 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4440 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4442 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
4447 case MM_DISPLAY_SURFACE_REMOTE:
4449 if (player->set_mode.media_packet_video_stream) {
4450 LOGE("add data probe at videosink");
4451 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4452 "sync", TRUE, "signal-handoffs", TRUE, NULL);
4454 MMPLAYER_SIGNAL_CONNECT(player,
4455 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4456 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4458 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
4461 MMPLAYER_SIGNAL_CONNECT(player,
4462 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
4463 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4465 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
4470 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
4473 LOGD("disable last-sample");
4474 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
4484 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
4487 if (videobin[MMPLAYER_V_SINK].gst) {
4488 GstPad *sink_pad = NULL;
4489 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
4491 MMPLAYER_SIGNAL_CONNECT(player, sink_pad, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
4492 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), player);
4493 gst_object_unref(GST_OBJECT(sink_pad));
4495 LOGW("failed to get sink pad from videosink\n");
4498 /* store it as it's sink element */
4499 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
4501 /* adding created elements to bin */
4502 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
4503 LOGE("failed to add elements\n");
4507 /* Linking elements in the bucket by added order */
4508 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4509 LOGE("failed to link elements\n");
4513 /* get first element's sinkpad for creating ghostpad */
4515 first_element = (MMPlayerGstElement *)element_bucket->data;
4516 if (!first_element) {
4517 LOGE("failed to get first element from bucket\n");
4521 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
4523 LOGE("failed to get pad from first element\n");
4527 /* create ghostpad */
4528 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
4529 if (FALSE == gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
4530 LOGE("failed to add ghostpad to videobin\n");
4533 gst_object_unref(pad);
4535 /* done. free allocated variables */
4537 g_list_free(element_bucket);
4541 return MM_ERROR_NONE;
4544 LOGE("ERROR : releasing videobin\n");
4546 g_list_free(element_bucket);
4549 gst_object_unref(GST_OBJECT(pad));
4551 /* release videobin with it's childs */
4552 if (videobin[MMPLAYER_V_BIN].gst)
4553 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
4556 MMPLAYER_FREEIF(videobin);
4558 player->pipeline->videobin = NULL;
4560 return MM_ERROR_PLAYER_INTERNAL;
4563 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
4565 GList *element_bucket = NULL;
4566 MMPlayerGstElement *textbin = player->pipeline->textbin;
4568 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
4569 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
4570 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
4571 "signal-handoffs", FALSE,
4574 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
4575 MMPLAYER_SIGNAL_CONNECT(player,
4576 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
4577 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
4579 G_CALLBACK(__mmplayer_update_subtitle),
4582 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE, NULL);
4583 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "signal-handoffs", TRUE, NULL);
4585 if (!player->play_subtitle) {
4586 LOGD("add textbin sink as sink element of whole pipeline.\n");
4587 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
4590 /* adding created elements to bin */
4591 LOGD("adding created elements to bin\n");
4592 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
4593 LOGE("failed to add elements\n");
4597 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
4598 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
4599 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
4601 /* linking elements in the bucket by added order. */
4602 LOGD("Linking elements in the bucket by added order.\n");
4603 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
4604 LOGE("failed to link elements\n");
4608 /* done. free allocated variables */
4609 g_list_free(element_bucket);
4611 if (textbin[MMPLAYER_T_QUEUE].gst) {
4613 GstPad *ghostpad = NULL;
4615 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
4617 LOGE("failed to get sink pad of text queue");
4621 ghostpad = gst_ghost_pad_new("text_sink", pad);
4622 gst_object_unref(pad);
4625 LOGE("failed to create ghostpad of textbin\n");
4629 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
4630 LOGE("failed to add ghostpad to textbin\n");
4631 gst_object_unref(ghostpad);
4636 return MM_ERROR_NONE;
4639 g_list_free(element_bucket);
4641 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
4642 LOGE("remove textbin sink from sink list");
4643 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
4646 /* release element at __mmplayer_gst_create_text_sink_bin */
4647 return MM_ERROR_PLAYER_INTERNAL;
4650 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
4652 MMPlayerGstElement *textbin = NULL;
4653 GList *element_bucket = NULL;
4654 int surface_type = 0;
4659 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4662 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
4664 LOGE("failed to allocate memory for textbin\n");
4665 return MM_ERROR_PLAYER_NO_FREE_SPACE;
4669 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
4670 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
4671 if (!textbin[MMPLAYER_T_BIN].gst) {
4672 LOGE("failed to create textbin\n");
4677 player->pipeline->textbin = textbin;
4680 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
4681 LOGD("surface type for subtitle : %d", surface_type);
4682 switch (surface_type) {
4683 case MM_DISPLAY_SURFACE_OVERLAY:
4684 case MM_DISPLAY_SURFACE_NULL:
4685 case MM_DISPLAY_SURFACE_REMOTE:
4686 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
4687 LOGE("failed to make plain text elements\n");
4698 return MM_ERROR_NONE;
4702 LOGD("ERROR : releasing textbin\n");
4704 g_list_free(element_bucket);
4706 /* release signal */
4707 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4709 /* release element which are not added to bin */
4710 for (i = 1; i < MMPLAYER_T_NUM; i++) {
4711 /* NOTE : skip bin */
4712 if (textbin[i].gst) {
4713 GstObject* parent = NULL;
4714 parent = gst_element_get_parent(textbin[i].gst);
4717 gst_object_unref(GST_OBJECT(textbin[i].gst));
4718 textbin[i].gst = NULL;
4720 gst_object_unref(GST_OBJECT(parent));
4725 /* release textbin with it's childs */
4726 if (textbin[MMPLAYER_T_BIN].gst)
4727 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4729 MMPLAYER_FREEIF(player->pipeline->textbin);
4730 player->pipeline->textbin = NULL;
4733 return MM_ERROR_PLAYER_INTERNAL;
4738 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
4740 MMPlayerGstElement* mainbin = NULL;
4741 MMPlayerGstElement* textbin = NULL;
4742 MMHandleType attrs = 0;
4743 GstElement *subsrc = NULL;
4744 GstElement *subparse = NULL;
4745 gchar *subtitle_uri = NULL;
4746 const gchar *charset = NULL;
4752 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4754 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4756 mainbin = player->pipeline->mainbin;
4758 attrs = MMPLAYER_GET_ATTRS(player);
4760 LOGE("cannot get content attribute\n");
4761 return MM_ERROR_PLAYER_INTERNAL;
4764 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4765 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4766 LOGE("subtitle uri is not proper filepath.\n");
4767 return MM_ERROR_PLAYER_INVALID_URI;
4770 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4771 LOGE("failed to get storage info of subtitle path");
4772 return MM_ERROR_PLAYER_INVALID_URI;
4775 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
4777 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4778 player->subtitle_language_list = NULL;
4779 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4781 /* create the subtitle source */
4782 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4784 LOGE("failed to create filesrc element\n");
4787 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4789 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4790 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4792 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4793 LOGW("failed to add queue\n");
4794 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4795 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4796 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4801 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4803 LOGE("failed to create subparse element\n");
4807 charset = util_get_charset(subtitle_uri);
4809 LOGD("detected charset is %s\n", charset);
4810 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4813 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4814 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4816 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4817 LOGW("failed to add subparse\n");
4818 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4819 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4820 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4824 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4825 LOGW("failed to link subsrc and subparse\n");
4829 player->play_subtitle = TRUE;
4830 player->adjust_subtitle_pos = 0;
4832 LOGD("play subtitle using subtitle file\n");
4834 if (player->pipeline->textbin == NULL) {
4835 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4836 LOGE("failed to create text sink bin. continuing without text\n");
4840 textbin = player->pipeline->textbin;
4842 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4843 LOGW("failed to add textbin\n");
4845 /* release signal */
4846 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4848 /* release textbin with it's childs */
4849 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4850 MMPLAYER_FREEIF(player->pipeline->textbin);
4851 player->pipeline->textbin = textbin = NULL;
4855 LOGD("link text input selector and textbin ghost pad");
4857 player->textsink_linked = 1;
4858 player->external_text_idx = 0;
4859 LOGI("player->textsink_linked set to 1\n");
4861 textbin = player->pipeline->textbin;
4862 LOGD("text bin has been created. reuse it.");
4863 player->external_text_idx = 1;
4866 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4867 LOGW("failed to link subparse and textbin\n");
4871 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4873 LOGE("failed to get sink pad from textsink to probe data");
4877 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4878 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4880 gst_object_unref(pad);
4883 /* create dot. for debugging */
4884 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4887 return MM_ERROR_NONE;
4890 /* release text pipeline resource */
4891 player->textsink_linked = 0;
4893 /* release signal */
4894 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4896 if (player->pipeline->textbin) {
4897 LOGE("remove textbin");
4899 /* release textbin with it's childs */
4900 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4901 MMPLAYER_FREEIF(player->pipeline->textbin);
4902 player->pipeline->textbin = NULL;
4906 /* release subtitle elem */
4907 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4908 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4910 return MM_ERROR_PLAYER_INTERNAL;
4914 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
4916 mm_player_t* player = (mm_player_t*) data;
4917 MMMessageParamType msg = {0, };
4918 GstClockTime duration = 0;
4919 gpointer text = NULL;
4920 guint text_size = 0;
4921 gboolean ret = TRUE;
4922 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4926 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4927 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4929 if (player->is_subtitle_force_drop) {
4930 LOGW("subtitle is dropped forcedly.");
4934 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4935 text = mapinfo.data;
4936 text_size = mapinfo.size;
4937 duration = GST_BUFFER_DURATION(buffer);
4939 if (player->set_mode.subtitle_off) {
4940 LOGD("subtitle is OFF.\n");
4944 if (!text || (text_size == 0)) {
4945 LOGD("There is no subtitle to be displayed.\n");
4949 msg.data = (void *) text;
4950 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4952 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
4954 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4955 gst_buffer_unmap(buffer, &mapinfo);
4962 static GstPadProbeReturn
4963 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4965 mm_player_t *player = (mm_player_t *) u_data;
4966 GstClockTime cur_timestamp = 0;
4967 gint64 adjusted_timestamp = 0;
4968 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4970 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4972 if (player->set_mode.subtitle_off) {
4973 LOGD("subtitle is OFF.\n");
4977 if (player->adjust_subtitle_pos == 0) {
4978 LOGD("nothing to do");
4982 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4983 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4985 if (adjusted_timestamp < 0) {
4986 LOGD("adjusted_timestamp under zero");
4991 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4992 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4993 GST_TIME_ARGS(cur_timestamp),
4994 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4996 return GST_PAD_PROBE_OK;
4998 static int __gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
5002 /* check player and subtitlebin are created */
5003 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5004 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
5006 if (position == 0) {
5007 LOGD("nothing to do\n");
5009 return MM_ERROR_NONE;
5013 case MM_PLAYER_POS_FORMAT_TIME:
5015 /* check current postion */
5016 player->adjust_subtitle_pos = position;
5018 LOGD("save adjust_subtitle_pos in player") ;
5024 LOGW("invalid format.\n");
5026 return MM_ERROR_INVALID_ARGUMENT;
5032 return MM_ERROR_NONE;
5036 __gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer user_data)
5038 GstElement *appsrc = element;
5039 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
5040 GstBuffer *buffer = NULL;
5041 GstFlowReturn ret = GST_FLOW_OK;
5044 MMPLAYER_RETURN_IF_FAIL(element);
5045 MMPLAYER_RETURN_IF_FAIL(buf);
5047 buffer = gst_buffer_new();
5049 if (buf->offset >= buf->len) {
5050 LOGD("call eos appsrc\n");
5051 g_signal_emit_by_name(appsrc, "end-of-stream", &ret);
5055 if (buf->len - buf->offset < size)
5056 len = buf->len - buf->offset;
5058 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, (guint8 *)(buf->buf + buf->offset), len, 0, len, NULL, NULL));
5059 GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset;
5060 GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len);
5062 //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len);
5063 g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
5069 __gst_appsrc_seek_data_mem(GstElement *element, guint64 size, gpointer user_data)
5071 MMPlayerInputBuffer *buf = (MMPlayerInputBuffer *)user_data;
5073 MMPLAYER_RETURN_VAL_IF_FAIL(buf, FALSE);
5075 buf->offset = (int)size;
5081 __mmplayer_gst_create_decoder(mm_player_t *player,
5082 MMPlayerTrackType track,
5084 enum MainElementID elemId,
5087 gboolean ret = TRUE;
5088 GstPad *sinkpad = NULL;
5092 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5094 player->pipeline->mainbin, FALSE);
5095 MMPLAYER_RETURN_VAL_IF_FAIL((track == MM_PLAYER_TRACK_TYPE_AUDIO || track == MM_PLAYER_TRACK_TYPE_VIDEO), FALSE);
5096 MMPLAYER_RETURN_VAL_IF_FAIL(srcpad, FALSE);
5097 MMPLAYER_RETURN_VAL_IF_FAIL((player->pipeline->mainbin[elemId].gst == NULL), FALSE);
5099 GstElement *decodebin = NULL;
5100 GstCaps *dec_caps = NULL;
5102 /* create decodebin */
5103 decodebin = gst_element_factory_make("decodebin", name);
5106 LOGE("error : fail to create decodebin for %d decoder\n", track);
5111 /* raw pad handling signal */
5112 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5113 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
5115 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5116 before looking for any elements that can handle that stream.*/
5117 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5118 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
5120 /* This signal is emitted when a element is added to the bin.*/
5121 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5122 G_CALLBACK(__mmplayer_gst_element_added), player);
5124 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5125 LOGE("failed to add new decodebin\n");
5130 dec_caps = gst_pad_query_caps(srcpad, NULL);
5132 //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps);
5133 g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL);
5134 gst_caps_unref(dec_caps);
5137 player->pipeline->mainbin[elemId].id = elemId;
5138 player->pipeline->mainbin[elemId].gst = decodebin;
5140 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5142 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5143 LOGW("failed to link [%s:%s] to decoder\n", GST_DEBUG_PAD_NAME(srcpad));
5144 gst_object_unref(GST_OBJECT(decodebin));
5147 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin))
5148 LOGE("failed to sync second level decodebin state with parent\n");
5150 LOGD("Total num of %d tracks = %d \n", track, player->selector[track].total_track_num);
5154 gst_object_unref(GST_OBJECT(sinkpad));
5163 * This function is to create audio or video pipeline for playing.
5165 * @param player [in] handle of player
5167 * @return This function returns zero on success.
5172 __mmplayer_gst_create_pipeline(mm_player_t* player)
5175 MMPlayerGstElement *mainbin = NULL;
5176 MMHandleType attrs = 0;
5177 GstElement* element = NULL;
5178 GstElement* elem_src_audio = NULL;
5179 GstElement* elem_src_subtitle = NULL;
5180 GstElement* es_video_queue = NULL;
5181 GstElement* es_audio_queue = NULL;
5182 GstElement* es_subtitle_queue = NULL;
5183 GList* element_bucket = NULL;
5184 gboolean need_state_holder = TRUE;
5186 #ifdef SW_CODEC_ONLY
5187 int surface_type = 0;
5191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5193 /* get profile attribute */
5194 attrs = MMPLAYER_GET_ATTRS(player);
5196 LOGE("cannot get content attribute\n");
5200 /* create pipeline handles */
5201 if (player->pipeline) {
5202 LOGW("pipeline should be released before create new one\n");
5206 player->video360_metadata.is_spherical = -1;
5207 player->is_openal_plugin_used = FALSE;
5209 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
5210 if (player->pipeline == NULL)
5213 memset(player->pipeline, 0, sizeof(MMPlayerGstPipelineInfo)); /* g_malloc0 did this job already */
5215 /* create mainbin */
5216 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
5217 if (mainbin == NULL)
5220 memset(mainbin, 0, sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM); /* g_malloc0 did this job already */
5222 /* create pipeline */
5223 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
5224 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
5225 if (!mainbin[MMPLAYER_M_PIPE].gst) {
5226 LOGE("failed to create pipeline\n");
5229 player->demux_pad_index = 0;
5230 player->subtitle_language_list = NULL;
5232 player->is_subtitle_force_drop = FALSE;
5233 player->last_multiwin_status = FALSE;
5235 _mmplayer_track_initialize(player);
5236 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5238 /* create source element */
5239 switch (player->profile.uri_type) {
5240 /* rtsp streamming */
5241 case MM_PLAYER_URI_TYPE_URL_RTSP:
5245 element = gst_element_factory_make("rtspsrc", "rtsp source");
5248 LOGE("failed to create streaming source element\n");
5256 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
5258 SECURE_LOGD("user_agent : %s\n", user_agent);
5260 /* setting property to streaming source */
5261 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5263 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
5265 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5266 G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), player);
5267 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5268 G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), player);
5273 case MM_PLAYER_URI_TYPE_URL_HTTP:
5275 gchar *user_agent, *cookies, **cookie_list;
5276 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
5277 user_agent = cookies = NULL;
5279 gint mode = MM_PLAYER_PD_MODE_NONE;
5281 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
5283 player->pd_mode = mode;
5285 LOGD("http playback, PD mode : %d\n", player->pd_mode);
5287 if (!MMPLAYER_IS_HTTP_PD(player)) {
5288 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
5290 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
5293 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
5296 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
5297 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
5299 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
5300 LOGD("get timeout from ini\n");
5301 http_timeout = player->ini.http_timeout;
5305 SECURE_LOGD("location : %s\n", player->profile.uri);
5306 SECURE_LOGD("cookies : %s\n", cookies);
5307 SECURE_LOGD("user_agent : %s\n", user_agent);
5308 LOGD("timeout : %d\n", http_timeout);
5310 /* setting property to streaming source */
5311 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5312 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
5313 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
5315 /* parsing cookies */
5316 if ((cookie_list = util_get_cookie_list((const char*)cookies))) {
5317 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
5318 g_strfreev(cookie_list);
5321 g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL);
5323 if (MMPLAYER_URL_HAS_DASH_SUFFIX(player))
5324 LOGW("it's dash. and it's still experimental feature.");
5326 // progressive download
5327 gchar* location = NULL;
5329 if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5332 mm_attrs_get_string_by_name(attrs, "pd_location", &path);
5334 MMPLAYER_FREEIF(player->pd_file_save_path);
5336 LOGD("PD Location : %s\n", path);
5339 if (!util_get_storage_info(path, &player->storage_info[MMPLAYER_PATH_VOD])) {
5340 LOGE("failed to get storage info");
5343 player->pd_file_save_path = g_strdup(path);
5345 LOGE("can't find pd location so, it should be set \n");
5350 element = gst_element_factory_make("pdpushsrc", "PD pushsrc");
5352 LOGE("failed to create PD push source element[%s].\n", "pdpushsrc");
5356 if (player->pd_mode == MM_PLAYER_PD_MODE_URI)
5357 g_object_set(G_OBJECT(element), "location", player->pd_file_save_path, NULL);
5359 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5360 g_object_get(element, "location", &location, NULL);
5361 LOGD("PD_LOCATION [%s].\n", location);
5369 case MM_PLAYER_URI_TYPE_FILE:
5371 LOGD("using filesrc for 'file://' handler.\n");
5372 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
5373 LOGE("failed to get storage info");
5377 element = gst_element_factory_make("filesrc", "source");
5379 LOGE("failed to create filesrc\n");
5383 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
5387 case MM_PLAYER_URI_TYPE_SS:
5389 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
5390 element = gst_element_factory_make("souphttpsrc", "http streaming source");
5392 LOGE("failed to create http streaming source element[%s]", player->ini.httpsrc_element);
5396 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
5397 LOGD("get timeout from ini\n");
5398 http_timeout = player->ini.http_timeout;
5401 /* setting property to streaming source */
5402 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
5403 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
5406 case MM_PLAYER_URI_TYPE_MS_BUFF:
5408 LOGD("MS buff src is selected\n");
5410 if (player->v_stream_caps) {
5411 element = gst_element_factory_make("appsrc", "video_appsrc");
5413 LOGF("failed to create video app source element[appsrc].\n");
5417 if (player->a_stream_caps) {
5418 elem_src_audio = gst_element_factory_make("appsrc", "audio_appsrc");
5419 if (!elem_src_audio) {
5420 LOGF("failed to create audio app source element[appsrc].\n");
5424 } else if (player->a_stream_caps) {
5425 /* no video, only audio pipeline*/
5426 element = gst_element_factory_make("appsrc", "audio_appsrc");
5428 LOGF("failed to create audio app source element[appsrc].\n");
5433 if (player->s_stream_caps) {
5434 elem_src_subtitle = gst_element_factory_make("appsrc", "subtitle_appsrc");
5435 if (!elem_src_subtitle) {
5436 LOGF("failed to create subtitle app source element[appsrc].\n");
5441 LOGD("setting app sources properties.\n");
5442 LOGD("location : %s\n", player->profile.uri);
5444 if (player->v_stream_caps && element) {
5445 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
5446 "blocksize", (guint)1048576, /* size of many video frames are larger than default blocksize as 4096 */
5447 "caps", player->v_stream_caps, NULL);
5449 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
5450 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
5451 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO] > 0)
5452 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_VIDEO], NULL);
5454 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
5455 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
5456 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5457 G_CALLBACK(__gst_seek_video_data), player);
5459 if (player->a_stream_caps && elem_src_audio) {
5460 g_object_set(G_OBJECT(elem_src_audio), "format", GST_FORMAT_TIME,
5461 "caps", player->a_stream_caps, NULL);
5463 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5464 g_object_set(G_OBJECT(elem_src_audio), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5465 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5466 g_object_set(G_OBJECT(elem_src_audio), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5468 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
5469 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_audio), GST_APP_STREAM_TYPE_SEEKABLE);
5470 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5471 G_CALLBACK(__gst_seek_audio_data), player);
5473 } else if (player->a_stream_caps && element) {
5474 g_object_set(G_OBJECT(element), "format", GST_FORMAT_TIME,
5475 "caps", player->a_stream_caps, NULL);
5477 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5478 g_object_set(G_OBJECT(element), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5479 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO] > 0)
5480 g_object_set(G_OBJECT(element), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_AUDIO], NULL);
5482 /*Fix Seek External Demuxer: set audio and video appsrc as seekable */
5483 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(element), GST_APP_STREAM_TYPE_SEEKABLE);
5484 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5485 G_CALLBACK(__gst_seek_audio_data), player);
5488 if (player->s_stream_caps && elem_src_subtitle) {
5489 g_object_set(G_OBJECT(elem_src_subtitle), "format", GST_FORMAT_TIME,
5490 "caps", player->s_stream_caps, NULL);
5492 if (player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
5493 g_object_set(G_OBJECT(elem_src_subtitle), "max-bytes", player->media_stream_buffer_max_size[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
5494 if (player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT] > 0)
5495 g_object_set(G_OBJECT(elem_src_subtitle), "min-percent", player->media_stream_buffer_min_percent[MM_PLAYER_STREAM_TYPE_TEXT], NULL);
5497 gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(elem_src_subtitle), GST_APP_STREAM_TYPE_SEEKABLE);
5499 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5500 G_CALLBACK(__gst_seek_subtitle_data), player);
5503 if (player->v_stream_caps && element) {
5504 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5505 G_CALLBACK(__gst_appsrc_feed_video_data), player);
5506 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
5507 G_CALLBACK(__gst_appsrc_enough_video_data), player);
5509 if (player->a_stream_caps && elem_src_audio) {
5510 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5511 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
5512 MMPLAYER_SIGNAL_CONNECT(player, elem_src_audio, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
5513 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
5515 } else if (player->a_stream_caps && element) {
5516 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5517 G_CALLBACK(__gst_appsrc_feed_audio_data), player);
5518 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data",
5519 G_CALLBACK(__gst_appsrc_enough_audio_data), player);
5522 if (player->s_stream_caps && elem_src_subtitle)
5523 MMPLAYER_SIGNAL_CONNECT(player, elem_src_subtitle, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5524 G_CALLBACK(__gst_appsrc_feed_subtitle_data), player);
5526 need_state_holder = FALSE;
5528 mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE);
5529 if (mmf_attrs_commit(attrs)) /* return -1 if error */
5530 LOGE("failed to commit\n");
5534 case MM_PLAYER_URI_TYPE_MEM:
5536 guint64 stream_type = GST_APP_STREAM_TYPE_RANDOM_ACCESS;
5538 LOGD("mem src is selected\n");
5540 element = gst_element_factory_make("appsrc", "mem-source");
5542 LOGE("failed to create appsrc element\n");
5546 g_object_set(element, "stream-type", stream_type, NULL);
5547 g_object_set(element, "size", player->profile.input_mem.len, NULL);
5548 g_object_set(element, "blocksize", (guint64)20480, NULL);
5550 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data",
5551 G_CALLBACK(__gst_appsrc_seek_data_mem), &player->profile.input_mem);
5552 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data",
5553 G_CALLBACK(__gst_appsrc_feed_data_mem), &player->profile.input_mem);
5556 case MM_PLAYER_URI_TYPE_URL:
5559 case MM_PLAYER_URI_TYPE_TEMP:
5562 case MM_PLAYER_URI_TYPE_NONE:
5567 /* check source element is OK */
5569 LOGE("no source element was created.\n");
5573 /* take source element */
5574 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
5575 mainbin[MMPLAYER_M_SRC].gst = element;
5576 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SRC]);
5578 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5579 player->streamer = __mm_player_streaming_create();
5580 __mm_player_streaming_initialize(player->streamer);
5583 if (MMPLAYER_IS_HTTP_PD(player)) {
5584 gint pre_buffering_time = player->streamer->buffering_req.prebuffer_time;
5586 LOGD("Picked queue2 element(pre buffer : %d ms)....\n", pre_buffering_time);
5587 element = gst_element_factory_make("queue2", "queue2");
5589 LOGE("failed to create http streaming buffer element\n");
5594 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5595 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element;
5596 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_MUXED_S_BUFFER]);
5598 pre_buffering_time = (pre_buffering_time > 0) ? (pre_buffering_time) : (player->ini.http_buffering_time);
5600 player->streamer->is_pd_mode = TRUE;
5602 __mm_player_streaming_set_queue2(player->streamer,
5605 player->ini.http_max_size_bytes, // + PLAYER_PD_EXT_MAX_SIZE_BYTE,
5608 player->ini.http_buffering_limit,
5609 MUXED_BUFFER_TYPE_MEM_QUEUE,
5613 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5614 if (player->v_stream_caps) {
5615 es_video_queue = gst_element_factory_make("queue2", "video_queue");
5616 if (!es_video_queue) {
5617 LOGE("create es_video_queue for es player failed\n");
5620 g_object_set(G_OBJECT(es_video_queue), "max-size-buffers", 2, NULL);
5621 mainbin[MMPLAYER_M_V_BUFFER].id = MMPLAYER_M_V_BUFFER;
5622 mainbin[MMPLAYER_M_V_BUFFER].gst = es_video_queue;
5623 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_V_BUFFER]);
5625 /* Adding audio appsrc to bucket */
5626 if (player->a_stream_caps && elem_src_audio) {
5627 mainbin[MMPLAYER_M_2ND_SRC].id = MMPLAYER_M_2ND_SRC;
5628 mainbin[MMPLAYER_M_2ND_SRC].gst = elem_src_audio;
5629 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_2ND_SRC]);
5631 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
5632 if (!es_audio_queue) {
5633 LOGE("create es_audio_queue for es player failed\n");
5636 g_object_set(G_OBJECT(es_audio_queue), "max-size-buffers", 2, NULL);
5638 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
5639 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
5640 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
5642 } else if (player->a_stream_caps) {
5643 /* Only audio stream, no video */
5644 es_audio_queue = gst_element_factory_make("queue2", "audio_queue");
5645 if (!es_audio_queue) {
5646 LOGE("create es_audio_queue for es player failed\n");
5649 mainbin[MMPLAYER_M_A_BUFFER].id = MMPLAYER_M_A_BUFFER;
5650 mainbin[MMPLAYER_M_A_BUFFER].gst = es_audio_queue;
5651 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_A_BUFFER]);
5654 if (player->s_stream_caps && elem_src_subtitle) {
5655 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
5656 mainbin[MMPLAYER_M_SUBSRC].gst = elem_src_subtitle;
5657 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_SUBSRC]);
5659 es_subtitle_queue = gst_element_factory_make("queue2", "subtitle_queue");
5660 if (!es_subtitle_queue) {
5661 LOGE("create es_subtitle_queue for es player failed\n");
5664 mainbin[MMPLAYER_M_S_BUFFER].id = MMPLAYER_M_V_BUFFER;
5665 mainbin[MMPLAYER_M_S_BUFFER].gst = es_subtitle_queue;
5666 element_bucket = g_list_append(element_bucket, &mainbin[MMPLAYER_M_S_BUFFER]);
5670 /* create autoplugging element if src element is not a rtsp src */
5671 if ((player->profile.uri_type != MM_PLAYER_URI_TYPE_URL_RTSP) &&
5672 (player->profile.uri_type != MM_PLAYER_URI_TYPE_MS_BUFF)) {
5674 enum MainElementID elemId = MMPLAYER_M_NUM;
5676 if (((MMPLAYER_IS_HTTP_PD(player)) ||
5677 (!MMPLAYER_IS_HTTP_STREAMING(player)))) {
5678 elemId = MMPLAYER_M_AUTOPLUG;
5679 element = __mmplayer_create_decodebin(player);
5681 /* default size of mq in decodebin is 2M
5682 * but it can cause blocking issue during seeking depends on content. */
5683 g_object_set(G_OBJECT(element), "max-size-bytes", (5*1024*1024), NULL);
5685 need_state_holder = FALSE;
5687 elemId = MMPLAYER_M_TYPEFIND;
5688 element = gst_element_factory_make("typefind", "typefinder");
5689 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
5690 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
5693 /* check autoplug element is OK */
5695 LOGE("can not create element(%d)\n", elemId);
5699 mainbin[elemId].id = elemId;
5700 mainbin[elemId].gst = element;
5702 element_bucket = g_list_append(element_bucket, &mainbin[elemId]);
5705 /* add elements to pipeline */
5706 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) {
5707 LOGE("Failed to add elements to pipeline\n");
5712 /* linking elements in the bucket by added order. */
5713 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
5714 LOGE("Failed to link some elements\n");
5719 /* create fakesink element for keeping the pipeline state PAUSED. if needed */
5720 if (need_state_holder) {
5722 mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK;
5723 mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder");
5725 if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) {
5726 LOGE("fakesink element could not be created\n");
5729 GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK);
5731 /* take ownership of fakesink. we are reusing it */
5732 gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst);
5735 if (FALSE == gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst),
5736 mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) {
5737 LOGE("failed to add fakesink to bin\n");
5742 /* now we have completed mainbin. take it */
5743 player->pipeline->mainbin = mainbin;
5745 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5746 GstPad *srcpad = NULL;
5748 if (mainbin[MMPLAYER_M_V_BUFFER].gst) {
5749 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_V_BUFFER].gst, "src");
5751 __mmplayer_gst_create_decoder(player,
5752 MM_PLAYER_TRACK_TYPE_VIDEO,
5754 MMPLAYER_M_AUTOPLUG_V_DEC,
5757 gst_object_unref(GST_OBJECT(srcpad));
5762 if ((player->a_stream_caps) && (mainbin[MMPLAYER_M_A_BUFFER].gst)) {
5763 srcpad = gst_element_get_static_pad(mainbin[MMPLAYER_M_A_BUFFER].gst, "src");
5765 __mmplayer_gst_create_decoder(player,
5766 MM_PLAYER_TRACK_TYPE_AUDIO,
5768 MMPLAYER_M_AUTOPLUG_A_DEC,
5771 gst_object_unref(GST_OBJECT(srcpad));
5776 if (mainbin[MMPLAYER_M_S_BUFFER].gst)
5777 __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
5780 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
5781 if (__mmplayer_check_subtitle(player)) {
5782 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
5783 LOGE("fail to create text pipeline");
5786 /* connect bus callback */
5787 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
5789 LOGE("cannot get bus from pipeline.\n");
5793 player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player);
5795 player->context.thread_default = g_main_context_get_thread_default();
5797 if (player->context.thread_default == NULL) {
5798 player->context.thread_default = g_main_context_default();
5799 LOGD("thread-default context is the global default context");
5801 LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
5803 /* set sync handler to get tag synchronously */
5804 gst_bus_set_sync_handler(bus, __mmplayer_gst_bus_sync_callback, player, NULL);
5807 gst_object_unref(GST_OBJECT(bus));
5808 g_list_free(element_bucket);
5810 /* create gst bus_msb_cb thread */
5811 g_mutex_init(&player->bus_msg_thread_mutex);
5812 g_cond_init(&player->bus_msg_thread_cond);
5813 player->bus_msg_thread_exit = FALSE;
5814 player->bus_msg_thread =
5815 g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
5816 if (!player->bus_msg_thread) {
5817 LOGE("failed to create gst BUS msg thread");
5818 g_mutex_clear(&player->bus_msg_thread_mutex);
5819 g_cond_clear(&player->bus_msg_thread_cond);
5825 return MM_ERROR_NONE;
5828 __mmplayer_gst_destroy_pipeline(player);
5829 g_list_free(element_bucket);
5832 /* release element which are not added to bin */
5833 for (i = 1; i < MMPLAYER_M_NUM; i++) {
5834 /* NOTE : skip pipeline */
5835 if (mainbin[i].gst) {
5836 GstObject* parent = NULL;
5837 parent = gst_element_get_parent(mainbin[i].gst);
5840 gst_object_unref(GST_OBJECT(mainbin[i].gst));
5841 mainbin[i].gst = NULL;
5843 gst_object_unref(GST_OBJECT(parent));
5847 /* release pipeline with it's childs */
5848 if (mainbin[MMPLAYER_M_PIPE].gst)
5849 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
5851 MMPLAYER_FREEIF(mainbin);
5854 MMPLAYER_FREEIF(player->pipeline);
5855 return MM_ERROR_PLAYER_INTERNAL;
5859 __mmplayer_reset_gapless_state(mm_player_t* player)
5862 MMPLAYER_RETURN_IF_FAIL(player
5864 && player->pipeline->audiobin
5865 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
5867 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
5874 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
5877 int ret = MM_ERROR_NONE;
5881 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
5883 /* cleanup stuffs */
5884 MMPLAYER_FREEIF(player->type);
5885 player->have_dynamic_pad = FALSE;
5886 player->no_more_pad = FALSE;
5887 player->num_dynamic_pad = 0;
5888 player->demux_pad_index = 0;
5889 player->use_deinterleave = FALSE;
5890 player->max_audio_channels = 0;
5891 player->video_share_api_delta = 0;
5892 player->video_share_clock_delta = 0;
5893 player->video_hub_download_mode = 0;
5895 MMPLAYER_SUBTITLE_INFO_LOCK(player);
5896 player->subtitle_language_list = NULL;
5897 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
5899 __mmplayer_reset_gapless_state(player);
5901 if (player->streamer) {
5902 __mm_player_streaming_deinitialize(player->streamer);
5903 __mm_player_streaming_destroy(player->streamer);
5904 player->streamer = NULL;
5907 /* cleanup unlinked mime type */
5908 MMPLAYER_FREEIF(player->unlinked_audio_mime);
5909 MMPLAYER_FREEIF(player->unlinked_video_mime);
5910 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
5912 /* cleanup running stuffs */
5913 __mmplayer_cancel_eos_timer(player);
5915 /* cleanup gst stuffs */
5916 if (player->pipeline) {
5917 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
5918 GstTagList* tag_list = player->pipeline->tag_list;
5920 /* first we need to disconnect all signal hander */
5921 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
5924 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
5925 MMPlayerGstElement* videobin = player->pipeline->videobin;
5926 MMPlayerGstElement* textbin = player->pipeline->textbin;
5927 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
5928 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
5929 gst_object_unref(bus);
5931 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5932 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
5933 if (ret != MM_ERROR_NONE) {
5934 LOGE("fail to change state to NULL\n");
5935 return MM_ERROR_PLAYER_INTERNAL;
5938 LOGW("succeeded in changing state to NULL\n");
5940 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
5943 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
5944 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
5946 /* free avsysaudiosink
5947 avsysaudiosink should be unref when destory pipeline just after start play with BT.
5948 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
5950 MMPLAYER_FREEIF(audiobin);
5951 MMPLAYER_FREEIF(videobin);
5952 MMPLAYER_FREEIF(textbin);
5953 MMPLAYER_FREEIF(mainbin);
5957 gst_tag_list_free(tag_list);
5959 MMPLAYER_FREEIF(player->pipeline);
5961 MMPLAYER_FREEIF(player->album_art);
5963 if (player->v_stream_caps) {
5964 gst_caps_unref(player->v_stream_caps);
5965 player->v_stream_caps = NULL;
5967 if (player->a_stream_caps) {
5968 gst_caps_unref(player->a_stream_caps);
5969 player->a_stream_caps = NULL;
5972 if (player->s_stream_caps) {
5973 gst_caps_unref(player->s_stream_caps);
5974 player->s_stream_caps = NULL;
5976 _mmplayer_track_destroy(player);
5978 if (player->sink_elements)
5979 g_list_free(player->sink_elements);
5980 player->sink_elements = NULL;
5982 if (player->bufmgr) {
5983 tbm_bufmgr_deinit(player->bufmgr);
5984 player->bufmgr = NULL;
5987 LOGW("finished destroy pipeline\n");
5994 static int __gst_realize(mm_player_t* player)
5997 int ret = MM_ERROR_NONE;
6001 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6003 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
6005 ret = __mmplayer_gst_create_pipeline(player);
6007 LOGE("failed to create pipeline\n");
6011 /* set pipeline state to READY */
6012 /* NOTE : state change to READY must be performed sync. */
6013 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
6014 ret = __mmplayer_gst_set_state(player,
6015 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
6017 if (ret != MM_ERROR_NONE) {
6018 /* return error if failed to set state */
6019 LOGE("failed to set READY state");
6023 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
6025 /* create dot before error-return. for debugging */
6026 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
6033 static int __gst_unrealize(mm_player_t* player)
6035 int ret = MM_ERROR_NONE;
6039 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6041 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
6042 MMPLAYER_PRINT_STATE(player);
6044 /* release miscellaneous information */
6045 __mmplayer_release_misc(player);
6047 /* destroy pipeline */
6048 ret = __mmplayer_gst_destroy_pipeline(player);
6049 if (ret != MM_ERROR_NONE) {
6050 LOGE("failed to destory pipeline\n");
6054 /* release miscellaneous information.
6055 these info needs to be released after pipeline is destroyed. */
6056 __mmplayer_release_misc_post(player);
6058 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
6066 __gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
6071 LOGW("set_message_callback is called with invalid player handle\n");
6072 return MM_ERROR_PLAYER_NOT_INITIALIZED;
6075 player->msg_cb = callback;
6076 player->msg_cb_param = user_param;
6078 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
6082 return MM_ERROR_NONE;
6085 static int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
6087 int ret = MM_ERROR_PLAYER_INVALID_URI;
6092 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
6093 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
6094 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
6096 memset(data, 0, sizeof(MMPlayerParseProfile));
6098 if ((path = strstr(uri, "es_buff://"))) {
6100 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6101 data->uri_type = MM_PLAYER_URI_TYPE_MS_BUFF;
6102 ret = MM_ERROR_NONE;
6104 } else if ((path = strstr(uri, "rtsp://")) || (path = strstr(uri, "rtsps://"))) {
6106 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6107 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6108 ret = MM_ERROR_NONE;
6110 } else if ((path = strstr(uri, "http://")) || (path = strstr(uri, "https://"))) {
6113 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6114 tmp = g_ascii_strdown(uri, strlen(uri));
6116 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
6117 data->uri_type = MM_PLAYER_URI_TYPE_SS;
6119 data->uri_type = MM_PLAYER_URI_TYPE_URL_HTTP;
6121 ret = MM_ERROR_NONE;
6124 } else if ((path = strstr(uri, "rtspu://"))) {
6126 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6127 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6128 ret = MM_ERROR_NONE;
6130 } else if ((path = strstr(uri, "rtspr://"))) {
6131 strncpy(data->uri, path, MM_MAX_URL_LEN-1);
6132 char *separater = strstr(path, "*");
6136 char *urgent = separater + strlen("*");
6138 if ((urgent_len = strlen(urgent))) {
6139 data->uri[strlen(path) - urgent_len - strlen("*")] = '\0';
6140 strncpy(data->urgent, urgent, MM_MAX_FILENAME_LEN-1);
6141 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6142 ret = MM_ERROR_NONE;
6145 } else if ((path = strstr(uri, "mms://"))) {
6147 strncpy(data->uri, uri, MM_MAX_URL_LEN-1);
6148 data->uri_type = MM_PLAYER_URI_TYPE_URL_MMS;
6149 ret = MM_ERROR_NONE;
6151 } else if ((path = strstr(uri, "mem://"))) {
6154 char *buffer = NULL;
6155 char *seperator = strchr(path, ',');
6156 char ext[100] = {0,}, size[100] = {0,};
6159 if ((buffer = strstr(path, "ext="))) {
6160 buffer += strlen("ext=");
6162 if (strlen(buffer)) {
6163 strncpy(ext, buffer, 99);
6165 if ((seperator = strchr(ext, ','))
6166 || (seperator = strchr(ext, ' '))
6167 || (seperator = strchr(ext, '\0'))) {
6168 seperator[0] = '\0';
6173 if ((buffer = strstr(path, "size="))) {
6174 buffer += strlen("size=");
6176 if (strlen(buffer) > 0) {
6177 strncpy(size, buffer, 99);
6179 if ((seperator = strchr(size, ','))
6180 || (seperator = strchr(size, ' '))
6181 || (seperator = strchr(size, '\0'))) {
6182 seperator[0] = '\0';
6185 mem_size = atoi(size);
6190 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
6191 if (mem_size && param) {
6192 if (data->input_mem.buf)
6193 free(data->input_mem.buf);
6194 data->input_mem.buf = malloc(mem_size);
6196 if (data->input_mem.buf) {
6197 memcpy(data->input_mem.buf, param, mem_size);
6198 data->input_mem.len = mem_size;
6199 ret = MM_ERROR_NONE;
6201 LOGE("failed to alloc mem %d", mem_size);
6202 ret = MM_ERROR_PLAYER_INTERNAL;
6205 data->input_mem.offset = 0;
6206 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
6210 gchar *location = NULL;
6213 if ((path = strstr(uri, "file://"))) {
6215 location = g_filename_from_uri(uri, NULL, &err);
6217 if (!location || (err != NULL)) {
6218 LOGE("Invalid URI '%s' for filesrc: %s", path,
6219 (err != NULL) ? err->message : "unknown error");
6221 if (err) g_error_free(err);
6222 if (location) g_free(location);
6224 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
6228 LOGD("path from uri: %s", location);
6231 path = (location != NULL) ? (location) : ((char*)uri);
6232 int file_stat = MM_ERROR_NONE;
6234 file_stat = util_exist_file_path(path);
6236 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
6237 if (file_stat == MM_ERROR_NONE) {
6238 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
6240 if (util_is_sdp_file(path)) {
6241 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
6242 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
6244 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
6246 ret = MM_ERROR_NONE;
6247 } else if (file_stat == MM_ERROR_PLAYER_PERMISSION_DENIED) {
6248 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
6250 LOGE("invalid uri, could not play..\n");
6251 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
6254 if (location) g_free(location);
6258 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
6259 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
6260 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
6261 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
6263 /* dump parse result */
6264 SECURE_LOGW("incomming uri : %s\n", uri);
6265 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
6266 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
6274 __mmplayer_can_do_interrupt(mm_player_t *player)
6276 if (!player || !player->pipeline || !player->attrs) {
6277 LOGW("not initialized");
6281 if (player->set_mode.pcm_extraction) {
6282 LOGW("leave right now, %d", player->set_mode.pcm_extraction);
6286 /* check if seeking */
6287 if (player->seek_state != MMPLAYER_SEEK_NONE) {
6288 MMMessageParamType msg_param;
6289 memset(&msg_param, 0, sizeof(MMMessageParamType));
6290 msg_param.code = MM_ERROR_PLAYER_SEEK;
6291 player->seek_state = MMPLAYER_SEEK_NONE;
6292 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6296 /* check other thread */
6297 if (!MMPLAYER_CMD_TRYLOCK(player)) {
6298 LOGW("locked already, cmd state : %d", player->cmd);
6300 /* check application command */
6301 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
6302 LOGW("playing.. should wait cmd lock then, will be interrupted");
6304 /* lock will be released at mrp_resource_release_cb() */
6305 MMPLAYER_CMD_LOCK(player);
6308 LOGW("nothing to do");
6311 LOGW("can interrupt immediately");
6315 FAILED: /* with CMD UNLOCKED */
6318 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
6323 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
6326 mm_player_t *player = NULL;
6330 if (user_data == NULL) {
6331 LOGE("- user_data is null\n");
6334 player = (mm_player_t *)user_data;
6336 /* do something to release resource here.
6337 * player stop and interrupt forwarding */
6338 if (!__mmplayer_can_do_interrupt(player)) {
6339 LOGW("no need to interrupt, so leave");
6341 MMMessageParamType msg = {0, };
6344 player->interrupted_by_resource = TRUE;
6346 /* get last play position */
6347 if (_mmplayer_get_position((MMHandleType)player, MM_PLAYER_POS_FORMAT_TIME, &pos) != MM_ERROR_NONE) {
6348 LOGW("failed to get play position.");
6350 msg.union_type = MM_MSG_UNION_TIME;
6351 msg.time.elapsed = pos;
6352 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
6354 LOGD("video resource conflict so, resource will be freed by unrealizing");
6355 if (_mmplayer_unrealize((MMHandleType)player))
6356 LOGW("failed to unrealize");
6358 /* lock is called in __mmplayer_can_do_interrupt() */
6359 MMPLAYER_CMD_UNLOCK(player);
6362 if (res == player->video_overlay_resource)
6363 player->video_overlay_resource = FALSE;
6365 player->video_decoder_resource = FALSE;
6373 _mmplayer_create_player(MMHandleType handle)
6375 int ret = MM_ERROR_PLAYER_INTERNAL;
6376 bool enabled = false;
6378 mm_player_t* player = MM_PLAYER_CAST(handle);
6382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6384 /* initialize player state */
6385 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
6386 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
6387 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
6388 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
6390 /* check current state */
6391 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
6393 /* construct attributes */
6394 player->attrs = _mmplayer_construct_attribute(handle);
6396 if (!player->attrs) {
6397 LOGE("Failed to construct attributes\n");
6401 /* initialize gstreamer with configured parameter */
6402 if (!__mmplayer_init_gstreamer(player)) {
6403 LOGE("Initializing gstreamer failed\n");
6404 _mmplayer_deconstruct_attribute(handle);
6408 /* create lock. note that g_tread_init() has already called in gst_init() */
6409 g_mutex_init(&player->fsink_lock);
6411 /* create update tag lock */
6412 g_mutex_init(&player->update_tag_lock);
6414 /* create next play mutex */
6415 g_mutex_init(&player->next_play_thread_mutex);
6417 /* create next play cond */
6418 g_cond_init(&player->next_play_thread_cond);
6420 /* create next play thread */
6421 player->next_play_thread =
6422 g_thread_try_new("next_play_thread", __mmplayer_next_play_thread, (gpointer)player, NULL);
6423 if (!player->next_play_thread) {
6424 LOGE("failed to create next play thread");
6425 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
6426 g_mutex_clear(&player->next_play_thread_mutex);
6427 g_cond_clear(&player->next_play_thread_cond);
6431 player->bus_msg_q = g_queue_new();
6432 if (!player->bus_msg_q) {
6433 LOGE("failed to create queue for bus_msg");
6434 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
6438 ret = _mmplayer_initialize_video_capture(player);
6439 if (ret != MM_ERROR_NONE) {
6440 LOGE("failed to initialize video capture\n");
6444 /* initialize resource manager */
6445 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
6446 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
6447 &player->resource_manager)) {
6448 LOGE("failed to initialize resource manager\n");
6452 if (MMPLAYER_IS_HTTP_PD(player)) {
6453 player->pd_downloader = NULL;
6454 player->pd_file_save_path = NULL;
6457 /* create video bo lock and cond */
6458 g_mutex_init(&player->video_bo_mutex);
6459 g_cond_init(&player->video_bo_cond);
6461 /* create media stream callback mutex */
6462 g_mutex_init(&player->media_stream_cb_lock);
6464 /* create subtitle info lock and cond */
6465 g_mutex_init(&player->subtitle_info_mutex);
6466 g_cond_init(&player->subtitle_info_cond);
6468 player->streaming_type = STREAMING_SERVICE_NONE;
6470 /* give default value of audio effect setting */
6471 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
6472 player->sound.rg_enable = false;
6473 player->playback_rate = DEFAULT_PLAYBACK_RATE;
6475 player->play_subtitle = FALSE;
6476 player->use_deinterleave = FALSE;
6477 player->max_audio_channels = 0;
6478 player->video_share_api_delta = 0;
6479 player->video_share_clock_delta = 0;
6480 player->has_closed_caption = FALSE;
6481 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
6482 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
6483 player->pending_resume = FALSE;
6484 if (player->ini.dump_element_keyword[0][0] == '\0')
6485 player->ini.set_dump_element_flag = FALSE;
6487 player->ini.set_dump_element_flag = TRUE;
6489 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
6490 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
6491 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
6493 /* Set video360 settings to their defaults for just-created player.
6496 player->is_360_feature_enabled = FALSE;
6497 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
6498 LOGI("spherical feature info: %d", enabled);
6500 player->is_360_feature_enabled = TRUE;
6502 LOGE("failed to get spherical feature info");
6505 player->is_content_spherical = FALSE;
6506 player->is_video360_enabled = TRUE;
6507 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
6508 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
6509 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
6510 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
6511 player->video360_zoom = 1.0f;
6512 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
6513 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
6515 /* set player state to null */
6516 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
6517 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
6519 return MM_ERROR_NONE;
6523 g_mutex_clear(&player->fsink_lock);
6525 /* free update tag lock */
6526 g_mutex_clear(&player->update_tag_lock);
6528 g_queue_free(player->bus_msg_q);
6530 /* free next play thread */
6531 if (player->next_play_thread) {
6532 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
6533 player->next_play_thread_exit = TRUE;
6534 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
6535 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
6537 g_thread_join(player->next_play_thread);
6538 player->next_play_thread = NULL;
6540 g_mutex_clear(&player->next_play_thread_mutex);
6541 g_cond_clear(&player->next_play_thread_cond);
6544 /* release attributes */
6545 _mmplayer_deconstruct_attribute(handle);
6553 __mmplayer_init_gstreamer(mm_player_t* player)
6555 static gboolean initialized = FALSE;
6556 static const int max_argc = 50;
6558 gchar** argv = NULL;
6559 gchar** argv2 = NULL;
6565 LOGD("gstreamer already initialized.\n");
6570 argc = malloc(sizeof(int));
6571 argv = malloc(sizeof(gchar*) * max_argc);
6572 argv2 = malloc(sizeof(gchar*) * max_argc);
6574 if (!argc || !argv || !argv2)
6577 memset(argv, 0, sizeof(gchar*) * max_argc);
6578 memset(argv2, 0, sizeof(gchar*) * max_argc);
6582 argv[0] = g_strdup("mmplayer");
6585 for (i = 0; i < 5; i++) {
6586 /* FIXIT : num of param is now fixed to 5. make it dynamic */
6587 if (strlen(player->ini.gst_param[i]) > 0) {
6588 argv[*argc] = g_strdup(player->ini.gst_param[i]);
6593 /* we would not do fork for scanning plugins */
6594 argv[*argc] = g_strdup("--gst-disable-registry-fork");
6597 /* check disable registry scan */
6598 if (player->ini.skip_rescan) {
6599 argv[*argc] = g_strdup("--gst-disable-registry-update");
6603 /* check disable segtrap */
6604 if (player->ini.disable_segtrap) {
6605 argv[*argc] = g_strdup("--gst-disable-segtrap");
6609 LOGD("initializing gstreamer with following parameter\n");
6610 LOGD("argc : %d\n", *argc);
6613 for (i = 0; i < arg_count; i++) {
6615 LOGD("argv[%d] : %s\n", i, argv2[i]);
6618 /* initializing gstreamer */
6619 if (!gst_init_check(argc, &argv, &err)) {
6620 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
6627 for (i = 0; i < arg_count; i++) {
6628 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
6629 MMPLAYER_FREEIF(argv2[i]);
6632 MMPLAYER_FREEIF(argv);
6633 MMPLAYER_FREEIF(argv2);
6634 MMPLAYER_FREEIF(argc);
6644 for (i = 0; i < arg_count; i++) {
6645 LOGD("free[%d] : %s\n", i, argv2[i]);
6646 MMPLAYER_FREEIF(argv2[i]);
6649 MMPLAYER_FREEIF(argv);
6650 MMPLAYER_FREEIF(argv2);
6651 MMPLAYER_FREEIF(argc);
6657 __mmplayer_destroy_streaming_ext(mm_player_t* player)
6659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6661 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
6662 _mmplayer_destroy_pd_downloader((MMHandleType)player);
6663 MMPLAYER_FREEIF(player->pd_file_save_path);
6666 return MM_ERROR_NONE;
6670 __mmplayer_check_async_state_transition(mm_player_t* player)
6672 GstState element_state = GST_STATE_VOID_PENDING;
6673 GstState element_pending_state = GST_STATE_VOID_PENDING;
6674 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
6675 GstElement * element = NULL;
6676 gboolean async = FALSE;
6678 /* check player handle */
6679 MMPLAYER_RETURN_IF_FAIL(player &&
6681 player->pipeline->mainbin &&
6682 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
6685 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6687 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
6688 LOGD("don't need to check the pipeline state");
6692 MMPLAYER_PRINT_STATE(player);
6694 /* wait for state transition */
6695 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
6696 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
6698 if (ret == GST_STATE_CHANGE_FAILURE) {
6699 LOGE(" [%s] state : %s pending : %s \n",
6700 GST_ELEMENT_NAME(element),
6701 gst_element_state_get_name(element_state),
6702 gst_element_state_get_name(element_pending_state));
6704 /* dump state of all element */
6705 __mmplayer_dump_pipeline_state(player);
6710 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
6715 _mmplayer_destroy(MMHandleType handle)
6717 mm_player_t* player = MM_PLAYER_CAST(handle);
6721 /* check player handle */
6722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6724 /* destroy can called at anytime */
6725 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
6727 /* check async state transition */
6728 __mmplayer_check_async_state_transition(player);
6730 __mmplayer_destroy_streaming_ext(player);
6732 /* release next play thread */
6733 if (player->next_play_thread) {
6734 MMPLAYER_NEXT_PLAY_THREAD_LOCK(player);
6735 player->next_play_thread_exit = TRUE;
6736 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
6737 MMPLAYER_NEXT_PLAY_THREAD_UNLOCK(player);
6739 LOGD("waitting for next play thread exit\n");
6740 g_thread_join(player->next_play_thread);
6741 g_mutex_clear(&player->next_play_thread_mutex);
6742 g_cond_clear(&player->next_play_thread_cond);
6743 LOGD("next play thread released\n");
6746 _mmplayer_release_video_capture(player);
6748 /* de-initialize resource manager */
6749 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
6750 player->resource_manager))
6751 LOGE("failed to deinitialize resource manager\n");
6753 /* release pipeline */
6754 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
6755 LOGE("failed to destory pipeline\n");
6756 return MM_ERROR_PLAYER_INTERNAL;
6759 g_queue_free(player->bus_msg_q);
6761 /* release subtitle info lock and cond */
6762 g_mutex_clear(&player->subtitle_info_mutex);
6763 g_cond_clear(&player->subtitle_info_cond);
6765 __mmplayer_release_dump_list(player->dump_list);
6767 /* release miscellaneous information */
6768 __mmplayer_release_misc(player);
6770 /* release miscellaneous information.
6771 these info needs to be released after pipeline is destroyed. */
6772 __mmplayer_release_misc_post(player);
6774 /* release attributes */
6775 _mmplayer_deconstruct_attribute(handle);
6778 g_mutex_clear(&player->fsink_lock);
6781 g_mutex_clear(&player->update_tag_lock);
6783 /* release video bo lock and cond */
6784 g_mutex_clear(&player->video_bo_mutex);
6785 g_cond_clear(&player->video_bo_cond);
6787 /* release media stream callback lock */
6788 g_mutex_clear(&player->media_stream_cb_lock);
6792 return MM_ERROR_NONE;
6796 __mmplayer_realize_streaming_ext(mm_player_t* player)
6798 int ret = MM_ERROR_NONE;
6801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6803 if (MMPLAYER_IS_HTTP_PD(player)) {
6804 gboolean bret = FALSE;
6806 player->pd_downloader = _mmplayer_create_pd_downloader();
6807 if (!player->pd_downloader) {
6808 LOGE("Unable to create PD Downloader...");
6809 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
6812 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
6814 if (FALSE == bret) {
6815 LOGE("Unable to create PD Downloader...");
6816 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
6825 _mmplayer_realize(MMHandleType hplayer)
6827 mm_player_t* player = (mm_player_t*)hplayer;
6830 MMHandleType attrs = 0;
6831 int ret = MM_ERROR_NONE;
6835 /* check player handle */
6836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
6838 /* check current state */
6839 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
6841 attrs = MMPLAYER_GET_ATTRS(player);
6843 LOGE("fail to get attributes.\n");
6844 return MM_ERROR_PLAYER_INTERNAL;
6846 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6847 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
6849 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
6850 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
6852 if (ret != MM_ERROR_NONE) {
6853 LOGE("failed to parse profile\n");
6858 if (uri && (strstr(uri, "es_buff://"))) {
6859 if (strstr(uri, "es_buff://push_mode"))
6860 player->es_player_push_mode = TRUE;
6862 player->es_player_push_mode = FALSE;
6865 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
6866 LOGW("mms protocol is not supported format.\n");
6867 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6870 if (MMPLAYER_IS_STREAMING(player))
6871 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
6873 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
6875 player->smooth_streaming = FALSE;
6876 player->videodec_linked = 0;
6877 player->videosink_linked = 0;
6878 player->audiodec_linked = 0;
6879 player->audiosink_linked = 0;
6880 player->textsink_linked = 0;
6881 player->is_external_subtitle_present = FALSE;
6882 player->is_external_subtitle_added_now = FALSE;
6883 /* set the subtitle ON default */
6884 player->is_subtitle_off = FALSE;
6886 /* realize pipeline */
6887 ret = __gst_realize(player);
6888 if (ret != MM_ERROR_NONE)
6889 LOGE("fail to realize the player.\n");
6891 ret = __mmplayer_realize_streaming_ext(player);
6893 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
6901 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
6904 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6906 /* destroy can called at anytime */
6907 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
6908 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
6911 return MM_ERROR_NONE;
6915 _mmplayer_unrealize(MMHandleType hplayer)
6917 mm_player_t* player = (mm_player_t*)hplayer;
6918 int ret = MM_ERROR_NONE;
6922 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6924 MMPLAYER_CMD_UNLOCK(player);
6925 /* destroy the gst bus msg thread which is created during realize.
6926 this funct have to be called before getting cmd lock. */
6927 __mmplayer_bus_msg_thread_destroy(player);
6928 MMPLAYER_CMD_LOCK(player);
6930 /* check current state */
6931 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
6933 /* check async state transition */
6934 __mmplayer_check_async_state_transition(player);
6936 __mmplayer_unrealize_streaming_ext(player);
6938 /* unrealize pipeline */
6939 ret = __gst_unrealize(player);
6941 /* set asm stop if success */
6942 if (MM_ERROR_NONE == ret) {
6943 if (!player->interrupted_by_resource) {
6944 if (player->video_decoder_resource != NULL) {
6945 ret = mm_resource_manager_mark_for_release(player->resource_manager,
6946 player->video_decoder_resource);
6947 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
6948 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
6950 player->video_decoder_resource = NULL;
6953 if (player->video_overlay_resource != NULL) {
6954 ret = mm_resource_manager_mark_for_release(player->resource_manager,
6955 player->video_overlay_resource);
6956 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
6957 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
6959 player->video_overlay_resource = NULL;
6962 ret = mm_resource_manager_commit(player->resource_manager);
6963 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
6964 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
6967 LOGE("failed and don't change asm state to stop");
6975 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
6977 mm_player_t* player = (mm_player_t*)hplayer;
6979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6981 return __gst_set_message_callback(player, callback, user_param);
6985 _mmplayer_get_state(MMHandleType hplayer, int* state)
6987 mm_player_t *player = (mm_player_t*)hplayer;
6989 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
6991 *state = MMPLAYER_CURRENT_STATE(player);
6993 return MM_ERROR_NONE;
6998 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
7000 mm_player_t* player = (mm_player_t*) hplayer;
7001 GstElement* vol_element = NULL;
7006 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7008 LOGD("volume [L]=%f:[R]=%f\n",
7009 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
7011 /* invalid factor range or not */
7012 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
7013 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
7014 LOGE("Invalid factor!(valid factor:0~1.0)\n");
7015 return MM_ERROR_INVALID_ARGUMENT;
7019 /* not support to set other value into each channel */
7020 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
7021 return MM_ERROR_INVALID_ARGUMENT;
7023 /* Save volume to handle. Currently the first array element will be saved. */
7024 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
7026 /* check pipeline handle */
7027 if (!player->pipeline || !player->pipeline->audiobin) {
7028 LOGD("audiobin is not created yet\n");
7029 LOGD("but, current stored volume will be set when it's created.\n");
7031 /* NOTE : stored volume will be used in create_audiobin
7032 * returning MM_ERROR_NONE here makes application to able to
7033 * set volume at anytime.
7035 return MM_ERROR_NONE;
7038 /* setting volume to volume element */
7039 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7042 LOGD("volume is set [%f]\n", player->sound.volume);
7043 g_object_set(vol_element, "volume", player->sound.volume, NULL);
7048 return MM_ERROR_NONE;
7053 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
7055 mm_player_t* player = (mm_player_t*) hplayer;
7060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7061 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
7063 /* returning stored volume */
7064 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
7065 volume->level[i] = player->sound.volume;
7069 return MM_ERROR_NONE;
7073 _mmplayer_set_mute(MMHandleType hplayer, int mute)
7075 mm_player_t* player = (mm_player_t*) hplayer;
7076 GstElement* vol_element = NULL;
7080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7082 /* mute value shoud 0 or 1 */
7083 if (mute != 0 && mute != 1) {
7084 LOGE("bad mute value\n");
7086 /* FIXIT : definitly, we need _BAD_PARAM error code */
7087 return MM_ERROR_INVALID_ARGUMENT;
7090 player->sound.mute = mute;
7092 /* just hold mute value if pipeline is not ready */
7093 if (!player->pipeline || !player->pipeline->audiobin) {
7094 LOGD("pipeline is not ready. holding mute value\n");
7095 return MM_ERROR_NONE;
7098 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
7100 /* NOTE : volume will only created when the bt is enabled */
7102 LOGD("mute : %d\n", mute);
7103 g_object_set(vol_element, "mute", mute, NULL);
7105 LOGD("volume elemnet is not created. using volume in audiosink\n");
7109 return MM_ERROR_NONE;
7113 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
7115 mm_player_t* player = (mm_player_t*) hplayer;
7119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7120 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
7122 /* just hold mute value if pipeline is not ready */
7123 if (!player->pipeline || !player->pipeline->audiobin) {
7124 LOGD("pipeline is not ready. returning stored value\n");
7125 *pmute = player->sound.mute;
7126 return MM_ERROR_NONE;
7129 *pmute = player->sound.mute;
7133 return MM_ERROR_NONE;
7137 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
7139 mm_player_t* player = (mm_player_t*) hplayer;
7143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7145 player->video_stream_changed_cb = callback;
7146 player->video_stream_changed_cb_user_param = user_param;
7147 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
7151 return MM_ERROR_NONE;
7155 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
7157 mm_player_t* player = (mm_player_t*) hplayer;
7161 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7163 player->audio_stream_changed_cb = callback;
7164 player->audio_stream_changed_cb_user_param = user_param;
7165 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
7169 return MM_ERROR_NONE;
7173 _mmplayer_set_audiostream_cb_ex(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback_ex callback, void *user_param)
7175 mm_player_t* player = (mm_player_t*) hplayer;
7179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7181 player->audio_stream_render_cb_ex = callback;
7182 player->audio_stream_cb_user_param = user_param;
7183 player->audio_stream_sink_sync = sync;
7184 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);
7188 return MM_ERROR_NONE;
7192 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
7194 mm_player_t* player = (mm_player_t*) hplayer;
7198 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7200 if (callback && !player->bufmgr)
7201 player->bufmgr = tbm_bufmgr_init(-1);
7203 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
7204 player->video_stream_cb = callback;
7205 player->video_stream_cb_user_param = user_param;
7207 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
7211 return MM_ERROR_NONE;
7215 _mmplayer_set_audiostream_cb(MMHandleType hplayer, mm_player_audio_stream_callback callback, void *user_param)
7217 mm_player_t* player = (mm_player_t*) hplayer;
7221 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7223 player->audio_stream_cb = callback;
7224 player->audio_stream_cb_user_param = user_param;
7225 LOGD("Audio Stream cb Handle value is %p : %p\n", player, player->audio_stream_cb);
7229 return MM_ERROR_NONE;
7233 __mmplayer_start_streaming_ext(mm_player_t *player)
7235 gint ret = MM_ERROR_NONE;
7238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7240 if (MMPLAYER_IS_HTTP_PD(player)) {
7241 if (!player->pd_downloader) {
7242 ret = __mmplayer_realize_streaming_ext(player);
7244 if (ret != MM_ERROR_NONE) {
7245 LOGE("failed to realize streaming ext\n");
7250 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
7251 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
7253 LOGE("ERROR while starting PD...\n");
7254 return MM_ERROR_PLAYER_NOT_INITIALIZED;
7256 ret = MM_ERROR_NONE;
7265 _mmplayer_start(MMHandleType hplayer)
7267 mm_player_t* player = (mm_player_t*) hplayer;
7268 gint ret = MM_ERROR_NONE;
7272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7274 /* check current state */
7275 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
7277 /* PD - start streaming */
7278 ret = __mmplayer_start_streaming_ext(player);
7279 if (ret != MM_ERROR_NONE) {
7280 LOGE("failed to start streaming ext 0x%X", ret);
7284 /* start pipeline */
7285 ret = __mmplayer_gst_start(player);
7286 if (ret != MM_ERROR_NONE)
7287 LOGE("failed to start player.\n");
7289 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7290 LOGD("force playing start even during buffering");
7291 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7299 /* NOTE: post "not supported codec message" to application
7300 * when one codec is not found during AUTOPLUGGING in MSL.
7301 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
7302 * And, if any codec is not found, don't send message here.
7303 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
7306 __mmplayer_handle_missed_plugin(mm_player_t* player)
7308 MMMessageParamType msg_param;
7309 memset(&msg_param, 0, sizeof(MMMessageParamType));
7310 gboolean post_msg_direct = FALSE;
7314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7316 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
7317 player->not_supported_codec, player->can_support_codec);
7319 if (player->not_found_demuxer) {
7320 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7321 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
7323 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7324 MMPLAYER_FREEIF(msg_param.data);
7326 return MM_ERROR_NONE;
7329 if (player->not_supported_codec) {
7330 if (player->can_support_codec) {
7331 // There is one codec to play
7332 post_msg_direct = TRUE;
7334 if (player->pipeline->audiobin) // Some content has only PCM data in container.
7335 post_msg_direct = TRUE;
7338 if (post_msg_direct) {
7339 MMMessageParamType msg_param;
7340 memset(&msg_param, 0, sizeof(MMMessageParamType));
7342 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
7343 LOGW("not found AUDIO codec, posting error code to application.\n");
7345 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7346 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7347 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
7348 LOGW("not found VIDEO codec, posting error code to application.\n");
7350 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
7351 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
7354 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7356 MMPLAYER_FREEIF(msg_param.data);
7358 return MM_ERROR_NONE;
7360 // no any supported codec case
7361 LOGW("not found any codec, posting error code to application.\n");
7363 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
7364 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
7365 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
7367 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
7368 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
7371 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7373 MMPLAYER_FREEIF(msg_param.data);
7379 return MM_ERROR_NONE;
7382 static void __mmplayer_check_pipeline(mm_player_t* player)
7384 GstState element_state = GST_STATE_VOID_PENDING;
7385 GstState element_pending_state = GST_STATE_VOID_PENDING;
7387 int ret = MM_ERROR_NONE;
7389 if (player->gapless.reconfigure) {
7390 LOGW("pipeline is under construction.\n");
7392 MMPLAYER_PLAYBACK_LOCK(player);
7393 MMPLAYER_PLAYBACK_UNLOCK(player);
7395 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7397 /* wait for state transition */
7398 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
7400 if (ret == GST_STATE_CHANGE_FAILURE)
7401 LOGE("failed to change pipeline state within %d sec\n", timeout);
7405 /* NOTE : it should be able to call 'stop' anytime*/
7407 _mmplayer_stop(MMHandleType hplayer)
7409 mm_player_t* player = (mm_player_t*)hplayer;
7410 int ret = MM_ERROR_NONE;
7414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7416 /* check current state */
7417 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
7419 /* check pipline building state */
7420 __mmplayer_check_pipeline(player);
7421 __mmplayer_reset_gapless_state(player);
7423 /* NOTE : application should not wait for EOS after calling STOP */
7424 __mmplayer_cancel_eos_timer(player);
7426 __mmplayer_unrealize_streaming_ext(player);
7429 player->seek_state = MMPLAYER_SEEK_NONE;
7432 ret = __mmplayer_gst_stop(player);
7434 if (ret != MM_ERROR_NONE)
7435 LOGE("failed to stop player.\n");
7443 _mmplayer_pause(MMHandleType hplayer)
7445 mm_player_t* player = (mm_player_t*)hplayer;
7446 gint64 pos_nsec = 0;
7447 gboolean async = FALSE;
7448 gint ret = MM_ERROR_NONE;
7452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7454 /* check current state */
7455 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
7457 /* check pipline building state */
7458 __mmplayer_check_pipeline(player);
7460 switch (MMPLAYER_CURRENT_STATE(player)) {
7461 case MM_PLAYER_STATE_READY:
7463 /* check prepare async or not.
7464 * In the case of streaming playback, it's recommned to avoid blocking wait.
7466 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
7467 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
7469 /* Changing back sync of rtspsrc to async */
7470 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
7471 LOGD("async prepare working mode for rtsp");
7477 case MM_PLAYER_STATE_PLAYING:
7479 /* NOTE : store current point to overcome some bad operation
7480 *(returning zero when getting current position in paused state) of some
7483 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
7484 LOGW("getting current position failed in paused\n");
7486 player->last_position = pos_nsec;
7488 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
7489 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
7490 This causes problem is position calculation during normal pause resume scenarios also.
7491 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
7492 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
7493 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
7494 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
7500 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
7501 LOGD("doing async pause in case of ms buff src");
7505 /* pause pipeline */
7506 ret = __mmplayer_gst_pause(player, async);
7508 if (ret != MM_ERROR_NONE)
7509 LOGE("failed to pause player. ret : 0x%x\n", ret);
7511 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
7512 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
7513 LOGE("failed to update display_rotation");
7521 /* in case of streaming, pause could take long time.*/
7523 _mmplayer_abort_pause(MMHandleType hplayer)
7525 mm_player_t* player = (mm_player_t*)hplayer;
7526 int ret = MM_ERROR_NONE;
7530 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7532 player->pipeline->mainbin,
7533 MM_ERROR_PLAYER_NOT_INITIALIZED);
7535 LOGD("set the pipeline state to READY");
7537 /* set state to READY */
7538 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7539 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
7540 if (ret != MM_ERROR_NONE) {
7541 LOGE("fail to change state to READY");
7542 return MM_ERROR_PLAYER_INTERNAL;
7545 LOGD("succeeded in changing state to READY");
7551 _mmplayer_resume(MMHandleType hplayer)
7553 mm_player_t* player = (mm_player_t*)hplayer;
7554 int ret = MM_ERROR_NONE;
7555 gboolean async = FALSE;
7559 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7561 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
7562 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
7563 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
7567 /* Changing back sync mode rtspsrc to async */
7568 LOGD("async resume for rtsp case");
7572 /* check current state */
7573 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
7575 ret = __mmplayer_gst_resume(player, async);
7576 if (ret != MM_ERROR_NONE)
7577 LOGE("failed to resume player.\n");
7579 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
7580 LOGD("force resume even during buffering");
7581 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
7590 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
7592 mm_player_t* player = (mm_player_t*)hplayer;
7593 gint64 pos_nsec = 0;
7594 int ret = MM_ERROR_NONE;
7596 signed long long start = 0, stop = 0;
7597 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
7600 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
7601 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
7603 /* The sound of video is not supported under 0.0 and over 2.0. */
7604 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
7605 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
7608 _mmplayer_set_mute(hplayer, mute);
7610 if (player->playback_rate == rate)
7611 return MM_ERROR_NONE;
7613 /* If the position is reached at start potion during fast backward, EOS is posted.
7614 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
7616 player->playback_rate = rate;
7618 current_state = MMPLAYER_CURRENT_STATE(player);
7620 if (current_state != MM_PLAYER_STATE_PAUSED)
7621 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
7623 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
7625 if ((current_state == MM_PLAYER_STATE_PAUSED)
7626 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
7627 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
7628 pos_nsec = player->last_position;
7633 stop = GST_CLOCK_TIME_NONE;
7635 start = GST_CLOCK_TIME_NONE;
7639 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
7640 player->playback_rate,
7642 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
7643 GST_SEEK_TYPE_SET, start,
7644 GST_SEEK_TYPE_SET, stop)) {
7645 LOGE("failed to set speed playback\n");
7646 return MM_ERROR_PLAYER_SEEK;
7649 LOGD("succeeded to set speed playback as %0.1f\n", rate);
7653 return MM_ERROR_NONE;;
7657 _mmplayer_set_position(MMHandleType hplayer, int format, gint64 position)
7659 mm_player_t* player = (mm_player_t*)hplayer;
7660 int ret = MM_ERROR_NONE;
7664 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7666 /* check pipline building state */
7667 __mmplayer_check_pipeline(player);
7669 ret = __mmplayer_gst_set_position(player, format, position, FALSE);
7677 _mmplayer_get_position(MMHandleType hplayer, int format, gint64 *position)
7679 mm_player_t* player = (mm_player_t*)hplayer;
7680 int ret = MM_ERROR_NONE;
7682 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7684 ret = __mmplayer_gst_get_position(player, format, position);
7690 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
7692 mm_player_t* player = (mm_player_t*)hplayer;
7693 int ret = MM_ERROR_NONE;
7695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7696 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
7698 *duration = player->duration;
7703 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
7705 mm_player_t* player = (mm_player_t*)hplayer;
7706 int ret = MM_ERROR_NONE;
7708 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7710 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
7716 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
7718 mm_player_t* player = (mm_player_t*)hplayer;
7719 int ret = MM_ERROR_NONE;
7723 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7725 ret = __gst_adjust_subtitle_position(player, format, position);
7733 __mmplayer_is_midi_type(gchar* str_caps)
7735 if ((g_strrstr(str_caps, "audio/midi")) ||
7736 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
7737 (g_strrstr(str_caps, "application/x-smaf")) ||
7738 (g_strrstr(str_caps, "audio/x-imelody")) ||
7739 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
7740 (g_strrstr(str_caps, "audio/xmf")) ||
7741 (g_strrstr(str_caps, "audio/mxmf"))) {
7750 __mmplayer_is_only_mp3_type(gchar *str_caps)
7752 if (g_strrstr(str_caps, "application/x-id3") ||
7753 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
7759 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
7761 GstStructure* caps_structure = NULL;
7762 gint samplerate = 0;
7766 MMPLAYER_RETURN_IF_FAIL(player && caps);
7768 caps_structure = gst_caps_get_structure(caps, 0);
7770 /* set stream information */
7771 gst_structure_get_int(caps_structure, "rate", &samplerate);
7772 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
7774 gst_structure_get_int(caps_structure, "channels", &channels);
7775 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
7777 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
7781 __mmplayer_update_content_type_info(mm_player_t* player)
7784 MMPLAYER_RETURN_IF_FAIL(player && player->type);
7786 if (__mmplayer_is_midi_type(player->type)) {
7787 player->bypass_audio_effect = TRUE;
7788 } else if (g_strrstr(player->type, "application/x-hls")) {
7789 /* If it can't know exact type when it parses uri because of redirection case,
7790 * it will be fixed by typefinder or when doing autoplugging.
7792 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7793 if (player->streamer) {
7794 player->streamer->is_adaptive_streaming = TRUE;
7795 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
7796 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
7798 } else if (g_strrstr(player->type, "application/dash+xml")) {
7799 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7800 if (player->streamer) {
7801 player->streamer->is_adaptive_streaming = TRUE;
7802 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
7806 LOGD("uri type : %d", player->profile.uri_type);
7811 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
7812 GstCaps *caps, gpointer data)
7814 mm_player_t* player = (mm_player_t*)data;
7819 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
7821 /* store type string */
7822 MMPLAYER_FREEIF(player->type);
7823 player->type = gst_caps_to_string(caps);
7825 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
7826 player, player->type, probability, gst_caps_get_size(caps));
7829 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
7830 (g_strrstr(player->type, "audio/x-raw-int"))) {
7831 LOGE("not support media format\n");
7833 if (player->msg_posted == FALSE) {
7834 MMMessageParamType msg_param;
7835 memset(&msg_param, 0, sizeof(MMMessageParamType));
7837 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
7838 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
7840 /* don't post more if one was sent already */
7841 player->msg_posted = TRUE;
7846 __mmplayer_update_content_type_info(player);
7848 pad = gst_element_get_static_pad(tf, "src");
7850 LOGE("fail to get typefind src pad.\n");
7854 if (!__mmplayer_try_to_plug_decodebin(player, pad, caps)) {
7855 gboolean async = FALSE;
7856 LOGE("failed to autoplug %s\n", player->type);
7858 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
7860 if (async && player->msg_posted == FALSE)
7861 __mmplayer_handle_missed_plugin(player);
7867 gst_object_unref(GST_OBJECT(pad));
7875 __mmplayer_create_decodebin(mm_player_t* player)
7877 GstElement *decodebin = NULL;
7881 /* create decodebin */
7882 decodebin = gst_element_factory_make("decodebin", NULL);
7885 LOGE("fail to create decodebin\n");
7889 /* raw pad handling signal */
7890 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
7891 G_CALLBACK(__mmplayer_gst_decode_pad_added), player);
7893 /* no-more-pad pad handling signal */
7894 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
7895 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), player);
7897 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
7898 G_CALLBACK(__mmplayer_gst_decode_pad_removed), player);
7900 /* This signal is emitted when a pad for which there is no further possible
7901 decoding is added to the decodebin.*/
7902 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
7903 G_CALLBACK(__mmplayer_gst_decode_unknown_type), player);
7905 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
7906 before looking for any elements that can handle that stream.*/
7907 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
7908 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), player);
7910 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
7911 before looking for any elements that can handle that stream.*/
7912 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
7913 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), player);
7915 /* This signal is emitted once decodebin has finished decoding all the data.*/
7916 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
7917 G_CALLBACK(__mmplayer_gst_decode_drained), player);
7919 /* This signal is emitted when a element is added to the bin.*/
7920 MMPLAYER_SIGNAL_CONNECT(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
7921 G_CALLBACK(__mmplayer_gst_element_added), player);
7928 __mmplayer_try_to_plug_decodebin(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
7930 MMPlayerGstElement* mainbin = NULL;
7931 GstElement* decodebin = NULL;
7932 GstElement* queue2 = NULL;
7933 GstPad* sinkpad = NULL;
7934 GstPad* qsrcpad = NULL;
7935 gint64 dur_bytes = 0L;
7937 guint max_buffer_size_bytes = 0;
7938 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
7941 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
7943 mainbin = player->pipeline->mainbin;
7945 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
7946 (MMPLAYER_IS_HTTP_STREAMING(player))) {
7947 LOGD("creating http streaming buffering queue(queue2)\n");
7949 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
7950 LOGE("MMPLAYER_M_MUXED_S_BUFFER is not null\n");
7952 queue2 = gst_element_factory_make("queue2", "queue2");
7954 LOGE("failed to create buffering queue element\n");
7958 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
7959 LOGE("failed to add buffering queue\n");
7963 sinkpad = gst_element_get_static_pad(queue2, "sink");
7964 qsrcpad = gst_element_get_static_pad(queue2, "src");
7966 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
7967 LOGE("failed to link buffering queue");
7971 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
7972 LOGE("fail to get duration");
7974 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
7976 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
7978 if (dur_bytes > 0) {
7979 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
7980 type = MUXED_BUFFER_TYPE_FILE;
7982 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
7983 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
7989 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
7990 * skip the pull mode(file or ring buffering) setting. */
7991 if (!g_strrstr(player->type, "video/mpegts")) {
7992 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
7993 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
7995 __mm_player_streaming_set_queue2(player->streamer,
7998 max_buffer_size_bytes,
7999 player->ini.http_buffering_time,
8000 1.0, /* no meaning */
8001 player->ini.http_buffering_limit, /* no meaning */
8003 player->http_file_buffering_path,
8004 (guint64)dur_bytes);
8007 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(queue2)) {
8008 LOGE("failed to sync queue2 state with parent\n");
8014 gst_object_unref(GST_OBJECT(sinkpad));
8016 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
8017 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
8021 /* create decodebin */
8022 decodebin = __mmplayer_create_decodebin(player);
8025 LOGE("can not create autoplug element\n");
8029 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
8030 LOGE("failed to add decodebin\n");
8034 /* to force caps on the decodebin element and avoid reparsing stuff by
8035 * typefind. It also avoids a deadlock in the way typefind activates pads in
8036 * the state change */
8037 g_object_set(decodebin, "sink-caps", caps, NULL);
8039 sinkpad = gst_element_get_static_pad(decodebin, "sink");
8041 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
8042 LOGE("failed to link decodebin\n");
8046 gst_object_unref(GST_OBJECT(sinkpad));
8048 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
8049 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
8051 /* set decodebin property about buffer in streaming playback. *
8052 * in case of HLS/DASH, it does not need to have big buffer *
8053 * because it is kind of adaptive streaming. */
8054 if (!MMPLAYER_IS_HTTP_PD(player) &&
8055 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
8056 gdouble high_percent = 0.0;
8058 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
8059 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
8061 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
8062 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
8064 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
8065 "high-percent", (gint)high_percent,
8066 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
8067 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
8068 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
8069 "max-size-buffers", 0, NULL); // disable or automatic
8072 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
8073 LOGE("failed to sync decodebin state with parent\n");
8084 gst_object_unref(GST_OBJECT(sinkpad));
8087 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8088 * You need to explicitly set elements to the NULL state before
8089 * dropping the final reference, to allow them to clean up.
8091 gst_element_set_state(queue2, GST_STATE_NULL);
8093 /* And, it still has a parent "player".
8094 * You need to let the parent manage the object instead of unreffing the object directly.
8096 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
8097 gst_object_unref(queue2);
8102 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
8103 * You need to explicitly set elements to the NULL state before
8104 * dropping the final reference, to allow them to clean up.
8106 gst_element_set_state(decodebin, GST_STATE_NULL);
8108 /* And, it still has a parent "player".
8109 * You need to let the parent manage the object instead of unreffing the object directly.
8112 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
8113 gst_object_unref(decodebin);
8121 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
8125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
8126 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
8128 LOGD("class : %s, mime : %s \n", factory_class, mime);
8130 /* add missing plugin */
8131 /* NOTE : msl should check missing plugin for image mime type.
8132 * Some motion jpeg clips can have playable audio track.
8133 * So, msl have to play audio after displaying popup written video format not supported.
8135 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
8136 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
8137 LOGD("not found demuxer\n");
8138 player->not_found_demuxer = TRUE;
8139 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
8145 if (!g_strrstr(factory_class, "Demuxer")) {
8146 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
8147 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
8148 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
8150 /* check that clip have multi tracks or not */
8151 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
8152 LOGD("video plugin is already linked\n");
8154 LOGW("add VIDEO to missing plugin\n");
8155 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
8156 player->unlinked_video_mime = g_strdup_printf("%s", mime);
8158 } else if (g_str_has_prefix(mime, "audio")) {
8159 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
8160 LOGD("audio plugin is already linked\n");
8162 LOGW("add AUDIO to missing plugin\n");
8163 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
8164 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
8172 return MM_ERROR_NONE;
8177 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
8179 mm_player_t* player = (mm_player_t*)data;
8183 MMPLAYER_RETURN_IF_FAIL(player);
8185 /* remove fakesink. */
8186 if (!__mmplayer_gst_remove_fakesink(player,
8187 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
8188 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
8189 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
8190 * source element are not same. To overcome this situation, this function will called
8191 * several places and several times. Therefore, this is not an error case.
8196 LOGD("[handle: %p] pipeline has completely constructed", player);
8198 if ((player->ini.async_start) &&
8199 (player->msg_posted == FALSE) &&
8200 (player->cmd >= MMPLAYER_COMMAND_START))
8201 __mmplayer_handle_missed_plugin(player);
8203 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
8207 __mmplayer_verify_next_play_path(mm_player_t *player)
8209 MMHandleType attrs = 0;
8210 MMPlayerParseProfile profile;
8211 gint uri_idx = 0, check_cnt = 0;
8213 gint mode = MM_PLAYER_PD_MODE_NONE;
8217 guint num_of_list = 0;
8218 static int profile_tv = -1;
8222 LOGD("checking for gapless play");
8224 if (player->pipeline->textbin) {
8225 LOGE("subtitle path is enabled. gapless play is not supported.\n");
8229 attrs = MMPLAYER_GET_ATTRS(player);
8231 LOGE("fail to get attributes.\n");
8235 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
8237 if (__builtin_expect(profile_tv == -1, 0)) {
8239 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
8240 switch (*profileName) {
8250 /* gapless playback is not supported in case of video at TV profile. */
8251 if (profile_tv && video) {
8252 LOGW("not support video gapless playback");
8256 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
8263 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
8264 LOGE("can not get play count\n");
8266 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
8267 LOGE("can not get gapless mode\n");
8269 if (video && !gapless) {
8270 LOGW("not enabled video gapless playback");
8274 if ((count == -1 || count > 1)) /* enable gapless when looping or repeat */
8278 LOGW("gapless is disabled\n"); /* FIXME: playlist(without gapless) is not implemented. */
8282 num_of_list = g_list_length(player->uri_info.uri_list);
8284 LOGD("repeat count = %d, num_of_list = %d\n", count, num_of_list);
8286 if (num_of_list == 0) {
8287 if (mm_attrs_get_string_by_name(player->attrs, "profile_uri", &uri) != MM_ERROR_NONE) {
8288 LOGE("can not get profile_uri\n");
8293 LOGE("uri list is empty.\n");
8297 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
8298 LOGD("add original path : %s ", uri);
8304 uri_idx = player->uri_info.uri_idx;
8309 if (check_cnt > num_of_list) {
8310 LOGE("there is no valid uri.");
8314 LOGD("uri idx : %d / %d\n", uri_idx, num_of_list);
8316 if (uri_idx < num_of_list-1) {
8319 if ((count <= 1) && (count != -1)) {
8322 } else if (count > 1) {
8323 /* decrease play count */
8324 /* we succeeded to rewind. update play count and then wait for next EOS */
8327 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
8329 /* commit attribute */
8330 if (mmf_attrs_commit(attrs))
8331 LOGE("failed to commit attribute\n");
8334 /* count < 0 : repeat continually */
8338 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
8339 LOGD("uri idx : %d, uri = %s\n", uri_idx, uri);
8342 LOGW("next uri does not exist\n");
8346 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
8347 LOGE("failed to parse profile\n");
8351 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
8352 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
8353 LOGW("uri type is not supported(%d).", profile.uri_type);
8360 player->uri_info.uri_idx = uri_idx;
8361 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
8363 if (mmf_attrs_commit(player->attrs)) {
8364 LOGE("failed to commit.\n");
8368 LOGD("next uri %s(%d)\n", uri, uri_idx);
8374 LOGE("unable to play next path. EOS will be posted soon.\n");
8379 __mmplayer_initialize_next_play(mm_player_t *player)
8385 player->smooth_streaming = FALSE;
8386 player->videodec_linked = 0;
8387 player->audiodec_linked = 0;
8388 player->videosink_linked = 0;
8389 player->audiosink_linked = 0;
8390 player->textsink_linked = 0;
8391 player->is_external_subtitle_present = FALSE;
8392 player->is_external_subtitle_added_now = FALSE;
8393 player->not_supported_codec = MISSING_PLUGIN_NONE;
8394 player->can_support_codec = FOUND_PLUGIN_NONE;
8395 player->pending_seek.is_pending = FALSE;
8396 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
8397 player->pending_seek.pos = 0;
8398 player->msg_posted = FALSE;
8399 player->has_many_types = FALSE;
8400 player->no_more_pad = FALSE;
8401 player->not_found_demuxer = 0;
8402 player->seek_state = MMPLAYER_SEEK_NONE;
8403 player->max_audio_channels = 0;
8404 player->is_subtitle_force_drop = FALSE;
8405 player->play_subtitle = FALSE;
8406 player->adjust_subtitle_pos = 0;
8408 player->total_bitrate = 0;
8409 player->total_maximum_bitrate = 0;
8411 _mmplayer_track_initialize(player);
8412 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8414 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
8415 player->bitrate[i] = 0;
8416 player->maximum_bitrate[i] = 0;
8419 if (player->v_stream_caps) {
8420 gst_caps_unref(player->v_stream_caps);
8421 player->v_stream_caps = NULL;
8424 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
8426 /* clean found parsers */
8427 if (player->parsers) {
8428 GList *parsers = player->parsers;
8429 for (; parsers; parsers = g_list_next(parsers)) {
8430 gchar *name = parsers->data;
8431 MMPLAYER_FREEIF(name);
8433 g_list_free(player->parsers);
8434 player->parsers = NULL;
8437 /* clean found audio decoders */
8438 if (player->audio_decoders) {
8439 GList *a_dec = player->audio_decoders;
8440 for (; a_dec; a_dec = g_list_next(a_dec)) {
8441 gchar *name = a_dec->data;
8442 MMPLAYER_FREEIF(name);
8444 g_list_free(player->audio_decoders);
8445 player->audio_decoders = NULL;
8452 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
8454 MMPlayerGstElement *mainbin = NULL;
8455 MMMessageParamType msg_param = {0,};
8456 GstElement *element = NULL;
8457 MMHandleType attrs = 0;
8459 enum MainElementID elemId = MMPLAYER_M_NUM;
8463 if ((player == NULL) ||
8464 (player->pipeline == NULL) ||
8465 (player->pipeline->mainbin == NULL)) {
8466 LOGE("player is null.\n");
8470 mainbin = player->pipeline->mainbin;
8471 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
8473 attrs = MMPLAYER_GET_ATTRS(player);
8475 LOGE("fail to get attributes.\n");
8479 /* Initialize Player values */
8480 __mmplayer_initialize_next_play(player);
8482 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
8484 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
8485 LOGE("failed to parse profile\n");
8486 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8490 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
8491 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
8492 LOGE("it's dash or hls. not support.");
8493 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8498 switch (player->profile.uri_type) {
8500 case MM_PLAYER_URI_TYPE_FILE:
8502 LOGD("using filesrc for 'file://' handler.\n");
8503 if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) {
8504 LOGE("failed to get storage info");
8508 element = gst_element_factory_make("filesrc", "source");
8511 LOGE("failed to create filesrc\n");
8515 g_object_set(G_OBJECT(element), "location", (player->profile.uri)+7, NULL); /* uri+7 -> remove "file:// */
8518 case MM_PLAYER_URI_TYPE_URL_HTTP:
8520 gchar *user_agent, *cookies, **cookie_list;
8521 gint http_timeout = DEFAULT_HTTP_TIMEOUT;
8522 user_agent = cookies = NULL;
8525 element = gst_element_factory_make(player->ini.httpsrc_element, "http_streaming_source");
8527 LOGE("failed to create http streaming source element[%s].\n", player->ini.httpsrc_element);
8530 LOGD("using http streamming source [%s].\n", player->ini.httpsrc_element);
8533 mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies);
8534 mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent);
8536 if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) {
8537 LOGD("get timeout from ini\n");
8538 http_timeout = player->ini.http_timeout;
8542 SECURE_LOGD("location : %s\n", player->profile.uri);
8543 SECURE_LOGD("cookies : %s\n", cookies);
8544 SECURE_LOGD("user_agent : %s\n", user_agent);
8545 LOGD("timeout : %d\n", http_timeout);
8547 /* setting property to streaming source */
8548 g_object_set(G_OBJECT(element), "location", player->profile.uri, NULL);
8549 g_object_set(G_OBJECT(element), "timeout", http_timeout, NULL);
8550 g_object_set(G_OBJECT(element), "blocksize", (unsigned long)(64*1024), NULL);
8552 /* parsing cookies */
8553 if ((cookie_list = util_get_cookie_list((const char*)cookies)))
8554 g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL);
8556 g_object_set(G_OBJECT(element), "user_agent", user_agent, NULL);
8560 LOGE("not support uri type %d\n", player->profile.uri_type);
8565 LOGE("no source element was created.\n");
8569 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
8570 LOGE("failed to add source element to pipeline\n");
8571 gst_object_unref(GST_OBJECT(element));
8576 /* take source element */
8577 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
8578 mainbin[MMPLAYER_M_SRC].gst = element;
8582 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8583 if (player->streamer == NULL) {
8584 player->streamer = __mm_player_streaming_create();
8585 __mm_player_streaming_initialize(player->streamer);
8588 elemId = MMPLAYER_M_TYPEFIND;
8589 element = gst_element_factory_make("typefind", "typefinder");
8590 MMPLAYER_SIGNAL_CONNECT(player, element, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type",
8591 G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
8593 elemId = MMPLAYER_M_AUTOPLUG;
8594 element = __mmplayer_create_decodebin(player);
8597 /* check autoplug element is OK */
8599 LOGE("can not create element(%d)\n", elemId);
8603 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
8604 LOGE("failed to add sinkbin to pipeline\n");
8605 gst_object_unref(GST_OBJECT(element));
8610 mainbin[elemId].id = elemId;
8611 mainbin[elemId].gst = element;
8613 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elemId].gst) == FALSE) {
8614 LOGE("Failed to link src - autoplug(or typefind)\n");
8618 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
8619 LOGE("Failed to change state of src element\n");
8623 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
8624 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
8625 LOGE("Failed to change state of decodebin\n");
8629 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
8630 LOGE("Failed to change state of src element\n");
8635 player->gapless.stream_changed = TRUE;
8636 player->gapless.running = TRUE;
8642 MMPLAYER_PLAYBACK_UNLOCK(player);
8644 if (!player->msg_posted) {
8645 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8646 player->msg_posted = TRUE;
8653 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
8655 mm_player_selector_t *selector = &player->selector[type];
8656 MMPlayerGstElement *sinkbin = NULL;
8657 enum MainElementID selectorId = MMPLAYER_M_NUM;
8658 enum MainElementID sinkId = MMPLAYER_M_NUM;
8659 GstPad *srcpad = NULL;
8660 GstPad *sinkpad = NULL;
8661 gboolean send_notice = FALSE;
8664 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8666 LOGD("type %d", type);
8669 case MM_PLAYER_TRACK_TYPE_AUDIO:
8670 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
8671 sinkId = MMPLAYER_A_BIN;
8672 sinkbin = player->pipeline->audiobin;
8674 case MM_PLAYER_TRACK_TYPE_VIDEO:
8675 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
8676 sinkId = MMPLAYER_V_BIN;
8677 sinkbin = player->pipeline->videobin;
8680 case MM_PLAYER_TRACK_TYPE_TEXT:
8681 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
8682 sinkId = MMPLAYER_T_BIN;
8683 sinkbin = player->pipeline->textbin;
8686 LOGE("requested type is not supportable");
8691 if (player->pipeline->mainbin[selectorId].gst) {
8694 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
8696 if (selector->event_probe_id != 0)
8697 gst_pad_remove_probe(srcpad, selector->event_probe_id);
8698 selector->event_probe_id = 0;
8700 if ((sinkbin) && (sinkbin[sinkId].gst)) {
8701 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
8703 if (srcpad && sinkpad) {
8704 /* after getting drained signal there is no data flows, so no need to do pad_block */
8705 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
8706 gst_pad_unlink(srcpad, sinkpad);
8708 /* send custom event to sink pad to handle it at video sink */
8710 LOGD("send custom event to sinkpad");
8711 GstStructure *s = gst_structure_new_empty("application/flush-buffer");
8712 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
8713 gst_pad_send_event(sinkpad, event);
8717 gst_object_unref(sinkpad);
8720 gst_object_unref(srcpad);
8723 LOGD("selector release");
8725 /* release and unref requests pad from the selector */
8726 for (n = 0; n < selector->channels->len; n++) {
8727 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
8728 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
8730 g_ptr_array_set_size(selector->channels, 0);
8732 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
8733 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
8735 player->pipeline->mainbin[selectorId].gst = NULL;
8743 __mmplayer_deactivate_old_path(mm_player_t *player)
8746 MMPLAYER_RETURN_IF_FAIL(player);
8748 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
8749 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
8750 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
8751 LOGE("deactivate selector error");
8755 _mmplayer_track_destroy(player);
8756 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8758 if (player->streamer) {
8759 __mm_player_streaming_deinitialize(player->streamer);
8760 __mm_player_streaming_destroy(player->streamer);
8761 player->streamer = NULL;
8764 MMPLAYER_PLAYBACK_LOCK(player);
8765 MMPLAYER_NEXT_PLAY_THREAD_SIGNAL(player);
8772 if (!player->msg_posted) {
8773 MMMessageParamType msg = {0,};
8776 msg.code = MM_ERROR_PLAYER_INTERNAL;
8777 LOGE("next_uri_play> deactivate error");
8779 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
8780 player->msg_posted = TRUE;
8785 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
8787 int result = MM_ERROR_NONE;
8788 mm_player_t* player = (mm_player_t*) hplayer;
8791 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8794 player->http_file_buffering_path = (gchar*)file_path;
8795 LOGD("temp file path: %s\n", player->http_file_buffering_path);
8801 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
8803 int result = MM_ERROR_NONE;
8804 mm_player_t* player = (mm_player_t*) hplayer;
8807 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8809 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
8810 if (mmf_attrs_commit(player->attrs)) {
8811 LOGE("failed to commit the original uri.\n");
8812 result = MM_ERROR_PLAYER_INTERNAL;
8814 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
8815 LOGE("failed to add the original uri in the uri list.\n");
8822 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
8824 mm_player_t* player = (mm_player_t*) hplayer;
8825 guint num_of_list = 0;
8829 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8830 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
8832 if (player->pipeline && player->pipeline->textbin) {
8833 LOGE("subtitle path is enabled.\n");
8834 return MM_ERROR_PLAYER_INVALID_STATE;
8837 num_of_list = g_list_length(player->uri_info.uri_list);
8839 if (is_first_path == TRUE) {
8840 if (num_of_list == 0) {
8841 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
8842 LOGD("add original path : %s", uri);
8844 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
8845 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
8847 LOGD("change original path : %s", uri);
8850 MMHandleType attrs = 0;
8851 attrs = MMPLAYER_GET_ATTRS(player);
8853 if (num_of_list == 0) {
8854 char *original_uri = NULL;
8857 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
8859 if (!original_uri) {
8860 LOGE("there is no original uri.");
8861 return MM_ERROR_PLAYER_INVALID_STATE;
8864 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
8865 player->uri_info.uri_idx = 0;
8867 LOGD("add original path at first : %s(%d)", original_uri);
8871 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
8872 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
8876 return MM_ERROR_NONE;
8879 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
8881 mm_player_t* player = (mm_player_t*) hplayer;
8882 char *next_uri = NULL;
8883 guint num_of_list = 0;
8886 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8888 num_of_list = g_list_length(player->uri_info.uri_list);
8890 if (num_of_list > 0) {
8891 gint uri_idx = player->uri_info.uri_idx;
8893 if (uri_idx < num_of_list-1)
8898 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
8899 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
8901 *uri = g_strdup(next_uri);
8905 return MM_ERROR_NONE;
8909 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
8910 GstCaps *caps, gpointer data)
8912 mm_player_t* player = (mm_player_t*)data;
8913 const gchar* klass = NULL;
8914 const gchar* mime = NULL;
8915 gchar* caps_str = NULL;
8917 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
8918 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
8919 caps_str = gst_caps_to_string(caps);
8921 LOGW("unknown type of caps : %s from %s",
8922 caps_str, GST_ELEMENT_NAME(elem));
8924 MMPLAYER_FREEIF(caps_str);
8926 /* There is no available codec. */
8927 __mmplayer_check_not_supported_codec(player, klass, mime);
8931 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
8932 GstCaps * caps, gpointer data)
8934 mm_player_t* player = (mm_player_t*)data;
8935 const char* mime = NULL;
8936 gboolean ret = TRUE;
8938 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8939 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
8941 if (g_str_has_prefix(mime, "audio")) {
8942 GstStructure* caps_structure = NULL;
8943 gint samplerate = 0;
8945 gchar *caps_str = NULL;
8947 caps_structure = gst_caps_get_structure(caps, 0);
8948 gst_structure_get_int(caps_structure, "rate", &samplerate);
8949 gst_structure_get_int(caps_structure, "channels", &channels);
8951 if ((channels > 0 && samplerate == 0)) {
8952 LOGD("exclude audio...");
8956 caps_str = gst_caps_to_string(caps);
8957 /* set it directly because not sent by TAG */
8958 if (g_strrstr(caps_str, "mobile-xmf"))
8959 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
8960 MMPLAYER_FREEIF(caps_str);
8961 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
8962 MMMessageParamType msg_param;
8963 memset(&msg_param, 0, sizeof(MMMessageParamType));
8964 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
8965 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8966 LOGD("video file is not supported on this device");
8968 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
8969 LOGD("already video linked");
8972 LOGD("found new stream");
8979 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
8981 int ret = MM_ERROR_NONE;
8983 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8985 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
8986 GstStructure* str = NULL;
8988 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
8990 LOGD("audio codec type: %d", codec_type);
8991 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
8992 /* sw codec will be skipped */
8993 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
8994 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
8995 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
8996 ret = MM_ERROR_PLAYER_INTERNAL;
9000 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
9001 /* hw codec will be skipped */
9002 if (strcmp(player->ini.audiocodec_element_hw, "") &&
9003 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
9004 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
9005 ret = MM_ERROR_PLAYER_INTERNAL;
9010 str = gst_caps_get_structure(caps, 0);
9012 gst_structure_get_int(str, "channels", &channels);
9014 LOGD("check audio ch : %d %d\n", player->max_audio_channels, channels);
9015 if (player->max_audio_channels < channels)
9016 player->max_audio_channels = channels;
9018 /* set stream information */
9019 if (!player->audiodec_linked)
9020 __mmplayer_set_audio_attrs(player, caps);
9022 /* update codec info */
9023 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
9024 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
9025 player->audiodec_linked = 1;
9027 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
9029 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
9031 LOGD("video codec type: %d", codec_type);
9032 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
9033 /* sw codec is skipped */
9034 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
9035 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
9036 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
9037 ret = MM_ERROR_PLAYER_INTERNAL;
9041 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
9042 /* hw codec is skipped */
9043 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
9044 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
9045 ret = MM_ERROR_PLAYER_INTERNAL;
9050 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
9051 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
9053 /* mark video decoder for acquire */
9054 if (player->video_decoder_resource == NULL) {
9055 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
9056 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
9057 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
9058 &player->video_decoder_resource)
9059 != MM_RESOURCE_MANAGER_ERROR_NONE) {
9060 LOGE("could not mark video_decoder resource for acquire");
9061 ret = MM_ERROR_PLAYER_INTERNAL;
9065 LOGW("video decoder resource is already acquired, skip it.");
9066 ret = MM_ERROR_PLAYER_INTERNAL;
9070 player->interrupted_by_resource = FALSE;
9071 /* acquire resources for video playing */
9072 if (mm_resource_manager_commit(player->resource_manager)
9073 != MM_RESOURCE_MANAGER_ERROR_NONE) {
9074 LOGE("could not acquire resources for video decoding\n");
9075 ret = MM_ERROR_PLAYER_INTERNAL;
9080 /* update codec info */
9081 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
9082 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
9083 player->videodec_linked = 1;
9091 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
9092 GstCaps* caps, GstElementFactory* factory, gpointer data)
9094 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
9095 We are defining our own and will be removed when it actually exposed */
9097 GST_AUTOPLUG_SELECT_TRY,
9098 GST_AUTOPLUG_SELECT_EXPOSE,
9099 GST_AUTOPLUG_SELECT_SKIP
9100 } GstAutoplugSelectResult;
9102 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
9103 mm_player_t* player = (mm_player_t*)data;
9105 gchar* factory_name = NULL;
9106 gchar* caps_str = NULL;
9107 const gchar* klass = NULL;
9110 factory_name = GST_OBJECT_NAME(factory);
9111 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
9112 caps_str = gst_caps_to_string(caps);
9114 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
9116 /* store type string */
9117 if (player->type == NULL) {
9118 player->type = gst_caps_to_string(caps);
9119 __mmplayer_update_content_type_info(player);
9122 /* filtering exclude keyword */
9123 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
9124 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
9125 LOGW("skipping [%s] by exculde keyword [%s]\n",
9126 factory_name, player->ini.exclude_element_keyword[idx]);
9128 result = GST_AUTOPLUG_SELECT_SKIP;
9133 /* exclude webm format */
9134 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
9135 * because webm format is not supportable.
9136 * If webm is disabled in "autoplug-continue", there is no state change
9137 * failure or error because the decodebin will expose the pad directly.
9138 * It make MSL invoke _prepare_async_callback.
9139 * So, we need to disable webm format in "autoplug-select" */
9140 if (caps_str && strstr(caps_str, "webm")) {
9141 LOGW("webm is not supported");
9142 result = GST_AUTOPLUG_SELECT_SKIP;
9146 /* check factory class for filtering */
9147 /* NOTE : msl don't need to use image plugins.
9148 * So, those plugins should be skipped for error handling.
9150 if (g_strrstr(klass, "Codec/Decoder/Image")) {
9151 LOGD("skipping [%s] by not required\n", factory_name);
9152 result = GST_AUTOPLUG_SELECT_SKIP;
9156 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
9157 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
9158 // TO CHECK : subtitle if needed, add subparse exception.
9159 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
9160 result = GST_AUTOPLUG_SELECT_SKIP;
9164 if (g_strrstr(factory_name, "mpegpsdemux")) {
9165 LOGD("skipping PS container - not support\n");
9166 result = GST_AUTOPLUG_SELECT_SKIP;
9170 if (g_strrstr(factory_name, "mssdemux"))
9171 player->smooth_streaming = TRUE;
9173 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
9174 (g_strrstr(klass, "Codec/Decoder/Video"))) {
9177 GstStructure *str = NULL;
9178 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
9180 /* don't make video because of not required */
9181 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
9182 (player->set_mode.media_packet_video_stream == FALSE)) {
9183 LOGD("no video because it's not required. -> return expose");
9184 result = GST_AUTOPLUG_SELECT_EXPOSE;
9188 /* get w/h for omx state-tune */
9189 /* FIXME: deprecated? */
9190 str = gst_caps_get_structure(caps, 0);
9191 gst_structure_get_int(str, "width", &width);
9194 if (player->v_stream_caps) {
9195 gst_caps_unref(player->v_stream_caps);
9196 player->v_stream_caps = NULL;
9199 player->v_stream_caps = gst_caps_copy(caps);
9200 LOGD("take caps for video state tune");
9201 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
9205 if (g_strrstr(klass, "Codec/Decoder")) {
9206 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
9207 LOGD("skipping %s codec", factory_name);
9208 result = GST_AUTOPLUG_SELECT_SKIP;
9214 MMPLAYER_FREEIF(caps_str);
9220 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
9223 //mm_player_t* player = (mm_player_t*)data;
9224 GstCaps* caps = NULL;
9226 LOGD("[Decodebin2] pad-removed signal\n");
9228 caps = gst_pad_query_caps(new_pad, NULL);
9230 gchar* caps_str = NULL;
9231 caps_str = gst_caps_to_string(caps);
9233 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
9235 MMPLAYER_FREEIF(caps_str);
9236 gst_caps_unref(caps);
9241 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
9243 mm_player_t* player = (mm_player_t*)data;
9244 GstIterator *iter = NULL;
9245 GValue item = { 0, };
9247 gboolean done = FALSE;
9248 gboolean is_all_drained = TRUE;
9251 MMPLAYER_RETURN_IF_FAIL(player);
9253 LOGD("__mmplayer_gst_decode_drained");
9255 if (player->use_deinterleave == TRUE) {
9256 LOGD("group playing mode.");
9260 if (!MMPLAYER_CMD_TRYLOCK(player)) {
9261 LOGW("Fail to get cmd lock");
9265 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
9266 !__mmplayer_verify_next_play_path(player)) {
9267 LOGD("decoding is finished.");
9268 __mmplayer_reset_gapless_state(player);
9269 MMPLAYER_CMD_UNLOCK(player);
9273 player->gapless.reconfigure = TRUE;
9275 /* check decodebin src pads whether they received EOS or not */
9276 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
9279 switch (gst_iterator_next(iter, &item)) {
9280 case GST_ITERATOR_OK:
9281 pad = g_value_get_object(&item);
9282 if (pad && !GST_PAD_IS_EOS(pad)) {
9283 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
9284 is_all_drained = FALSE;
9287 g_value_reset(&item);
9289 case GST_ITERATOR_RESYNC:
9290 gst_iterator_resync(iter);
9292 case GST_ITERATOR_ERROR:
9293 case GST_ITERATOR_DONE:
9298 g_value_unset(&item);
9299 gst_iterator_free(iter);
9301 if (!is_all_drained) {
9302 LOGD("Wait util the all pads get EOS.");
9303 MMPLAYER_CMD_UNLOCK(player);
9308 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
9309 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
9311 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
9312 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
9313 __mmplayer_deactivate_old_path(player);
9314 MMPLAYER_CMD_UNLOCK(player);
9320 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
9322 mm_player_t* player = (mm_player_t*)data;
9323 const gchar* klass = NULL;
9324 gchar* factory_name = NULL;
9326 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
9327 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
9329 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
9331 if (__mmplayer_add_dump_buffer_probe(player, element))
9332 LOGD("add buffer probe");
9335 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
9336 gchar* selected = NULL;
9337 selected = g_strdup(GST_ELEMENT_NAME(element));
9338 player->audio_decoders = g_list_append(player->audio_decoders, selected);
9342 if (g_strrstr(klass, "Parser")) {
9343 gchar* selected = NULL;
9345 selected = g_strdup(factory_name);
9346 player->parsers = g_list_append(player->parsers, selected);
9349 if (g_strrstr(klass, "Demuxer/Adaptive")) {
9350 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
9351 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
9353 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
9354 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
9356 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9357 "max-bandwidth", player->adaptive_info.limit.bandwidth,
9358 "max-video-width", player->adaptive_info.limit.width,
9359 "max-video-height", player->adaptive_info.limit.height, NULL);
9361 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
9362 /* FIXIT : first value will be overwritten if there's more
9363 * than 1 demuxer/parser
9366 //LOGD("plugged element is demuxer. take it\n");
9367 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
9368 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
9370 /*Added for multi audio support */ // Q. del?
9371 if (g_strrstr(klass, "Demux")) {
9372 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
9373 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
9377 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
9378 int surface_type = 0;
9380 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
9383 // to support trust-zone only
9384 if (g_strrstr(factory_name, "asfdemux")) {
9385 LOGD("set file-location %s\n", player->profile.uri);
9386 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
9388 if (player->video_hub_download_mode == TRUE)
9389 g_object_set(G_OBJECT(element), "downloading-mode", player->video_hub_download_mode, NULL);
9390 } else if (g_strrstr(factory_name, "legacyh264parse")) {
9391 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
9392 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
9393 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
9394 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
9395 (__mmplayer_is_only_mp3_type(player->type))) {
9396 LOGD("[mpegaudioparse] set streaming pull mode.");
9397 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
9399 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
9400 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
9403 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
9404 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
9405 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
9407 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
9408 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
9410 if (!MMPLAYER_IS_HTTP_PD(player) &&
9411 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
9412 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
9413 (MMPLAYER_IS_DASH_STREAMING(player)))) {
9414 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
9415 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
9416 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
9424 gboolean __mmplayer_configure_audio_callback(mm_player_t* player)
9427 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9429 if (MMPLAYER_IS_STREAMING(player))
9432 /* This callback can be set to music player only. */
9433 if ((player->can_support_codec & 0x02) == FOUND_PLUGIN_VIDEO) {
9434 LOGW("audio callback is not supported for video");
9438 if (player->audio_stream_cb) {
9441 pad = gst_element_get_static_pad(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "sink");
9444 LOGE("failed to get sink pad from audiosink to probe data\n");
9447 player->audio_cb_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
9448 __mmplayer_audio_stream_probe, player, NULL);
9450 gst_object_unref(pad);
9454 LOGE("There is no audio callback to configure.\n");
9464 __mmplayer_release_misc(mm_player_t* player)
9467 bool cur_mode = player->set_mode.rich_audio;
9470 MMPLAYER_RETURN_IF_FAIL(player);
9472 player->video_stream_cb = NULL;
9473 player->video_stream_cb_user_param = NULL;
9474 player->video_stream_prerolled = FALSE;
9476 player->audio_stream_cb = NULL;
9477 player->audio_stream_render_cb_ex = NULL;
9478 player->audio_stream_cb_user_param = NULL;
9479 player->audio_stream_sink_sync = false;
9481 player->video_stream_changed_cb = NULL;
9482 player->video_stream_changed_cb_user_param = NULL;
9484 player->audio_stream_changed_cb = NULL;
9485 player->audio_stream_changed_cb_user_param = NULL;
9487 player->sent_bos = FALSE;
9488 player->playback_rate = DEFAULT_PLAYBACK_RATE;
9490 player->seek_state = MMPLAYER_SEEK_NONE;
9492 player->total_bitrate = 0;
9493 player->total_maximum_bitrate = 0;
9495 player->not_found_demuxer = 0;
9497 player->last_position = 0;
9498 player->duration = 0;
9499 player->http_content_size = 0;
9500 player->not_supported_codec = MISSING_PLUGIN_NONE;
9501 player->can_support_codec = FOUND_PLUGIN_NONE;
9502 player->pending_seek.is_pending = FALSE;
9503 player->pending_seek.format = MM_PLAYER_POS_FORMAT_TIME;
9504 player->pending_seek.pos = 0;
9505 player->msg_posted = FALSE;
9506 player->has_many_types = FALSE;
9507 player->max_audio_channels = 0;
9508 player->video_share_api_delta = 0;
9509 player->video_share_clock_delta = 0;
9510 player->is_subtitle_force_drop = FALSE;
9511 player->play_subtitle = FALSE;
9512 player->adjust_subtitle_pos = 0;
9513 player->last_multiwin_status = FALSE;
9514 player->has_closed_caption = FALSE;
9515 player->set_mode.media_packet_video_stream = FALSE;
9516 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
9517 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
9519 player->set_mode.rich_audio = cur_mode;
9521 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
9522 player->bitrate[i] = 0;
9523 player->maximum_bitrate[i] = 0;
9526 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
9528 /* remove media stream cb(appsrc cb) */
9529 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
9530 player->media_stream_buffer_status_cb[i] = NULL;
9531 player->media_stream_seek_data_cb[i] = NULL;
9532 player->buffer_cb_user_param[i] = NULL;
9533 player->seek_cb_user_param[i] = NULL;
9535 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
9537 /* free memory related to audio effect */
9538 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
9540 if (player->adaptive_info.var_list) {
9541 g_list_free_full(player->adaptive_info.var_list, g_free);
9542 player->adaptive_info.var_list = NULL;
9545 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
9546 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
9547 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
9549 /* Reset video360 settings to their defaults in case if the pipeline is to be
9552 player->video360_metadata.is_spherical = -1;
9553 player->is_openal_plugin_used = FALSE;
9555 player->is_content_spherical = FALSE;
9556 player->is_video360_enabled = TRUE;
9557 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
9558 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
9559 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
9560 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
9561 player->video360_zoom = 1.0f;
9562 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
9563 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
9565 player->sound.rg_enable = false;
9571 __mmplayer_release_misc_post(mm_player_t* player)
9573 char *original_uri = NULL;
9576 /* player->pipeline is already released before. */
9578 MMPLAYER_RETURN_IF_FAIL(player);
9580 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
9582 /* clean found parsers */
9583 if (player->parsers) {
9584 GList *parsers = player->parsers;
9585 for (; parsers; parsers = g_list_next(parsers)) {
9586 gchar *name = parsers->data;
9587 MMPLAYER_FREEIF(name);
9589 g_list_free(player->parsers);
9590 player->parsers = NULL;
9593 /* clean found audio decoders */
9594 if (player->audio_decoders) {
9595 GList *a_dec = player->audio_decoders;
9596 for (; a_dec; a_dec = g_list_next(a_dec)) {
9597 gchar *name = a_dec->data;
9598 MMPLAYER_FREEIF(name);
9600 g_list_free(player->audio_decoders);
9601 player->audio_decoders = NULL;
9604 /* clean the uri list except original uri */
9605 if (player->uri_info.uri_list) {
9606 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
9608 if (player->attrs) {
9609 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
9610 LOGD("restore original uri = %s\n", original_uri);
9612 if (mmf_attrs_commit(player->attrs))
9613 LOGE("failed to commit the original uri.\n");
9616 GList *uri_list = player->uri_info.uri_list;
9617 for (; uri_list; uri_list = g_list_next(uri_list)) {
9618 gchar *uri = uri_list->data;
9619 MMPLAYER_FREEIF(uri);
9621 g_list_free(player->uri_info.uri_list);
9622 player->uri_info.uri_list = NULL;
9625 /* clear the audio stream buffer list */
9626 __mmplayer_audio_stream_clear_buffer(player, FALSE);
9628 /* clear the video stream bo list */
9629 __mmplayer_video_stream_destroy_bo_list(player);
9630 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
9632 if (player->profile.input_mem.buf) {
9633 free(player->profile.input_mem.buf);
9634 player->profile.input_mem.buf = NULL;
9636 player->profile.input_mem.len = 0;
9637 player->profile.input_mem.offset = 0;
9639 player->uri_info.uri_idx = 0;
9643 static GstElement *__mmplayer_element_create_and_link(mm_player_t *player, GstPad* pad, const char* name)
9645 GstElement *element = NULL;
9648 LOGD("creating %s to plug\n", name);
9650 element = gst_element_factory_make(name, NULL);
9652 LOGE("failed to create queue\n");
9656 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(element, GST_STATE_READY)) {
9657 LOGE("failed to set state READY to %s\n", name);
9658 gst_object_unref(element);
9662 if (!gst_bin_add(GST_BIN(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), element)) {
9663 LOGE("failed to add %s\n", name);
9664 gst_object_unref(element);
9668 sinkpad = gst_element_get_static_pad(element, "sink");
9670 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
9671 LOGE("failed to link %s\n", name);
9672 gst_object_unref(sinkpad);
9673 gst_object_unref(element);
9677 LOGD("linked %s to pipeline successfully\n", name);
9679 gst_object_unref(sinkpad);
9685 __mmplayer_check_subtitle(mm_player_t* player)
9687 MMHandleType attrs = 0;
9688 char *subtitle_uri = NULL;
9692 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9694 /* get subtitle attribute */
9695 attrs = MMPLAYER_GET_ATTRS(player);
9699 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
9700 if (!subtitle_uri || !strlen(subtitle_uri))
9703 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
9704 player->is_external_subtitle_present = TRUE;
9712 __mmplayer_can_extract_pcm(mm_player_t* player)
9714 MMHandleType attrs = 0;
9715 gboolean sound_extraction = FALSE;
9717 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
9719 attrs = MMPLAYER_GET_ATTRS(player);
9721 LOGE("fail to get attributes.");
9725 /* get sound_extraction property */
9726 mm_attrs_get_int_by_name(attrs, "pcm_extraction", &sound_extraction);
9728 if (!sound_extraction) {
9729 LOGD("checking pcm extraction mode : %d ", sound_extraction);
9737 __mmplayer_cancel_eos_timer(mm_player_t* player)
9739 MMPLAYER_RETURN_IF_FAIL(player);
9741 if (player->eos_timer) {
9742 LOGD("cancel eos timer");
9743 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
9744 player->eos_timer = 0;
9751 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
9755 MMPLAYER_RETURN_IF_FAIL(player);
9756 MMPLAYER_RETURN_IF_FAIL(sink);
9758 player->sink_elements =
9759 g_list_append(player->sink_elements, sink);
9765 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
9769 MMPLAYER_RETURN_IF_FAIL(player);
9770 MMPLAYER_RETURN_IF_FAIL(sink);
9772 player->sink_elements =
9773 g_list_remove(player->sink_elements, sink);
9778 /* NOTE : be careful with calling this api. please refer to below glib comment
9779 * glib comment : Note that there is a bug in GObject that makes this function much
9780 * less useful than it might seem otherwise. Once gobject is disposed, the callback
9781 * will no longer be called, but, the signal handler is not currently disconnected.
9782 * If the instance is itself being freed at the same time than this doesn't matter,
9783 * since the signal will automatically be removed, but if instance persists,
9784 * then the signal handler will leak. You should not remove the signal yourself
9785 * because in a future versions of GObject, the handler will automatically be
9788 * It's possible to work around this problem in a way that will continue to work
9789 * with future versions of GObject by checking that the signal handler is still
9790 * connected before disconnected it:
9792 * if (g_signal_handler_is_connected(instance, id))
9793 * g_signal_handler_disconnect(instance, id);
9796 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
9798 GList* sig_list = NULL;
9799 MMPlayerSignalItem* item = NULL;
9803 MMPLAYER_RETURN_IF_FAIL(player);
9805 LOGD("release signals type : %d", type);
9807 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
9808 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
9809 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
9810 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
9811 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
9812 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
9816 sig_list = player->signals[type];
9818 for (; sig_list; sig_list = sig_list->next) {
9819 item = sig_list->data;
9821 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
9822 if (g_signal_handler_is_connected(item->obj, item->sig))
9823 g_signal_handler_disconnect(item->obj, item->sig);
9826 MMPLAYER_FREEIF(item);
9829 g_list_free(player->signals[type]);
9830 player->signals[type] = NULL;
9837 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
9839 mm_player_t* player = 0;
9840 int prev_display_surface_type = 0;
9841 void *prev_display_overlay = NULL;
9842 const gchar *klass = NULL;
9843 gchar *cur_videosink_name = NULL;
9846 int num_of_dec = 2; /* DEC1, DEC2 */
9850 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
9851 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
9853 player = MM_PLAYER_CAST(handle);
9855 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
9856 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
9858 return MM_ERROR_INVALID_ARGUMENT;
9861 /* load previous attributes */
9862 if (player->attrs) {
9863 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
9864 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
9865 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
9866 if (prev_display_surface_type == surface_type) {
9867 LOGD("incoming display surface type is same as previous one, do nothing..");
9869 return MM_ERROR_NONE;
9872 LOGE("failed to load attributes");
9874 return MM_ERROR_PLAYER_INTERNAL;
9877 /* check videosink element is created */
9878 if (!player->pipeline || !player->pipeline->videobin ||
9879 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
9880 LOGD("videosink element is not yet ready");
9882 /* videobin is not created yet, so we just set attributes related to display surface */
9883 LOGD("store display attribute for given surface type(%d)", surface_type);
9884 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
9885 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
9886 if (mmf_attrs_commit(player->attrs)) {
9887 LOGE("failed to commit attribute");
9889 return MM_ERROR_PLAYER_INTERNAL;
9892 return MM_ERROR_NONE;
9894 /* get player command status */
9895 if (!(player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME || player->cmd == MMPLAYER_COMMAND_PAUSE)) {
9896 LOGE("invalid player command status(%d), __mmplayer_do_change_videosink() is only available with START/RESUME/PAUSE command", player->cmd);
9898 return MM_ERROR_PLAYER_INVALID_STATE;
9901 /* surface change */
9902 for (i = 0 ; i < num_of_dec ; i++) {
9903 if (player->pipeline->mainbin &&
9904 player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst) {
9905 GstElementFactory *decfactory;
9906 decfactory = gst_element_get_factory(player->pipeline->mainbin[MMPLAYER_M_DEC1+i].gst);
9908 klass = gst_element_factory_get_metadata(decfactory, GST_ELEMENT_METADATA_KLASS);
9909 if ((g_strrstr(klass, "Codec/Decoder/Video"))) {
9910 if ((prev_display_surface_type == MM_DISPLAY_SURFACE_OVERLAY) && (surface_type == MM_DISPLAY_SURFACE_REMOTE)) {
9911 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, "fakesink", surface_type, display_overlay);
9915 LOGW("success to changing display surface(%d)", surface_type);
9917 return MM_ERROR_NONE;
9919 } else if ((prev_display_surface_type == MM_DISPLAY_SURFACE_REMOTE) && (surface_type == MM_DISPLAY_SURFACE_OVERLAY)) {
9920 ret = __mmplayer_do_change_videosink(player, MMPLAYER_M_DEC1+i, player->ini.videosink_element_overlay, surface_type, display_overlay);
9924 LOGW("success to changing display surface(%d)", surface_type);
9926 return MM_ERROR_NONE;
9929 LOGE("invalid incoming surface type(%d) and current videosink_name(%s) for changing display surface", surface_type, cur_videosink_name);
9930 ret = MM_ERROR_PLAYER_INTERNAL;
9939 /* rollback to previous attributes */
9940 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", prev_display_surface_type);
9941 mm_attrs_set_data_by_name(player->attrs, "display_overlay", prev_display_overlay, sizeof(void*));
9942 if (mmf_attrs_commit(player->attrs)) {
9943 LOGE("failed to commit attributes to rollback");
9945 return MM_ERROR_PLAYER_INTERNAL;
9951 /* NOTE : It does not support some use cases, eg using colorspace converter */
9953 __mmplayer_do_change_videosink(mm_player_t* player, const int dec_index, const char *videosink_element, MMDisplaySurfaceType surface_type, void *display_overlay)
9955 GstPad *src_pad_dec = NULL;
9956 GstPad *sink_pad_videosink = NULL;
9957 GstPad *sink_pad_videobin = NULL;
9958 GstClock *clock = NULL;
9959 MMPlayerStateType previous_state = MM_PLAYER_STATE_NUM;
9960 int ret = MM_ERROR_NONE;
9961 gboolean is_audiobin_created = TRUE;
9965 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_COMMON_INVALID_ARGUMENT);
9966 MMPLAYER_RETURN_VAL_IF_FAIL(videosink_element, MM_ERROR_COMMON_INVALID_ARGUMENT);
9967 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
9969 LOGD("video dec is found(idx:%d), we are going to change videosink to %s", dec_index, videosink_element);
9970 LOGD("surface type(%d), display overlay(%x)", surface_type, display_overlay);
9972 /* get information whether if audiobin is created */
9973 if (!player->pipeline->audiobin ||
9974 !player->pipeline->audiobin[MMPLAYER_A_SINK].gst) {
9975 LOGW("audiobin is null, this video content may not have audio data");
9976 is_audiobin_created = FALSE;
9979 /* get current state of player */
9980 previous_state = MMPLAYER_CURRENT_STATE(player);
9981 LOGD("previous state(%d)", previous_state);
9984 /* get src pad of decoder and block it */
9985 src_pad_dec = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), "src");
9987 LOGE("failed to get src pad from decode in mainbin");
9988 return MM_ERROR_PLAYER_INTERNAL;
9991 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
9992 LOGW("trying to block pad(video)");
9993 // if (!gst_pad_set_blocked(src_pad_dec, TRUE))
9994 gst_pad_add_probe(src_pad_dec, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
9997 LOGE("failed to set block pad(video)");
9998 return MM_ERROR_PLAYER_INTERNAL;
10000 LOGW("pad is blocked(video)");
10002 /* no data flows, so no need to do pad_block */
10003 if (player->seek_state != MMPLAYER_SEEK_NONE)
10004 LOGW("not completed seek(%d), do nothing", player->seek_state);
10006 LOGD("MM_PLAYER_STATE is not PLAYING now, skip pad-block(TRUE)");
10010 if (!gst_element_remove_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst,
10011 GST_PAD_CAST(GST_GHOST_PAD(player->ghost_pad_for_videobin)))) {
10012 LOGE("failed to remove previous ghost_pad for videobin");
10013 return MM_ERROR_PLAYER_INTERNAL;
10016 /* change state of videobin to NULL */
10017 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_NULL);
10018 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL);
10019 if (ret != GST_STATE_CHANGE_SUCCESS) {
10020 LOGE("failed to change state of videobin to NULL");
10021 return MM_ERROR_PLAYER_INTERNAL;
10024 /* unlink between decoder and videobin and remove previous videosink from videobin */
10025 gst_element_unlink(GST_ELEMENT(player->pipeline->mainbin[dec_index].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst));
10026 if (!gst_bin_remove(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst))) {
10027 LOGE("failed to remove former videosink from videobin");
10028 return MM_ERROR_PLAYER_INTERNAL;
10031 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10033 /* create a new videosink and add it to videobin */
10034 player->pipeline->videobin[MMPLAYER_V_SINK].gst = gst_element_factory_make(videosink_element, "videosink");
10035 if (!player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
10036 LOGE("failed to create videosink element\n");
10038 return MM_ERROR_PLAYER_INTERNAL;
10040 gst_bin_add(GST_BIN(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst));
10041 __mmplayer_add_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10042 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "qos", TRUE, NULL);
10044 /* save attributes */
10045 if (player->attrs) {
10046 /* set a new display surface type */
10047 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
10048 /* set a new diplay overlay */
10049 switch (surface_type) {
10050 case MM_DISPLAY_SURFACE_OVERLAY:
10051 LOGD("save attributes related to video display surface : id = %d", *(int*)display_overlay);
10052 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
10055 LOGE("invalid type(%d) for changing display surface", surface_type);
10057 return MM_ERROR_INVALID_ARGUMENT;
10059 if (mmf_attrs_commit(player->attrs)) {
10060 LOGE("failed to commit");
10062 return MM_ERROR_PLAYER_INTERNAL;
10065 LOGE("player->attrs is null, failed to save attributes");
10067 return MM_ERROR_PLAYER_INTERNAL;
10070 /* update video param */
10071 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "update_all_param")) {
10072 LOGE("failed to update video param");
10073 return MM_ERROR_PLAYER_INTERNAL;
10076 /* change state of videobin to READY */
10077 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_READY);
10078 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_READY);
10079 if (ret != GST_STATE_CHANGE_SUCCESS) {
10080 LOGE("failed to change state of videobin to READY");
10081 return MM_ERROR_PLAYER_INTERNAL;
10084 /* change ghostpad */
10085 sink_pad_videosink = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "sink");
10086 if (!sink_pad_videosink) {
10087 LOGE("failed to get sink pad from videosink element");
10088 return MM_ERROR_PLAYER_INTERNAL;
10090 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", sink_pad_videosink);
10091 if (!gst_pad_set_active(player->ghost_pad_for_videobin, TRUE)) {
10092 LOGE("failed to set active to ghost_pad");
10093 return MM_ERROR_PLAYER_INTERNAL;
10095 if (FALSE == gst_element_add_pad(player->pipeline->videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
10096 LOGE("failed to change ghostpad for videobin");
10097 return MM_ERROR_PLAYER_INTERNAL;
10099 gst_object_unref(sink_pad_videosink);
10101 /* link decoder with videobin */
10102 sink_pad_videobin = gst_element_get_static_pad(GST_ELEMENT(player->pipeline->videobin[MMPLAYER_V_BIN].gst), "sink");
10103 if (!sink_pad_videobin) {
10104 LOGE("failed to get sink pad from videobin");
10105 return MM_ERROR_PLAYER_INTERNAL;
10107 if (GST_PAD_LINK_OK != gst_pad_link(src_pad_dec, sink_pad_videobin)) {
10108 LOGE("failed to link");
10109 return MM_ERROR_PLAYER_INTERNAL;
10111 gst_object_unref(sink_pad_videobin);
10113 /* clock setting for a new videosink plugin */
10114 /* NOTE : Below operation is needed, because a new videosink plugin doesn't have clock for basesink,
10115 so we set it from audiosink plugin or pipeline(system clock) */
10116 if (!is_audiobin_created) {
10117 LOGW("audiobin is not created, get clock from pipeline..");
10118 clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
10120 clock = GST_ELEMENT_CLOCK(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
10124 GstClockTime base_time;
10125 LOGD("set the clock to videosink");
10126 gst_element_set_clock(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), clock);
10127 clock = GST_ELEMENT_CLOCK(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10129 LOGD("got clock of videosink");
10130 now = gst_clock_get_time(clock);
10131 base_time = GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst)->base_time;
10132 LOGD("at time %" GST_TIME_FORMAT ", base %"
10133 GST_TIME_FORMAT, GST_TIME_ARGS(now), GST_TIME_ARGS(base_time));
10135 LOGE("failed to get clock of videosink after setting clock");
10136 return MM_ERROR_PLAYER_INTERNAL;
10139 LOGW("failed to get clock, maybe it is the time before first playing");
10141 if (player->seek_state == MMPLAYER_SEEK_NONE && previous_state == MM_PLAYER_STATE_PLAYING) {
10142 /* change state of videobin to PAUSED */
10143 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PLAYING);
10144 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PLAYING);
10145 if (ret != GST_STATE_CHANGE_FAILURE) {
10146 LOGW("change state of videobin to PLAYING, ret(%d)", ret);
10148 LOGE("failed to change state of videobin to PLAYING");
10149 return MM_ERROR_PLAYER_INTERNAL;
10152 /* release blocked and unref src pad of video decoder */
10154 if (!gst_pad_set_blocked(src_pad_dec, FALSE)) {
10155 LOGE("failed to set pad blocked FALSE(video)");
10156 return MM_ERROR_PLAYER_INTERNAL;
10159 LOGW("pad is unblocked(video)");
10161 if (player->seek_state != MMPLAYER_SEEK_NONE)
10162 LOGW("not completed seek(%d)", player->seek_state);
10163 /* change state of videobin to PAUSED */
10164 LOGD("setting [%s] state to : %d", GST_ELEMENT_NAME(player->pipeline->videobin[MMPLAYER_V_BIN].gst), GST_STATE_PAUSED);
10165 ret = gst_element_set_state(player->pipeline->videobin[MMPLAYER_V_BIN].gst, GST_STATE_PAUSED);
10166 if (ret != GST_STATE_CHANGE_FAILURE) {
10167 LOGW("change state of videobin to PAUSED, ret(%d)", ret);
10169 LOGE("failed to change state of videobin to PLAYING");
10170 return MM_ERROR_PLAYER_INTERNAL;
10173 /* already skipped pad block */
10174 LOGD("previous MM_PLAYER_STATE is not PLAYING, skip pad-block(FALSE)");
10177 /* do get/set position for new videosink plugin */
10179 gint64 position = 0;
10181 LOGD("do get/set position for new videosink plugin");
10182 if (__mmplayer_gst_get_position(player, MM_PLAYER_POS_FORMAT_TIME, &position)) {
10183 LOGE("failed to get position");
10184 return MM_ERROR_PLAYER_INTERNAL;
10186 #ifdef SINKCHANGE_WITH_ACCURATE_SEEK
10187 /* accurate seek */
10188 if (__mmplayer_gst_set_position(player, MM_PLAYER_POS_FORMAT_TIME, position, TRUE)) {
10189 LOGE("failed to set position");
10190 return MM_ERROR_PLAYER_INTERNAL;
10193 /* key unit seek */
10194 ret = __mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, 1.0,
10195 GST_FORMAT_TIME, (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),
10196 GST_SEEK_TYPE_SET, position,
10197 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
10199 LOGE("failed to set position");
10200 return MM_ERROR_PLAYER_INTERNAL;
10206 gst_object_unref(src_pad_dec);
10207 LOGD("success to change sink");
10211 return MM_ERROR_NONE;
10215 /* Note : if silent is true, then subtitle would not be displayed. :*/
10216 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
10218 mm_player_t* player = (mm_player_t*) hplayer;
10222 /* check player handle */
10223 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10225 player->set_mode.subtitle_off = silent;
10227 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
10231 return MM_ERROR_NONE;
10234 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
10236 MMPlayerGstElement* mainbin = NULL;
10237 MMPlayerGstElement* textbin = NULL;
10238 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
10239 GstState current_state = GST_STATE_VOID_PENDING;
10240 GstState element_state = GST_STATE_VOID_PENDING;
10241 GstState element_pending_state = GST_STATE_VOID_PENDING;
10243 GstEvent *event = NULL;
10244 int result = MM_ERROR_NONE;
10246 GstClock *curr_clock = NULL;
10247 GstClockTime base_time, start_time, curr_time;
10252 /* check player handle */
10253 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
10254 player->pipeline &&
10255 player->pipeline->mainbin &&
10256 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10258 mainbin = player->pipeline->mainbin;
10259 textbin = player->pipeline->textbin;
10261 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
10263 // sync clock with current pipeline
10264 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
10265 curr_time = gst_clock_get_time(curr_clock);
10267 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
10268 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
10270 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
10271 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
10273 if (current_state > GST_STATE_READY) {
10274 // sync state with current pipeline
10275 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
10276 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
10277 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
10279 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
10280 if (GST_STATE_CHANGE_FAILURE == ret) {
10281 LOGE("fail to state change.\n");
10282 result = MM_ERROR_PLAYER_INTERNAL;
10287 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
10288 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
10291 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
10292 gst_object_unref(curr_clock);
10295 // seek to current position
10296 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
10297 result = MM_ERROR_PLAYER_INVALID_STATE;
10298 LOGE("gst_element_query_position failed, invalid state\n");
10302 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
10303 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);
10305 __mmplayer_gst_send_event_to_sink(player, event);
10307 result = MM_ERROR_PLAYER_INTERNAL;
10308 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
10312 /* sync state with current pipeline */
10313 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
10314 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
10315 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
10317 return MM_ERROR_NONE;
10320 /* release text pipeline resource */
10321 player->textsink_linked = 0;
10323 /* release signal */
10324 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
10326 /* release textbin with it's childs */
10327 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
10328 MMPLAYER_FREEIF(player->pipeline->textbin);
10329 player->pipeline->textbin = NULL;
10331 /* release subtitle elem */
10332 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
10333 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
10339 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
10341 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
10342 GstState current_state = GST_STATE_VOID_PENDING;
10344 MMHandleType attrs = 0;
10345 MMPlayerGstElement* mainbin = NULL;
10346 MMPlayerGstElement* textbin = NULL;
10348 gchar* subtitle_uri = NULL;
10349 int result = MM_ERROR_NONE;
10350 const gchar *charset = NULL;
10354 /* check player handle */
10355 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
10356 player->pipeline &&
10357 player->pipeline->mainbin &&
10358 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10359 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
10361 mainbin = player->pipeline->mainbin;
10362 textbin = player->pipeline->textbin;
10364 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
10365 if (current_state < GST_STATE_READY) {
10366 result = MM_ERROR_PLAYER_INVALID_STATE;
10367 LOGE("Pipeline is not in proper state\n");
10371 attrs = MMPLAYER_GET_ATTRS(player);
10373 LOGE("cannot get content attribute\n");
10374 result = MM_ERROR_PLAYER_INTERNAL;
10378 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
10379 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
10380 LOGE("subtitle uri is not proper filepath\n");
10381 result = MM_ERROR_PLAYER_INVALID_URI;
10385 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
10386 LOGE("failed to get storage info of subtitle path");
10387 result = MM_ERROR_PLAYER_INVALID_URI;
10391 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
10392 LOGD("new subtitle file path is [%s]\n", filepath);
10394 if (!strcmp(filepath, subtitle_uri)) {
10395 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
10398 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
10399 if (mmf_attrs_commit(player->attrs)) {
10400 LOGE("failed to commit.\n");
10405 //gst_pad_set_blocked_async(src-srcpad, TRUE)
10406 MMPLAYER_SUBTITLE_INFO_LOCK(player);
10407 player->subtitle_language_list = NULL;
10408 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
10410 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
10411 if (ret != GST_STATE_CHANGE_SUCCESS) {
10412 LOGE("failed to change state of textbin to READY");
10413 result = MM_ERROR_PLAYER_INTERNAL;
10417 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
10418 if (ret != GST_STATE_CHANGE_SUCCESS) {
10419 LOGE("failed to change state of subparse to READY");
10420 result = MM_ERROR_PLAYER_INTERNAL;
10424 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
10425 if (ret != GST_STATE_CHANGE_SUCCESS) {
10426 LOGE("failed to change state of filesrc to READY");
10427 result = MM_ERROR_PLAYER_INTERNAL;
10431 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
10433 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
10435 charset = util_get_charset(filepath);
10437 LOGD("detected charset is %s\n", charset);
10438 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
10441 result = _mmplayer_sync_subtitle_pipeline(player);
10448 /* API to switch between external subtitles */
10449 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
10451 int result = MM_ERROR_NONE;
10452 mm_player_t* player = (mm_player_t*)hplayer;
10457 /* check player handle */
10458 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10460 /* filepath can be null in idle state */
10462 /* check file path */
10463 if ((path = strstr(filepath, "file://")))
10464 result = util_exist_file_path(path + 7);
10466 result = util_exist_file_path(filepath);
10468 if (result != MM_ERROR_NONE) {
10469 LOGE("invalid subtitle path 0x%X", result);
10470 return result; /* file not found or permission denied */
10474 if (!player->pipeline) {
10476 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
10477 if (mmf_attrs_commit(player->attrs)) {
10478 LOGE("failed to commit"); /* subtitle path will not be created */
10479 return MM_ERROR_PLAYER_INTERNAL;
10482 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
10483 /* check filepath */
10484 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
10486 if (!__mmplayer_check_subtitle(player)) {
10487 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
10488 if (mmf_attrs_commit(player->attrs)) {
10489 LOGE("failed to commit");
10490 return MM_ERROR_PLAYER_INTERNAL;
10493 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
10494 LOGE("fail to create text pipeline");
10495 return MM_ERROR_PLAYER_INTERNAL;
10498 result = _mmplayer_sync_subtitle_pipeline(player);
10500 result = __mmplayer_change_external_subtitle_language(player, filepath);
10503 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
10504 player->is_external_subtitle_added_now = TRUE;
10506 MMPLAYER_SUBTITLE_INFO_LOCK(player);
10507 if (!player->subtitle_language_list) {
10508 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
10509 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
10510 LOGW("subtitle language list is not updated yet");
10512 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
10520 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
10522 int result = MM_ERROR_NONE;
10523 gchar* change_pad_name = NULL;
10524 GstPad* sinkpad = NULL;
10525 MMPlayerGstElement* mainbin = NULL;
10526 enum MainElementID elemId = MMPLAYER_M_NUM;
10527 GstCaps* caps = NULL;
10528 gint total_track_num = 0;
10532 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
10533 MM_ERROR_PLAYER_NOT_INITIALIZED);
10535 LOGD("Change Track(%d) to %d\n", type, index);
10537 mainbin = player->pipeline->mainbin;
10539 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
10540 elemId = MMPLAYER_M_A_INPUT_SELECTOR;
10541 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
10542 elemId = MMPLAYER_M_T_INPUT_SELECTOR;
10544 /* Changing Video Track is not supported. */
10545 LOGE("Track Type Error\n");
10549 if (mainbin[elemId].gst == NULL) {
10550 result = MM_ERROR_PLAYER_NO_OP;
10551 LOGD("Req track doesn't exist\n");
10555 total_track_num = player->selector[type].total_track_num;
10556 if (total_track_num <= 0) {
10557 result = MM_ERROR_PLAYER_NO_OP;
10558 LOGD("Language list is not available \n");
10562 if ((index < 0) || (index >= total_track_num)) {
10563 result = MM_ERROR_INVALID_ARGUMENT;
10564 LOGD("Not a proper index : %d \n", index);
10568 /*To get the new pad from the selector*/
10569 change_pad_name = g_strdup_printf("sink_%u", index);
10570 if (change_pad_name == NULL) {
10571 result = MM_ERROR_PLAYER_INTERNAL;
10572 LOGD("Pad does not exists\n");
10576 LOGD("new active pad name: %s\n", change_pad_name);
10578 sinkpad = gst_element_get_static_pad(mainbin[elemId].gst, change_pad_name);
10579 if (sinkpad == NULL) {
10580 LOGD("sinkpad is NULL");
10581 result = MM_ERROR_PLAYER_INTERNAL;
10585 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
10586 g_object_set(mainbin[elemId].gst, "active-pad", sinkpad, NULL);
10588 caps = gst_pad_get_current_caps(sinkpad);
10589 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
10592 gst_object_unref(sinkpad);
10594 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
10595 __mmplayer_set_audio_attrs(player, caps);
10599 MMPLAYER_FREEIF(change_pad_name);
10603 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
10605 int result = MM_ERROR_NONE;
10606 mm_player_t* player = NULL;
10607 MMPlayerGstElement* mainbin = NULL;
10609 gint current_active_index = 0;
10611 GstState current_state = GST_STATE_VOID_PENDING;
10612 GstEvent* event = NULL;
10617 player = (mm_player_t*)hplayer;
10618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10620 if (!player->pipeline) {
10621 LOGE("Track %d pre setting -> %d\n", type, index);
10623 player->selector[type].active_pad_index = index;
10627 mainbin = player->pipeline->mainbin;
10629 current_active_index = player->selector[type].active_pad_index;
10631 /*If index is same as running index no need to change the pad*/
10632 if (current_active_index == index)
10635 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
10636 result = MM_ERROR_PLAYER_INVALID_STATE;
10640 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
10641 if (current_state < GST_STATE_PAUSED) {
10642 result = MM_ERROR_PLAYER_INVALID_STATE;
10643 LOGW("Pipeline not in porper state\n");
10647 result = __mmplayer_change_selector_pad(player, type, index);
10648 if (result != MM_ERROR_NONE) {
10649 LOGE("change selector pad error\n");
10653 player->selector[type].active_pad_index = index;
10655 if (current_state == GST_STATE_PLAYING) {
10656 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);
10658 __mmplayer_gst_send_event_to_sink(player, event);
10660 result = MM_ERROR_PLAYER_INTERNAL;
10669 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
10671 mm_player_t* player = (mm_player_t*) hplayer;
10675 /* check player handle */
10676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10678 *silent = player->set_mode.subtitle_off;
10680 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
10684 return MM_ERROR_NONE;
10688 _mmplayer_set_video_hub_download_mode(MMHandleType hplayer, bool mode)
10690 mm_player_t* player = (mm_player_t*) hplayer;
10692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10694 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL) {
10695 MMPLAYER_PRINT_STATE(player);
10696 LOGE("wrong-state : can't set the download mode to parse");
10697 return MM_ERROR_PLAYER_INVALID_STATE;
10700 LOGD("set video hub download mode to %s", (mode) ? "ON" : "OFF");
10701 player->video_hub_download_mode = mode;
10703 return MM_ERROR_NONE;
10707 _mmplayer_enable_sync_handler(MMHandleType hplayer, bool enable)
10709 mm_player_t* player = (mm_player_t*) hplayer;
10711 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10713 LOGD("enable sync handler : %s", (enable) ? "ON" : "OFF");
10714 player->sync_handler = enable;
10716 return MM_ERROR_NONE;
10720 _mmplayer_set_video_share_master_clock(MMHandleType hplayer, gint64 clock, gint64 clock_delta,
10721 gint64 video_time, gint64 media_clock, gint64 audio_time)
10723 mm_player_t* player = (mm_player_t*) hplayer;
10724 MMPlayerGstElement* mainbin = NULL;
10725 GstClockTime start_time_audio = 0, start_time_video = 0;
10726 GstClockTimeDiff base_time = 0, new_base_time = 0;
10727 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10728 gint64 api_delta = 0;
10729 gint64 position = 0, position_delta = 0;
10730 gint64 adj_base_time = 0;
10731 GstClock *curr_clock = NULL;
10732 GstClockTime curr_time = 0;
10733 gboolean query_ret = TRUE;
10734 int result = MM_ERROR_NONE;
10738 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10739 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10740 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
10742 /* LOGD("in(us) : %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT", %"G_GINT64_FORMAT,
10743 clock, clock_delta, video_time, media_clock, audio_time); */
10745 if ((video_time < 0) || (player->seek_state != MMPLAYER_SEEK_NONE)) {
10746 LOGD("skip setting master clock. %lld", video_time);
10750 mainbin = player->pipeline->mainbin;
10752 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
10753 curr_time = gst_clock_get_time(curr_clock);
10755 current_state = MMPLAYER_CURRENT_STATE(player);
10757 if (current_state == MM_PLAYER_STATE_PLAYING)
10758 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
10760 if ((current_state != MM_PLAYER_STATE_PLAYING) ||
10762 position = player->last_position;
10763 LOGD("query fail. %"G_GINT64_FORMAT, position);
10766 clock *= GST_USECOND;
10767 clock_delta *= GST_USECOND;
10769 api_delta = clock - curr_time;
10770 if ((player->video_share_api_delta == 0) || (player->video_share_api_delta > api_delta))
10771 player->video_share_api_delta = api_delta;
10773 clock_delta += (api_delta - player->video_share_api_delta);
10775 if ((player->video_share_clock_delta == 0) || (player->video_share_clock_delta > clock_delta)) {
10776 player->video_share_clock_delta = (gint64)clock_delta;
10778 position_delta = (position/GST_USECOND) - video_time;
10779 position_delta *= GST_USECOND;
10781 adj_base_time = position_delta;
10782 LOGD("video_share_clock_delta = %"G_GINT64_FORMAT", adj = %"G_GINT64_FORMAT, player->video_share_clock_delta, adj_base_time);
10785 gint64 new_play_time = 0;
10786 gint64 network_delay = 0;
10788 video_time *= GST_USECOND;
10790 network_delay = clock_delta - player->video_share_clock_delta;
10791 new_play_time = video_time + network_delay;
10793 adj_base_time = position - new_play_time;
10795 LOGD("%"G_GINT64_FORMAT"(delay) = %"G_GINT64_FORMAT" - %"G_GINT64_FORMAT" / %"G_GINT64_FORMAT
10796 "(adj) = %"G_GINT64_FORMAT"(slave_pos) - %"G_GINT64_FORMAT"(master_pos) - %"G_GINT64_FORMAT"(delay)",
10797 network_delay, clock_delta, player->video_share_clock_delta, adj_base_time, position, video_time, network_delay);
10800 /* Adjust Current Stream Time with base_time of sink
10801 * 1. Set Start time to CLOCK NONE, to control the base time by MSL
10802 * 2. Set new base time
10803 * if adj_base_time is positive value, the stream time will be decreased.
10804 * 3. If seek event is occurred, the start time will be reset. */
10805 if ((player->pipeline->audiobin) &&
10806 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst)) {
10807 start_time_audio = gst_element_get_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
10809 if (start_time_audio != GST_CLOCK_TIME_NONE) {
10810 LOGD("audio sink : gst_element_set_start_time -> NONE");
10811 gst_element_set_start_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, GST_CLOCK_TIME_NONE);
10814 base_time = gst_element_get_base_time(player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
10817 if ((player->pipeline->videobin) &&
10818 (player->pipeline->videobin[MMPLAYER_V_SINK].gst)) {
10819 start_time_video = gst_element_get_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10821 if (start_time_video != GST_CLOCK_TIME_NONE) {
10822 LOGD("video sink : gst_element_set_start_time -> NONE");
10823 gst_element_set_start_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst, GST_CLOCK_TIME_NONE);
10826 // if videobin exist, get base_time from videobin.
10827 base_time = gst_element_get_base_time(player->pipeline->videobin[MMPLAYER_V_SINK].gst);
10830 new_base_time = base_time + adj_base_time;
10832 if ((player->pipeline->audiobin) &&
10833 (player->pipeline->audiobin[MMPLAYER_A_SINK].gst))
10834 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->audiobin[MMPLAYER_A_SINK].gst), (GstClockTime)new_base_time);
10836 if ((player->pipeline->videobin) &&
10837 (player->pipeline->videobin[MMPLAYER_V_SINK].gst))
10838 gst_element_set_base_time(GST_ELEMENT_CAST(player->pipeline->videobin[MMPLAYER_V_SINK].gst), (GstClockTime)new_base_time);
10847 _mmplayer_get_video_share_master_clock(MMHandleType hplayer, gint64 *video_time, gint64 *media_clock, gint64 *audio_time)
10849 mm_player_t* player = (mm_player_t*) hplayer;
10850 MMPlayerGstElement* mainbin = NULL;
10851 GstClock *curr_clock = NULL;
10852 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
10853 gint64 position = 0;
10854 gboolean query_ret = TRUE;
10858 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
10859 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
10860 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, MM_ERROR_PLAYER_NOT_INITIALIZED);
10862 MMPLAYER_RETURN_VAL_IF_FAIL(video_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
10863 MMPLAYER_RETURN_VAL_IF_FAIL(media_clock, MM_ERROR_COMMON_INVALID_ARGUMENT);
10864 MMPLAYER_RETURN_VAL_IF_FAIL(audio_time, MM_ERROR_COMMON_INVALID_ARGUMENT);
10866 mainbin = player->pipeline->mainbin;
10868 curr_clock = gst_pipeline_get_clock(GST_PIPELINE_CAST(mainbin[MMPLAYER_M_PIPE].gst));
10870 current_state = MMPLAYER_CURRENT_STATE(player);
10872 if (current_state != MM_PLAYER_STATE_PAUSED)
10873 query_ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position);
10875 if ((current_state == MM_PLAYER_STATE_PAUSED) ||
10877 position = player->last_position;
10879 *media_clock = *video_time = *audio_time = (position/GST_USECOND);
10881 LOGD("media_clock: %"G_GINT64_FORMAT", video_time: %"G_GINT64_FORMAT"(us)", *media_clock, *video_time);
10884 gst_object_unref(curr_clock);
10888 return MM_ERROR_NONE;
10892 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
10894 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
10895 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
10897 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
10898 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
10902 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
10903 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
10904 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
10905 mm_player_dump_t *dump_s;
10906 dump_s = g_malloc(sizeof(mm_player_dump_t));
10908 if (dump_s == NULL) {
10909 LOGE("malloc fail");
10913 dump_s->dump_element_file = NULL;
10914 dump_s->dump_pad = NULL;
10915 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
10917 if (dump_s->dump_pad) {
10918 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
10919 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]);
10920 dump_s->dump_element_file = fopen(dump_file_name, "w+");
10921 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);
10922 /* add list for removed buffer probe and close FILE */
10923 player->dump_list = g_list_append(player->dump_list, dump_s);
10924 LOGD("%s sink pad added buffer probe for dump", factory_name);
10929 LOGE("failed to get %s sink pad added", factory_name);
10938 static GstPadProbeReturn
10939 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
10941 FILE *dump_data = (FILE *) u_data;
10942 // int written = 0;
10943 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
10944 GstMapInfo probe_info = GST_MAP_INFO_INIT;
10946 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
10948 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
10950 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
10952 fwrite(probe_info.data, 1, probe_info.size , dump_data);
10954 return GST_PAD_PROBE_OK;
10958 __mmplayer_release_dump_list(GList *dump_list)
10961 GList *d_list = dump_list;
10962 for (; d_list; d_list = g_list_next(d_list)) {
10963 mm_player_dump_t *dump_s = d_list->data;
10964 if (dump_s->dump_pad) {
10965 if (dump_s->probe_handle_id)
10966 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
10968 if (dump_s->dump_element_file) {
10969 fclose(dump_s->dump_element_file);
10970 dump_s->dump_element_file = NULL;
10972 MMPLAYER_FREEIF(dump_s);
10974 g_list_free(dump_list);
10980 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
10982 mm_player_t* player = (mm_player_t*) hplayer;
10986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
10987 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
10989 *exist = player->has_closed_caption;
10993 return MM_ERROR_NONE;
10996 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
11000 // LOGD("unref internal gst buffer %p", buffer);
11001 gst_buffer_unref((GstBuffer *)buffer);
11008 __gst_appsrc_feed_audio_data(GstElement *element, guint size, gpointer user_data)
11010 mm_player_t *player = (mm_player_t*)user_data;
11011 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
11012 guint64 current_level_bytes = 0;
11014 MMPLAYER_RETURN_IF_FAIL(player);
11016 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
11018 LOGI("app-src: feed audio(%llu)", current_level_bytes);
11019 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11021 if (player->media_stream_buffer_status_cb[type])
11022 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
11023 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11028 __gst_appsrc_feed_video_data(GstElement *element, guint size, gpointer user_data)
11030 mm_player_t *player = (mm_player_t*)user_data;
11031 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
11032 guint64 current_level_bytes = 0;
11034 MMPLAYER_RETURN_IF_FAIL(player);
11036 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
11038 LOGI("app-src: feed video(%llu)", current_level_bytes);
11040 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11041 if (player->media_stream_buffer_status_cb[type])
11042 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
11043 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11047 __gst_appsrc_feed_subtitle_data(GstElement *element, guint size, gpointer user_data)
11049 mm_player_t *player = (mm_player_t*)user_data;
11050 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
11051 guint64 current_level_bytes = 0;
11053 MMPLAYER_RETURN_IF_FAIL(player);
11055 LOGI("app-src: feed subtitle");
11057 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
11059 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11060 if (player->media_stream_buffer_status_cb[type])
11061 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]);
11063 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11067 __gst_appsrc_enough_audio_data(GstElement *element, gpointer user_data)
11069 mm_player_t *player = (mm_player_t*)user_data;
11070 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
11071 guint64 current_level_bytes = 0;
11073 MMPLAYER_RETURN_IF_FAIL(player);
11075 LOGI("app-src: audio buffer is full");
11077 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
11079 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11081 if (player->media_stream_buffer_status_cb[type])
11082 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
11084 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11088 __gst_appsrc_enough_video_data(GstElement *element, gpointer user_data)
11090 mm_player_t *player = (mm_player_t*)user_data;
11091 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
11092 guint64 current_level_bytes = 0;
11094 MMPLAYER_RETURN_IF_FAIL(player);
11096 LOGI("app-src: video buffer is full");
11098 g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL);
11100 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11101 if (player->media_stream_buffer_status_cb[type])
11102 player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]);
11104 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11108 __gst_seek_audio_data(GstElement * appsrc, guint64 position, gpointer user_data)
11110 mm_player_t *player = (mm_player_t*)user_data;
11111 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_AUDIO;
11113 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11115 LOGD("app-src: seek audio data %llu", position);
11116 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11118 if (player->media_stream_seek_data_cb[type])
11119 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
11120 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11126 __gst_seek_video_data(GstElement * appsrc, guint64 position, gpointer user_data)
11128 mm_player_t *player = (mm_player_t*)user_data;
11129 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_VIDEO;
11131 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11133 LOGD("app-src: seek video data %llu", position);
11134 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11135 if (player->media_stream_seek_data_cb[type])
11136 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
11137 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11143 __gst_seek_subtitle_data(GstElement * appsrc, guint64 position, gpointer user_data)
11145 mm_player_t *player = (mm_player_t*)user_data;
11146 MMPlayerStreamType type = MM_PLAYER_STREAM_TYPE_TEXT;
11148 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
11150 LOGD("app-src: seek subtitle data");
11151 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
11153 if (player->media_stream_seek_data_cb[type])
11154 player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]);
11155 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
11161 _mmplayer_set_pcm_spec(MMHandleType hplayer, int samplerate, int channel)
11163 mm_player_t* player = (mm_player_t*) hplayer;
11167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11169 player->pcm_samplerate = samplerate;
11170 player->pcm_channel = channel;
11173 return MM_ERROR_NONE;
11176 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
11178 mm_player_t* player = (mm_player_t*) hplayer;
11182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11183 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
11185 if (MMPLAYER_IS_HTTP_PD(player))
11186 *timeout = player->ini.live_state_change_timeout*2;
11187 else if (MMPLAYER_IS_STREAMING(player))
11188 *timeout = player->ini.live_state_change_timeout;
11190 *timeout = player->ini.localplayback_state_change_timeout;
11192 LOGD("timeout = %d\n", *timeout);
11195 return MM_ERROR_NONE;
11198 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
11200 mm_player_t* player = (mm_player_t*) hplayer;
11204 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11205 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
11207 *num = player->video_num_buffers;
11208 *extra_num = player->video_extra_num_buffers;
11210 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
11213 return MM_ERROR_NONE;
11217 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
11221 MMPLAYER_RETURN_IF_FAIL(player);
11223 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
11225 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
11226 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
11227 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
11228 player->storage_info[i].id = -1;
11229 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
11231 if (path_type != MMPLAYER_PATH_MAX)
11239 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
11241 int ret = MM_ERROR_NONE;
11242 mm_player_t* player = (mm_player_t*)hplayer;
11243 MMMessageParamType msg_param = {0, };
11246 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11248 LOGW("state changed storage %d:%d", id, state);
11250 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
11251 return MM_ERROR_NONE;
11253 /* FIXME: text path should be handled seperately. */
11254 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
11255 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
11256 LOGW("external storage is removed");
11258 if (player->msg_posted == FALSE) {
11259 memset(&msg_param, 0, sizeof(MMMessageParamType));
11260 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
11261 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
11262 player->msg_posted = TRUE;
11265 /* unrealize the player */
11266 ret = _mmplayer_unrealize(hplayer);
11267 if (ret != MM_ERROR_NONE)
11268 LOGE("failed to unrealize");
11275 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
11277 int ret = MM_ERROR_NONE;
11278 mm_player_t* player = (mm_player_t*) hplayer;
11279 int idx = 0, total = 0;
11280 gchar *result = NULL, *tmp = NULL;
11283 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11284 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
11286 total = *num = g_list_length(player->adaptive_info.var_list);
11288 LOGW("There is no stream variant info.");
11292 result = g_strdup("");
11293 for (idx = 0 ; idx < total ; idx++) {
11294 VariantData *v_data = NULL;
11295 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
11298 gchar data[64] = {0};
11299 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
11301 tmp = g_strconcat(result, data, NULL);
11305 LOGW("There is no variant data in %d", idx);
11310 *var_info = (char *)result;
11312 LOGD("variant info %d:%s", *num, *var_info);
11317 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
11319 int ret = MM_ERROR_NONE;
11320 mm_player_t* player = (mm_player_t*) hplayer;
11323 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11325 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
11327 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
11328 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
11329 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
11331 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
11332 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
11333 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
11334 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
11336 /* FIXME: seek to current position for applying new variant limitation */
11344 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
11346 int ret = MM_ERROR_NONE;
11347 mm_player_t* player = (mm_player_t*) hplayer;
11350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11351 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
11353 *bandwidth = player->adaptive_info.limit.bandwidth;
11354 *width = player->adaptive_info.limit.width;
11355 *height = player->adaptive_info.limit.height;
11357 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
11363 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
11365 int ret = MM_ERROR_NONE;
11366 mm_player_t* player = (mm_player_t*) hplayer;
11369 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11371 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
11372 LOGW("buffer_ms will not be applied.");
11375 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
11377 if (player->streamer == NULL) {
11378 player->streamer = __mm_player_streaming_create();
11379 __mm_player_streaming_initialize(player->streamer);
11382 if (buffer_ms >= 0)
11383 player->streamer->buffering_req.prebuffer_time = buffer_ms;
11385 if (rebuffer_ms >= 0)
11386 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
11393 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
11395 int ret = MM_ERROR_NONE;
11396 mm_player_t* player = (mm_player_t*) hplayer;
11399 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11400 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
11402 if (player->streamer == NULL) {
11403 player->streamer = __mm_player_streaming_create();
11404 __mm_player_streaming_initialize(player->streamer);
11407 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
11408 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
11410 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
11416 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
11418 #define IDX_FIRST_SW_CODEC 0
11419 mm_player_t* player = (mm_player_t*) hplayer;
11420 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
11421 MMHandleType attrs = 0;
11424 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11426 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
11427 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
11428 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
11430 switch (stream_type) {
11431 case MM_PLAYER_STREAM_TYPE_AUDIO:
11432 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
11433 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
11434 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
11435 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
11436 LOGE("There is no a codec for codec_type %d", codec_type);
11437 return MM_ERROR_PLAYER_NO_OP;
11440 case MM_PLAYER_STREAM_TYPE_VIDEO:
11441 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
11442 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
11443 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
11444 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
11445 LOGE("There is no v codec for codec_type %d", codec_type);
11446 return MM_ERROR_PLAYER_NO_OP;
11451 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
11452 return MM_ERROR_COMMON_INVALID_ARGUMENT;
11456 LOGD("update %s codec_type to %d", attr_name, codec_type);
11458 attrs = MMPLAYER_GET_ATTRS(player);
11459 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
11461 if (mmf_attrs_commit(player->attrs)) {
11462 LOGE("failed to commit codec_type attributes");
11463 return MM_ERROR_PLAYER_INTERNAL;
11467 return MM_ERROR_NONE;
11471 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
11473 mm_player_t* player = (mm_player_t*) hplayer;
11474 GstElement* rg_vol_element = NULL;
11478 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11480 player->sound.rg_enable = enabled;
11482 /* just hold rgvolume enable value if pipeline is not ready */
11483 if (!player->pipeline || !player->pipeline->audiobin) {
11484 LOGD("pipeline is not ready. holding rgvolume enable value\n");
11485 return MM_ERROR_NONE;
11488 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
11490 if (!rg_vol_element) {
11491 LOGD("rgvolume element is not created");
11492 return MM_ERROR_PLAYER_INTERNAL;
11496 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
11498 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
11502 return MM_ERROR_NONE;
11506 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
11508 mm_player_t* player = (mm_player_t*) hplayer;
11509 GstElement* rg_vol_element = NULL;
11510 gboolean enable = FALSE;
11514 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
11515 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
11517 /* just hold enable_rg value if pipeline is not ready */
11518 if (!player->pipeline || !player->pipeline->audiobin) {
11519 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
11520 *enabled = player->sound.rg_enable;
11521 return MM_ERROR_NONE;
11524 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
11526 if (!rg_vol_element) {
11527 LOGD("rgvolume element is not created");
11528 return MM_ERROR_PLAYER_INTERNAL;
11531 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
11536 return MM_ERROR_NONE;