4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.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 PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | GLOBAL VARIABLE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------
119 | LOCAL VARIABLE DEFINITIONS: |
120 ---------------------------------------------------------------------------*/
121 static sound_stream_info_h stream_info;
123 /*---------------------------------------------------------------------------
124 | LOCAL FUNCTION PROTOTYPES: |
125 ---------------------------------------------------------------------------*/
126 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
127 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
128 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
129 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
130 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
131 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
133 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
134 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
135 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
136 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
137 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
138 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
139 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
140 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
141 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
142 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
143 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
145 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
146 static void __mmplayer_release_misc(mm_player_t *player);
147 static void __mmplayer_release_misc_post(mm_player_t *player);
148 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
149 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
150 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
152 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
154 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
155 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
156 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
157 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
158 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
159 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
160 static gpointer __mmplayer_gapless_play_thread(gpointer data);
161 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
162 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static void __mmplayer_release_dump_list(GList *dump_list);
164 static int __mmplayer_gst_realize(mm_player_t *player);
165 static int __mmplayer_gst_unrealize(mm_player_t *player);
166 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
167 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
170 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
171 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
172 static void __mmplayer_check_pipeline(mm_player_t *player);
173 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
174 static void __mmplayer_deactivate_old_path(mm_player_t *player);
175 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
176 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
177 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
178 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
179 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
180 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
181 static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
182 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
183 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
186 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
187 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
188 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
190 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
191 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
192 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
193 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
195 static void __mmplayer_set_pause_state(mm_player_t *player);
196 static void __mmplayer_set_playing_state(mm_player_t *player);
197 /*===========================================================================================
199 | FUNCTION DEFINITIONS |
201 ========================================================================================== */
205 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
209 count = gst_tag_list_get_tag_size(list, tag);
211 LOGD("count = %d", count);
213 for (i = 0; i < count; i++) {
216 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
217 if (!gst_tag_list_get_string_index(list, tag, i, &str))
218 g_assert_not_reached();
220 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
224 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
226 g_print(" : %s", str);
233 /* This function should be called after the pipeline goes PAUSED or higher
236 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
238 static gboolean has_duration = FALSE;
239 static gboolean has_video_attrs = FALSE;
240 static gboolean has_audio_attrs = FALSE;
241 static gboolean has_bitrate = FALSE;
242 gboolean missing_only = FALSE;
243 gboolean all = FALSE;
244 MMHandleType attrs = 0;
248 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
250 /* check player state here */
251 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
252 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
253 /* give warning now only */
254 LOGW("be careful. content attributes may not available in this state ");
257 /* get content attribute first */
258 attrs = MMPLAYER_GET_ATTRS(player);
260 LOGE("cannot get content attribute");
264 /* get update flag */
266 if (flag & ATTR_MISSING_ONLY) {
268 LOGD("updating missed attr only");
271 if (flag & ATTR_ALL) {
273 has_duration = FALSE;
274 has_video_attrs = FALSE;
275 has_audio_attrs = FALSE;
278 LOGD("updating all attrs");
281 if (missing_only && all) {
282 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
283 missing_only = FALSE;
286 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
287 has_duration = __mmplayer_update_duration_attrs(player, attrs);
289 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
290 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
292 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
293 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
295 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
296 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
299 if (mm_attrs_commit_all(attrs)) {
300 LOGE("failed to update attributes");
310 __mmplayer_get_stream_service_type(mm_player_t *player)
312 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
316 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
318 player->pipeline->mainbin &&
319 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
320 STREAMING_SERVICE_NONE);
322 /* streaming service type if streaming */
323 if (!MMPLAYER_IS_STREAMING(player))
324 return STREAMING_SERVICE_NONE;
326 streaming_type = (player->duration == 0) ?
327 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
329 switch (streaming_type) {
330 case STREAMING_SERVICE_LIVE:
331 LOGD("it's live streaming");
333 case STREAMING_SERVICE_VOD:
334 LOGD("it's vod streaming");
337 LOGE("should not get here");
343 return streaming_type;
346 /* this function sets the player state and also report
347 * it to applicaton by calling callback function
350 __mmplayer_set_state(mm_player_t *player, int state)
352 MMMessageParamType msg = {0, };
354 MMPLAYER_RETURN_IF_FAIL(player);
356 if (MMPLAYER_CURRENT_STATE(player) == state) {
357 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
358 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
362 /* update player states */
363 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
364 MMPLAYER_CURRENT_STATE(player) = state;
366 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
370 MMPLAYER_PRINT_STATE(player);
372 switch (MMPLAYER_CURRENT_STATE(player)) {
373 case MM_PLAYER_STATE_NULL:
374 case MM_PLAYER_STATE_READY:
376 case MM_PLAYER_STATE_PAUSED:
377 __mmplayer_set_pause_state(player);
379 case MM_PLAYER_STATE_PLAYING:
380 __mmplayer_set_playing_state(player);
382 case MM_PLAYER_STATE_NONE:
384 LOGW("invalid target state, there is nothing to do.");
389 /* post message to application */
390 if (MMPLAYER_TARGET_STATE(player) == state) {
391 /* fill the message with state of player */
392 msg.union_type = MM_MSG_UNION_STATE;
393 msg.state.previous = MMPLAYER_PREV_STATE(player);
394 msg.state.current = MMPLAYER_CURRENT_STATE(player);
396 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
398 /* state changed by resource callback */
399 if (player->interrupted_by_resource)
400 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
401 else /* state changed by usecase */
402 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
405 LOGD("intermediate state, do nothing.");
406 MMPLAYER_PRINT_STATE(player);
410 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
411 && !player->sent_bos) {
412 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
413 player->sent_bos = TRUE;
420 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
422 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
423 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
425 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
427 //LOGD("incomming command : %d ", command);
429 current_state = MMPLAYER_CURRENT_STATE(player);
430 pending_state = MMPLAYER_PENDING_STATE(player);
432 MMPLAYER_PRINT_STATE(player);
435 case MMPLAYER_COMMAND_CREATE:
437 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
439 if (current_state == MM_PLAYER_STATE_NULL ||
440 current_state == MM_PLAYER_STATE_READY ||
441 current_state == MM_PLAYER_STATE_PAUSED ||
442 current_state == MM_PLAYER_STATE_PLAYING)
447 case MMPLAYER_COMMAND_DESTROY:
449 /* destroy can called anytime */
451 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
455 case MMPLAYER_COMMAND_REALIZE:
457 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
459 if (pending_state != MM_PLAYER_STATE_NONE) {
462 /* need ready state to realize */
463 if (current_state == MM_PLAYER_STATE_READY)
466 if (current_state != MM_PLAYER_STATE_NULL)
472 case MMPLAYER_COMMAND_UNREALIZE:
474 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
476 if (current_state == MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_START:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
485 if (pending_state == MM_PLAYER_STATE_NONE) {
486 if (current_state == MM_PLAYER_STATE_PLAYING)
488 else if (current_state != MM_PLAYER_STATE_READY &&
489 current_state != MM_PLAYER_STATE_PAUSED)
491 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
493 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
494 LOGD("player is going to paused state, just change the pending state as playing");
501 case MMPLAYER_COMMAND_STOP:
503 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
505 if (current_state == MM_PLAYER_STATE_READY)
508 /* need playing/paused state to stop */
509 if (current_state != MM_PLAYER_STATE_PLAYING &&
510 current_state != MM_PLAYER_STATE_PAUSED)
515 case MMPLAYER_COMMAND_PAUSE:
517 if (MMPLAYER_IS_LIVE_STREAMING(player))
520 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
521 goto NOT_COMPLETED_SEEK;
523 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
525 if (pending_state == MM_PLAYER_STATE_NONE) {
526 if (current_state == MM_PLAYER_STATE_PAUSED)
528 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
530 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
532 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
534 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
541 case MMPLAYER_COMMAND_RESUME:
543 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
544 goto NOT_COMPLETED_SEEK;
546 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
548 if (pending_state == MM_PLAYER_STATE_NONE) {
549 if (current_state == MM_PLAYER_STATE_PLAYING)
551 else if (current_state != MM_PLAYER_STATE_PAUSED)
553 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
555 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
556 LOGD("player is going to paused state, just change the pending state as playing");
566 player->cmd = command;
568 return MM_ERROR_NONE;
571 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
572 MMPLAYER_STATE_GET_NAME(current_state), command);
573 return MM_ERROR_PLAYER_INVALID_STATE;
576 LOGW("not completed seek");
577 return MM_ERROR_PLAYER_DOING_SEEK;
580 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
581 return MM_ERROR_PLAYER_NO_OP;
584 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
585 return MM_ERROR_PLAYER_NO_OP;
589 __mmplayer_gapless_play_thread(gpointer data)
591 mm_player_t *player = (mm_player_t *)data;
592 MMPlayerGstElement *mainbin = NULL;
594 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
596 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
597 while (!player->gapless_play_thread_exit) {
598 LOGD("gapless play thread started. waiting for signal.");
599 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
601 LOGD("reconfigure pipeline for gapless play.");
603 if (player->gapless_play_thread_exit) {
604 if (player->gapless.reconfigure) {
605 player->gapless.reconfigure = false;
606 MMPLAYER_PLAYBACK_UNLOCK(player);
608 LOGD("exiting gapless play thread");
612 mainbin = player->pipeline->mainbin;
614 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
615 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
616 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
617 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
618 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
620 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
622 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
628 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
630 GSource *source = NULL;
634 source = g_main_context_find_source_by_id(context, source_id);
635 if (source != NULL) {
636 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
637 g_source_destroy(source);
644 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
646 mm_player_t *player = (mm_player_t *)hplayer;
647 GstMessage *msg = NULL;
648 GQueue *queue = NULL;
651 MMPLAYER_RETURN_IF_FAIL(player);
653 /* disconnecting bus watch */
654 if (player->bus_watcher)
655 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
656 player->bus_watcher = 0;
658 /* destroy the gst bus msg thread */
659 if (player->bus_msg_thread) {
660 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
661 player->bus_msg_thread_exit = TRUE;
662 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
663 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
665 LOGD("gst bus msg thread exit.");
666 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
667 player->bus_msg_thread = NULL;
669 g_mutex_clear(&player->bus_msg_thread_mutex);
670 g_cond_clear(&player->bus_msg_thread_cond);
673 g_mutex_lock(&player->bus_msg_q_lock);
674 queue = player->bus_msg_q;
675 while (!g_queue_is_empty(queue)) {
676 msg = (GstMessage *)g_queue_pop_head(queue);
681 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
682 gst_message_unref(msg);
684 g_mutex_unlock(&player->bus_msg_q_lock);
690 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
692 GstElement *parent = NULL;
694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
696 /* if we have no fakesink. this meas we are using decodebin which doesn'
697 t need to add extra fakesink */
698 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
701 MMPLAYER_FSINK_LOCK(player);
706 /* get parent of fakesink */
707 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
709 LOGD("fakesink already removed");
713 gst_element_set_locked_state(fakesink->gst, TRUE);
715 /* setting the state to NULL never returns async
716 * so no need to wait for completion of state transiton
718 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
719 LOGE("fakesink state change failure!");
720 /* FIXIT : should I return here? or try to proceed to next? */
723 /* remove fakesink from it's parent */
724 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
725 LOGE("failed to remove fakesink");
727 gst_object_unref(parent);
732 gst_object_unref(parent);
734 LOGD("state-holder removed");
736 gst_element_set_locked_state(fakesink->gst, FALSE);
738 MMPLAYER_FSINK_UNLOCK(player);
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
749 static GstPadProbeReturn
750 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
752 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
753 return GST_PAD_PROBE_OK;
757 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
759 gint64 stop_running_time = 0;
760 gint64 position_running_time = 0;
764 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
765 if ((player->gapless.update_segment[idx] == TRUE) ||
766 !(player->selector[idx].event_probe_id)) {
767 /* LOGW("[%d] skip", idx); */
771 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
773 gst_segment_to_running_time(&player->gapless.segment[idx],
774 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
775 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
777 gst_segment_to_running_time(&player->gapless.segment[idx],
778 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
780 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
782 gst_segment_to_running_time(&player->gapless.segment[idx],
783 GST_FORMAT_TIME, player->duration);
786 position_running_time =
787 gst_segment_to_running_time(&player->gapless.segment[idx],
788 GST_FORMAT_TIME, player->gapless.segment[idx].position);
790 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
791 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
793 GST_TIME_ARGS(stop_running_time),
794 GST_TIME_ARGS(position_running_time),
795 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
796 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
798 position_running_time = MAX(position_running_time, stop_running_time);
799 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
800 GST_FORMAT_TIME, player->gapless.segment[idx].start);
801 position_running_time = MAX(0, position_running_time);
802 position = MAX(position, position_running_time);
806 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
807 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
808 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
810 player->gapless.start_time[stream_type] += position;
816 static GstPadProbeReturn
817 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
819 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
820 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
821 mm_player_t *player = (mm_player_t *)data;
822 GstCaps *caps = NULL;
823 GstStructure *str = NULL;
824 const gchar *name = NULL;
825 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
826 gboolean caps_ret = TRUE;
828 if (GST_EVENT_IS_DOWNSTREAM(event) &&
829 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
830 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
831 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
832 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
834 } else if (GST_EVENT_IS_UPSTREAM(event) &&
835 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
839 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
843 if (strstr(name, "audio")) {
844 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
845 } else if (strstr(name, "video")) {
846 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
848 /* text track is not supportable */
849 LOGE("invalid name %s", name);
853 switch (GST_EVENT_TYPE(event)) {
856 /* in case of gapless, drop eos event not to send it to sink */
857 if (player->gapless.reconfigure && !player->msg_posted) {
858 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
859 ret = GST_PAD_PROBE_DROP;
863 case GST_EVENT_STREAM_START:
865 __mmplayer_gst_selector_update_start_time(player, stream_type);
868 case GST_EVENT_FLUSH_STOP:
870 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
871 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
872 player->gapless.start_time[stream_type] = 0;
875 case GST_EVENT_SEGMENT:
880 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
881 gst_event_copy_segment(event, &segment);
883 if (segment.format != GST_FORMAT_TIME)
886 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
887 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
888 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
889 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
890 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
891 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
893 /* keep the all the segment ev to cover the seeking */
894 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
895 player->gapless.update_segment[stream_type] = TRUE;
897 if (!player->gapless.running)
900 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
902 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
904 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
905 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
906 gst_event_unref(event);
907 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
913 gdouble proportion = 0.0;
914 GstClockTimeDiff diff = 0;
915 GstClockTime timestamp = 0;
916 gint64 running_time_diff = -1;
918 GstEvent *tmpev = NULL;
920 running_time_diff = player->gapless.segment[stream_type].base;
922 if (running_time_diff <= 0) /* don't need to adjust */
925 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
926 gst_event_unref(event);
928 if (timestamp < running_time_diff) {
929 LOGW("QOS event from previous group");
930 ret = GST_PAD_PROBE_DROP;
934 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
935 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
936 stream_type, GST_TIME_ARGS(timestamp),
937 GST_TIME_ARGS(running_time_diff),
938 GST_TIME_ARGS(timestamp - running_time_diff));
940 timestamp -= running_time_diff;
942 /* That case is invalid for QoS events */
943 if (diff < 0 && -diff > timestamp) {
944 LOGW("QOS event from previous group");
945 ret = GST_PAD_PROBE_DROP;
949 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
950 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
960 gst_caps_unref(caps);
964 /* create fakesink for audio or video path witout audiobin or videobin */
966 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
968 GstElement *pipeline = NULL;
969 GstElement *fakesink = NULL;
970 GstPad *sinkpad = NULL;
973 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
975 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
978 fakesink = gst_element_factory_make("fakesink", NULL);
979 if (fakesink == NULL) {
980 LOGE("failed to create fakesink");
984 /* store it as it's sink element */
985 __mmplayer_add_sink(player, fakesink);
987 gst_bin_add(GST_BIN(pipeline), fakesink);
990 sinkpad = gst_element_get_static_pad(fakesink, "sink");
992 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
994 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
995 LOGE("failed to link fakesink");
996 gst_object_unref(GST_OBJECT(fakesink));
1000 if (strstr(name, "video")) {
1001 if (player->v_stream_caps) {
1002 gst_caps_unref(player->v_stream_caps);
1003 player->v_stream_caps = NULL;
1005 if (player->ini.set_dump_element_flag)
1006 __mmplayer_add_dump_buffer_probe(player, fakesink);
1009 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1010 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1014 gst_object_unref(GST_OBJECT(sinkpad));
1021 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1023 GstElement *pipeline = NULL;
1024 GstElement *selector = NULL;
1025 GstPad *srcpad = NULL;
1028 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1030 selector = gst_element_factory_make("input-selector", NULL);
1032 LOGE("failed to create input-selector");
1035 g_object_set(selector, "sync-streams", TRUE, NULL);
1037 player->pipeline->mainbin[elem_idx].id = elem_idx;
1038 player->pipeline->mainbin[elem_idx].gst = selector;
1040 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1042 srcpad = gst_element_get_static_pad(selector, "src");
1044 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1045 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1046 __mmplayer_gst_selector_blocked, NULL, NULL);
1047 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1048 __mmplayer_gst_selector_event_probe, player, NULL);
1050 gst_element_set_state(selector, GST_STATE_PAUSED);
1052 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1053 gst_bin_add(GST_BIN(pipeline), selector);
1060 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1062 mm_player_t *player = (mm_player_t *)data;
1063 GstElement *selector = NULL;
1064 GstCaps *caps = NULL;
1065 GstStructure *str = NULL;
1066 const gchar *name = NULL;
1067 GstPad *sinkpad = NULL;
1068 gboolean first_track = FALSE;
1069 gboolean caps_ret = TRUE;
1071 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1072 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1075 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 LOGD("pad-added signal handling");
1080 /* get mimetype from caps */
1081 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1085 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1086 /* LOGD("detected mimetype : %s", name); */
1088 if (strstr(name, "video")) {
1090 gchar *caps_str = NULL;
1092 caps_str = gst_caps_to_string(caps);
1093 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1094 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1095 player->set_mode.video_zc = true;
1097 MMPLAYER_FREEIF(caps_str);
1099 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1100 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1102 LOGD("surface type : %d", stype);
1104 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1105 __mmplayer_gst_create_sinkbin(elem, pad, player);
1109 /* in case of exporting video frame, it requires the 360 video filter.
1110 * it will be handled in _no_more_pads(). */
1111 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
1112 __mmplayer_gst_make_fakesink(player, pad, name);
1116 LOGD("video selector is required");
1117 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1118 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1119 } else if (strstr(name, "audio")) {
1120 gint samplerate = 0;
1123 gst_structure_get_int(str, "rate", &samplerate);
1124 gst_structure_get_int(str, "channels", &channels);
1126 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1127 __mmplayer_gst_create_sinkbin(elem, pad, player);
1131 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1132 __mmplayer_gst_make_fakesink(player, pad, name);
1136 LOGD("audio selector is required");
1137 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1138 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1140 } else if (strstr(name, "text")) {
1141 LOGD("text selector is required");
1142 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1143 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1145 LOGE("invalid caps info");
1149 /* check selector and create it */
1150 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1151 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1156 LOGD("input-selector is already created.");
1160 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1162 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1164 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1165 LOGE("failed to link selector");
1166 gst_object_unref(GST_OBJECT(selector));
1171 LOGD("this track will be activated");
1172 g_object_set(selector, "active-pad", sinkpad, NULL);
1175 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1181 gst_caps_unref(caps);
1184 gst_object_unref(GST_OBJECT(sinkpad));
1192 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1194 GstPad *srcpad = NULL;
1197 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1199 LOGD("type %d", type);
1202 LOGD("there is no %d track", type);
1206 srcpad = gst_element_get_static_pad(selector, "src");
1208 LOGE("failed to get srcpad from selector");
1212 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1214 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1216 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1217 if (player->selector[type].block_id) {
1218 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1219 player->selector[type].block_id = 0;
1223 gst_object_unref(GST_OBJECT(srcpad));
1232 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1234 MMHandleType attrs = 0;
1235 gint active_index = 0;
1238 MMPLAYER_RETURN_IF_FAIL(player);
1240 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1242 /* change track to active pad */
1243 active_index = player->selector[type].active_pad_index;
1244 if ((active_index != DEFAULT_TRACK) &&
1245 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1246 LOGW("failed to change %d type track to %d", type, active_index);
1247 player->selector[type].active_pad_index = DEFAULT_TRACK;
1251 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1252 attrs = MMPLAYER_GET_ATTRS(player);
1254 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1255 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1257 if (mm_attrs_commit_all(attrs))
1258 LOGW("failed to commit attrs.");
1260 LOGW("cannot get content attribute");
1269 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1274 if (!audio_selector) {
1275 LOGD("there is no audio track");
1277 /* in case the source is changed, output can be changed. */
1278 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1279 LOGD("remove previous audiobin if it exist");
1281 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1282 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1284 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1285 MMPLAYER_FREEIF(player->pipeline->audiobin);
1288 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1289 __mmplayer_pipeline_complete(NULL, player);
1294 /* apply the audio track information */
1295 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1297 /* create audio sink path */
1298 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1299 LOGE("failed to create audio sink path");
1308 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1311 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1313 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1314 LOGD("text path is not supproted");
1318 /* apply the text track information */
1319 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1321 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1322 player->has_closed_caption = TRUE;
1324 /* create text decode path */
1325 player->no_more_pad = TRUE;
1327 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1328 LOGE("failed to create text sink path");
1337 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1339 gint64 dur_bytes = 0L;
1342 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1343 player->pipeline->mainbin && player->streamer, FALSE);
1345 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1346 LOGE("fail to get duration.");
1348 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1349 * use file information was already set on Q2 when it was created. */
1350 __mm_player_streaming_set_queue2(player->streamer,
1351 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1352 TRUE, /* use_buffering */
1353 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1354 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1361 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1363 mm_player_t *player = NULL;
1364 GstElement *video_selector = NULL;
1365 GstElement *audio_selector = NULL;
1366 GstElement *text_selector = NULL;
1369 player = (mm_player_t *)data;
1371 LOGD("no-more-pad signal handling");
1373 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1374 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1375 LOGW("player is shutting down");
1379 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1380 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1381 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1382 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1383 LOGE("failed to set queue2 buffering");
1388 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1389 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1390 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1392 /* create video path followed by video-select */
1393 if (video_selector && !audio_selector && !text_selector)
1394 player->no_more_pad = TRUE;
1396 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1399 /* create audio path followed by audio-select */
1400 if (audio_selector && !text_selector)
1401 player->no_more_pad = TRUE;
1403 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1406 /* create text path followed by text-select */
1407 __mmplayer_create_text_sink_path(player, text_selector);
1410 if (player->gapless.reconfigure) {
1411 player->gapless.reconfigure = FALSE;
1412 MMPLAYER_PLAYBACK_UNLOCK(player);
1419 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1421 gboolean ret = FALSE;
1422 GstElement *pipeline = NULL;
1423 GstPad *sinkpad = NULL;
1426 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1429 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1431 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1433 LOGE("failed to get pad from sinkbin");
1439 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1440 LOGE("failed to link sinkbin for reusing");
1441 goto EXIT; /* exit either pass or fail */
1445 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1446 LOGE("failed to set state(READY) to sinkbin");
1451 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1452 LOGE("failed to add sinkbin to pipeline");
1457 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1458 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1463 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1464 LOGE("failed to set state(PAUSED) to sinkbin");
1473 gst_object_unref(GST_OBJECT(sinkpad));
1481 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1483 mm_player_t *player = NULL;
1484 GstCaps *caps = NULL;
1485 gchar *caps_str = NULL;
1486 GstStructure *str = NULL;
1487 const gchar *name = NULL;
1488 GstElement *sinkbin = NULL;
1489 gboolean reusing = FALSE;
1490 gboolean caps_ret = TRUE;
1491 gchar *sink_pad_name = "sink";
1494 player = (mm_player_t *)data;
1497 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1498 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1500 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1504 caps_str = gst_caps_to_string(caps);
1506 /* LOGD("detected mimetype : %s", name); */
1507 if (strstr(name, "audio")) {
1508 if (player->pipeline->audiobin == NULL) {
1509 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1510 LOGE("failed to create audiobin. continuing without audio");
1514 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1515 LOGD("creating audiobin success");
1518 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1519 LOGD("reusing audiobin");
1520 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1522 } else if (strstr(name, "video")) {
1523 /* 1. zero copy is updated at _decode_pad_added()
1524 * 2. NULL surface type is handled in _decode_pad_added() */
1525 LOGD("zero copy %d", player->set_mode.video_zc);
1526 if (player->pipeline->videobin == NULL) {
1527 int surface_type = 0;
1528 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1529 LOGD("display_surface_type (%d)", surface_type);
1531 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1532 LOGD("mark video overlay for acquire");
1533 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1534 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1535 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1536 &player->video_overlay_resource)
1537 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1538 LOGE("could not mark video_overlay resource for acquire");
1543 player->interrupted_by_resource = FALSE;
1545 if (mm_resource_manager_commit(player->resource_manager) !=
1546 MM_RESOURCE_MANAGER_ERROR_NONE) {
1547 LOGE("could not acquire resources for video playing");
1551 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1552 LOGE("failed to create videobin. continuing without video");
1556 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1557 LOGD("creating videosink bin success");
1560 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1561 LOGD("re-using videobin");
1562 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1564 } else if (strstr(name, "text")) {
1565 if (player->pipeline->textbin == NULL) {
1566 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1567 LOGE("failed to create text sink bin. continuing without text");
1571 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1572 player->textsink_linked = 1;
1573 LOGD("creating textsink bin success");
1575 if (!player->textsink_linked) {
1576 LOGD("re-using textbin");
1578 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1579 player->textsink_linked = 1;
1581 /* linked textbin exist which means that the external subtitle path exist already */
1582 LOGW("ignoring internal subtutle since external subtitle is available");
1585 sink_pad_name = "text_sink";
1587 LOGW("unknown mime type %s, ignoring it", name);
1591 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1594 LOGD("[handle: %p] success to create and link sink bin", player);
1596 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1597 * streaming task. if the task blocked, then buffer will not flow to the next element
1598 *(autoplugging element). so this is special hack for streaming. please try to remove it
1600 /* dec stream count. we can remove fakesink if it's zero */
1601 if (player->num_dynamic_pad)
1602 player->num_dynamic_pad--;
1604 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1606 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1607 __mmplayer_pipeline_complete(NULL, player);
1611 MMPLAYER_FREEIF(caps_str);
1614 gst_caps_unref(caps);
1620 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1622 int required_angle = 0; /* Angle required for straight view */
1623 int rotation_angle = 0;
1625 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1626 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1628 /* Counter clockwise */
1629 switch (orientation) {
1634 required_angle = 270;
1637 required_angle = 180;
1640 required_angle = 90;
1644 rotation_angle = display_angle + required_angle;
1645 if (rotation_angle >= 360)
1646 rotation_angle -= 360;
1648 /* chech if supported or not */
1649 if (rotation_angle % 90) {
1650 LOGD("not supported rotation angle = %d", rotation_angle);
1654 switch (rotation_angle) {
1656 *value = MM_DISPLAY_ROTATION_NONE;
1659 *value = MM_DISPLAY_ROTATION_90;
1662 *value = MM_DISPLAY_ROTATION_180;
1665 *value = MM_DISPLAY_ROTATION_270;
1669 LOGD("setting rotation property value : %d", *value);
1675 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1677 /* check video sinkbin is created */
1678 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1680 player->pipeline->videobin &&
1681 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1682 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1683 MM_ERROR_PLAYER_NOT_INITIALIZED);
1685 return MM_ERROR_NONE;
1689 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1691 int display_rotation = 0;
1692 gchar *org_orient = NULL;
1693 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1696 LOGE("cannot get content attribute");
1697 return MM_ERROR_PLAYER_INTERNAL;
1700 if (display_angle) {
1701 /* update user roation */
1702 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1704 /* Counter clockwise */
1705 switch (display_rotation) {
1706 case MM_DISPLAY_ROTATION_NONE:
1709 case MM_DISPLAY_ROTATION_90:
1710 *display_angle = 90;
1712 case MM_DISPLAY_ROTATION_180:
1713 *display_angle = 180;
1715 case MM_DISPLAY_ROTATION_270:
1716 *display_angle = 270;
1719 LOGW("wrong angle type : %d", display_rotation);
1722 LOGD("check user angle: %d", *display_angle);
1726 /* Counter clockwise */
1727 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1730 if (!strcmp(org_orient, "rotate-90"))
1732 else if (!strcmp(org_orient, "rotate-180"))
1734 else if (!strcmp(org_orient, "rotate-270"))
1737 LOGD("original rotation is %s", org_orient);
1739 LOGD("content_video_orientation get fail");
1742 LOGD("check orientation: %d", *orientation);
1745 return MM_ERROR_NONE;
1749 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1751 int rotation_value = 0;
1752 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1753 int display_angle = 0;
1756 /* check video sinkbin is created */
1757 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1760 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1762 /* get rotation value to set */
1763 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1764 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1765 LOGD("set video param : rotate %d", rotation_value);
1769 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1771 MMHandleType attrs = 0;
1775 /* check video sinkbin is created */
1776 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1779 attrs = MMPLAYER_GET_ATTRS(player);
1780 MMPLAYER_RETURN_IF_FAIL(attrs);
1782 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1783 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1784 LOGD("set video param : visible %d", visible);
1788 __mmplayer_video_param_set_display_method(mm_player_t *player)
1790 MMHandleType attrs = 0;
1791 int display_method = 0;
1794 /* check video sinkbin is created */
1795 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1798 attrs = MMPLAYER_GET_ATTRS(player);
1799 MMPLAYER_RETURN_IF_FAIL(attrs);
1801 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1802 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1803 LOGD("set video param : method %d", display_method);
1807 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1809 MMHandleType attrs = 0;
1810 void *handle = NULL;
1813 /* check video sinkbin is created */
1814 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1815 LOGW("There is no video sink");
1819 attrs = MMPLAYER_GET_ATTRS(player);
1820 MMPLAYER_RETURN_IF_FAIL(attrs);
1821 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1823 gst_video_overlay_set_video_roi_area(
1824 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1825 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1826 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1827 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1832 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1834 MMHandleType attrs = 0;
1835 void *handle = NULL;
1839 int win_roi_width = 0;
1840 int win_roi_height = 0;
1843 /* check video sinkbin is created */
1844 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1845 LOGW("There is no video sink");
1849 attrs = MMPLAYER_GET_ATTRS(player);
1850 MMPLAYER_RETURN_IF_FAIL(attrs);
1852 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1855 /* It should be set after setting window */
1856 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1857 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1858 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1859 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1861 /* After setting window handle, set display roi area */
1862 gst_video_overlay_set_display_roi_area(
1863 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1864 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1865 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1866 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1871 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1873 MMHandleType attrs = 0;
1874 void *handle = NULL;
1876 /* check video sinkbin is created */
1877 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1880 attrs = MMPLAYER_GET_ATTRS(player);
1881 MMPLAYER_RETURN_IF_FAIL(attrs);
1883 /* common case if using overlay surface */
1884 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1887 /* default is using wl_surface_id */
1888 unsigned int wl_surface_id = 0;
1889 wl_surface_id = *(int *)handle;
1890 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1891 gst_video_overlay_set_wl_window_wl_surface_id(
1892 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1895 /* FIXIT : is it error case? */
1896 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1901 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1903 gboolean update_all_param = FALSE;
1906 /* check video sinkbin is created */
1907 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1908 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1910 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1911 LOGE("can not find tizenwlsink");
1912 return MM_ERROR_PLAYER_INTERNAL;
1915 LOGD("param_name : %s", param_name);
1916 if (!g_strcmp0(param_name, "update_all_param"))
1917 update_all_param = TRUE;
1919 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1920 __mmplayer_video_param_set_display_overlay(player);
1921 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1922 __mmplayer_video_param_set_display_method(player);
1923 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1924 __mmplayer_video_param_set_display_visible(player);
1925 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1926 __mmplayer_video_param_set_display_rotation(player);
1927 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1928 __mmplayer_video_param_set_roi_area(player);
1929 if (update_all_param)
1930 __mmplayer_video_param_set_video_roi_area(player);
1932 return MM_ERROR_NONE;
1936 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1938 MMHandleType attrs = 0;
1939 int surface_type = 0;
1940 int ret = MM_ERROR_NONE;
1944 /* check video sinkbin is created */
1945 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1946 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1948 attrs = MMPLAYER_GET_ATTRS(player);
1950 LOGE("cannot get content attribute");
1951 return MM_ERROR_PLAYER_INTERNAL;
1953 LOGD("param_name : %s", param_name);
1955 /* update display surface */
1956 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1957 LOGD("check display surface type attribute: %d", surface_type);
1959 /* configuring display */
1960 switch (surface_type) {
1961 case MM_DISPLAY_SURFACE_OVERLAY:
1963 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1964 if (ret != MM_ERROR_NONE)
1972 return MM_ERROR_NONE;
1976 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1978 gboolean disable_overlay = FALSE;
1979 mm_player_t *player = (mm_player_t *)hplayer;
1980 int ret = MM_ERROR_NONE;
1983 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1984 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
1985 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1986 MM_ERROR_PLAYER_NO_OP); /* invalid op */
1988 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
1989 LOGW("Display control is not supported");
1990 return MM_ERROR_PLAYER_INTERNAL;
1993 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
1995 if (audio_only == (bool)disable_overlay) {
1996 LOGE("It's the same with current setting: (%d)", audio_only);
1997 return MM_ERROR_NONE;
2001 LOGE("disable overlay");
2002 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2004 /* release overlay resource */
2005 if (player->video_overlay_resource != NULL) {
2006 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2007 player->video_overlay_resource);
2008 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2009 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2012 player->video_overlay_resource = NULL;
2015 ret = mm_resource_manager_commit(player->resource_manager);
2016 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2017 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2021 /* mark video overlay for acquire */
2022 if (player->video_overlay_resource == NULL) {
2023 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2024 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2025 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2026 &player->video_overlay_resource);
2027 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2028 LOGE("could not prepare for video_overlay resource");
2033 player->interrupted_by_resource = FALSE;
2034 /* acquire resources for video overlay */
2035 ret = mm_resource_manager_commit(player->resource_manager);
2036 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2037 LOGE("could not acquire resources for video playing");
2041 LOGD("enable overlay");
2042 __mmplayer_video_param_set_display_overlay(player);
2043 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2048 return MM_ERROR_NONE;
2052 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2054 mm_player_t *player = (mm_player_t *)hplayer;
2055 gboolean disable_overlay = FALSE;
2059 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2060 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2061 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2062 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2063 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2065 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2066 LOGW("Display control is not supported");
2067 return MM_ERROR_PLAYER_INTERNAL;
2070 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2072 *paudio_only = (bool)disable_overlay;
2074 LOGD("audio_only : %d", *paudio_only);
2078 return MM_ERROR_NONE;
2082 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2084 GList *bucket = element_bucket;
2085 MMPlayerGstElement *element = NULL;
2086 MMPlayerGstElement *prv_element = NULL;
2087 gint successful_link_count = 0;
2091 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2093 prv_element = (MMPlayerGstElement *)bucket->data;
2094 bucket = bucket->next;
2096 for (; bucket; bucket = bucket->next) {
2097 element = (MMPlayerGstElement *)bucket->data;
2099 if (element && element->gst) {
2100 if (prv_element && prv_element->gst) {
2101 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2102 LOGD("linking [%s] to [%s] success",
2103 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2104 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2105 successful_link_count++;
2107 LOGD("linking [%s] to [%s] failed",
2108 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2109 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2115 prv_element = element;
2120 return successful_link_count;
2124 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2126 GList *bucket = element_bucket;
2127 MMPlayerGstElement *element = NULL;
2128 int successful_add_count = 0;
2132 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2133 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2135 for (; bucket; bucket = bucket->next) {
2136 element = (MMPlayerGstElement *)bucket->data;
2138 if (element && element->gst) {
2139 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2140 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2141 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2142 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2145 successful_add_count++;
2151 return successful_add_count;
2155 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2157 mm_player_t *player = (mm_player_t *)data;
2158 GstCaps *caps = NULL;
2159 GstStructure *str = NULL;
2161 gboolean caps_ret = TRUE;
2165 MMPLAYER_RETURN_IF_FAIL(pad);
2166 MMPLAYER_RETURN_IF_FAIL(unused);
2167 MMPLAYER_RETURN_IF_FAIL(data);
2169 caps = gst_pad_get_current_caps(pad);
2173 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2177 LOGD("name = %s", name);
2179 if (strstr(name, "audio")) {
2180 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2182 if (player->audio_stream_changed_cb) {
2183 LOGE("call the audio stream changed cb");
2184 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2186 } else if (strstr(name, "video")) {
2187 if ((name = gst_structure_get_string(str, "format")))
2188 player->set_mode.video_zc = name[0] == 'S';
2190 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2192 if (player->video_stream_changed_cb) {
2193 LOGE("call the video stream changed cb");
2194 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2197 LOGW("invalid caps info");
2202 gst_caps_unref(caps);
2210 * This function is to create audio pipeline for playing.
2212 * @param player [in] handle of player
2214 * @return This function returns zero on success.
2216 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2218 /* macro for code readability. just for sinkbin-creation functions */
2219 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2221 x_bin[x_id].id = x_id;\
2222 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2223 if (!x_bin[x_id].gst) {\
2224 LOGE("failed to create %s", x_factory);\
2227 if (x_player->ini.set_dump_element_flag)\
2228 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2231 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2235 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2240 MMPLAYER_RETURN_IF_FAIL(player);
2242 if (player->audio_stream_buff_list) {
2243 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2244 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2247 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2248 __mmplayer_audio_stream_send_data(player, tmp);
2250 MMPLAYER_FREEIF(tmp->pcm_data);
2251 MMPLAYER_FREEIF(tmp);
2254 g_list_free(player->audio_stream_buff_list);
2255 player->audio_stream_buff_list = NULL;
2262 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2264 MMPlayerAudioStreamDataType audio_stream = { 0, };
2267 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2269 audio_stream.bitrate = a_buffer->bitrate;
2270 audio_stream.channel = a_buffer->channel;
2271 audio_stream.depth = a_buffer->depth;
2272 audio_stream.is_little_endian = a_buffer->is_little_endian;
2273 audio_stream.channel_mask = a_buffer->channel_mask;
2274 audio_stream.data_size = a_buffer->data_size;
2275 audio_stream.data = a_buffer->pcm_data;
2277 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2278 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2284 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2286 mm_player_t *player = (mm_player_t *)data;
2290 gint endianness = 0;
2291 guint64 channel_mask = 0;
2292 void *a_data = NULL;
2294 mm_player_audio_stream_buff_t *a_buffer = NULL;
2295 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2299 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2301 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2302 a_data = mapinfo.data;
2303 a_size = mapinfo.size;
2305 GstCaps *caps = gst_pad_get_current_caps(pad);
2306 GstStructure *structure = gst_caps_get_structure(caps, 0);
2308 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2309 gst_structure_get_int(structure, "rate", &rate);
2310 gst_structure_get_int(structure, "channels", &channel);
2311 gst_structure_get_int(structure, "depth", &depth);
2312 gst_structure_get_int(structure, "endianness", &endianness);
2313 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2314 gst_caps_unref(GST_CAPS(caps));
2316 /* In case of the sync is false, use buffer list. *
2317 * The num of buffer list depends on the num of audio channels */
2318 if (player->audio_stream_buff_list) {
2319 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2320 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2322 if (channel_mask == tmp->channel_mask) {
2323 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2324 if (tmp->data_size + a_size < tmp->buff_size) {
2325 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2326 tmp->data_size += a_size;
2328 /* send data to client */
2329 __mmplayer_audio_stream_send_data(player, tmp);
2331 if (a_size > tmp->buff_size) {
2332 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2333 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2334 if (tmp->pcm_data == NULL) {
2335 LOGE("failed to realloc data.");
2338 tmp->buff_size = a_size;
2340 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2341 memcpy(tmp->pcm_data, a_data, a_size);
2342 tmp->data_size = a_size;
2347 LOGE("data is empty in list.");
2353 /* create new audio stream data */
2354 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2355 if (a_buffer == NULL) {
2356 LOGE("failed to alloc data.");
2359 a_buffer->bitrate = rate;
2360 a_buffer->channel = channel;
2361 a_buffer->depth = depth;
2362 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2363 a_buffer->channel_mask = channel_mask;
2364 a_buffer->data_size = a_size;
2366 if (!player->audio_stream_sink_sync) {
2367 /* If sync is FALSE, use buffer list to reduce the IPC. */
2368 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2369 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2370 if (a_buffer->pcm_data == NULL) {
2371 LOGE("failed to alloc data.");
2372 MMPLAYER_FREEIF(a_buffer);
2375 memcpy(a_buffer->pcm_data, a_data, a_size);
2376 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2377 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2379 /* If sync is TRUE, send data directly. */
2380 a_buffer->pcm_data = a_data;
2381 __mmplayer_audio_stream_send_data(player, a_buffer);
2382 MMPLAYER_FREEIF(a_buffer);
2386 gst_buffer_unmap(buffer, &mapinfo);
2391 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2393 mm_player_t *player = (mm_player_t *)data;
2394 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2395 GstPad *sinkpad = NULL;
2396 GstElement *queue = NULL, *sink = NULL;
2399 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2401 queue = gst_element_factory_make("queue", NULL);
2402 if (queue == NULL) {
2403 LOGD("fail make queue");
2407 sink = gst_element_factory_make("fakesink", NULL);
2409 LOGD("fail make fakesink");
2413 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2415 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2416 LOGW("failed to link queue & sink");
2420 sinkpad = gst_element_get_static_pad(queue, "sink");
2422 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2423 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2427 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2429 gst_object_unref(sinkpad);
2430 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2431 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2433 gst_element_set_state(sink, GST_STATE_PAUSED);
2434 gst_element_set_state(queue, GST_STATE_PAUSED);
2436 __mmplayer_add_signal_connection(player,
2438 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2440 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2447 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2449 gst_object_unref(GST_OBJECT(queue));
2453 gst_object_unref(GST_OBJECT(sink));
2457 gst_object_unref(GST_OBJECT(sinkpad));
2465 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2467 #define MAX_PROPS_LEN 128
2468 gint latency_mode = 0;
2469 gchar *stream_type = NULL;
2470 gchar *latency = NULL;
2472 gchar stream_props[MAX_PROPS_LEN] = {0,};
2473 GstStructure *props = NULL;
2476 * It should be set after player creation through attribute.
2477 * But, it can not be changed during playing.
2480 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2482 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2483 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2486 LOGE("stream_type is null.");
2488 if (player->sound.focus_id)
2489 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2490 stream_type, stream_id, player->sound.focus_id);
2492 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2493 stream_type, stream_id);
2494 props = gst_structure_from_string(stream_props, NULL);
2495 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2496 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2497 stream_type, stream_id, player->sound.focus_id, stream_props);
2498 gst_structure_free(props);
2501 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2503 switch (latency_mode) {
2504 case AUDIO_LATENCY_MODE_LOW:
2505 latency = g_strndup("low", 3);
2507 case AUDIO_LATENCY_MODE_MID:
2508 latency = g_strndup("mid", 3);
2510 case AUDIO_LATENCY_MODE_HIGH:
2511 latency = g_strndup("high", 4);
2515 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2519 LOGD("audiosink property - latency=%s", latency);
2521 MMPLAYER_FREEIF(latency);
2527 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2529 MMPlayerGstElement *audiobin = NULL;
2532 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2534 audiobin = player->pipeline->audiobin;
2536 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2537 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2538 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2540 if (player->video360_yaw_radians <= M_PI &&
2541 player->video360_yaw_radians >= -M_PI &&
2542 player->video360_pitch_radians <= M_PI_2 &&
2543 player->video360_pitch_radians >= -M_PI_2) {
2544 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2545 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2546 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2547 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2548 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2549 "source-orientation-y", player->video360_metadata.init_view_heading,
2550 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2557 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2559 MMPlayerGstElement *audiobin = NULL;
2560 MMHandleType attrs = 0;
2561 GList *element_bucket = NULL;
2562 GstCaps *acaps = NULL;
2563 GstPad *sink_pad = NULL;
2566 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2567 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2569 audiobin = player->pipeline->audiobin;
2570 attrs = MMPLAYER_GET_ATTRS(player);
2573 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2575 /* replaygain volume */
2576 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2577 if (player->sound.rg_enable)
2578 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2580 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2583 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2585 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2586 gchar *dst_format = NULL;
2588 int dst_samplerate = 0;
2589 int dst_channels = 0;
2590 GstCaps *caps = NULL;
2591 char *caps_str = NULL;
2593 /* get conf. values */
2594 mm_attrs_multiple_get(player->attrs, NULL,
2595 "pcm_audioformat", &dst_format, &dst_len,
2596 "pcm_extraction_samplerate", &dst_samplerate,
2597 "pcm_extraction_channels", &dst_channels,
2600 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2603 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2604 caps = gst_caps_new_simple("audio/x-raw",
2605 "format", G_TYPE_STRING, dst_format,
2606 "rate", G_TYPE_INT, dst_samplerate,
2607 "channels", G_TYPE_INT, dst_channels,
2610 caps_str = gst_caps_to_string(caps);
2611 LOGD("new caps : %s", caps_str);
2613 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2616 gst_caps_unref(caps);
2617 MMPLAYER_FREEIF(caps_str);
2619 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2621 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2623 /* raw pad handling signal, audiosink will be added after getting signal */
2624 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2625 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2629 /* normal playback */
2632 /* for logical volume control */
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2636 if (player->sound.mute) {
2637 LOGD("mute enabled");
2638 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2641 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2643 /* audio effect element. if audio effect is enabled */
2644 if ((strcmp(player->ini.audioeffect_element, ""))
2646 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2649 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2651 if ((!player->bypass_audio_effect)
2652 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2653 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2654 if (!_mmplayer_audio_effect_custom_apply(player))
2655 LOGI("apply audio effect(custom) setting success");
2659 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2660 && (player->set_mode.rich_audio))
2661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2664 /* create audio sink */
2665 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2666 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2667 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2669 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2670 if (player->is_360_feature_enabled &&
2671 player->is_content_spherical &&
2673 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2674 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2675 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2677 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2681 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2682 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2683 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2684 gst_caps_unref(acaps);
2686 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2688 player->is_openal_plugin_used = TRUE;
2690 if (player->is_360_feature_enabled && player->is_content_spherical)
2691 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2692 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2695 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2696 (player->videodec_linked && player->ini.use_system_clock)) {
2697 LOGD("system clock will be used.");
2698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2701 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2702 __mmplayer_gst_set_pulsesink_property(player, attrs);
2703 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2704 __mmplayer_gst_set_openalsink_property(player);
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2710 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2711 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2712 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2713 gst_object_unref(GST_OBJECT(sink_pad));
2715 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2718 *bucket = element_bucket;
2721 return MM_ERROR_NONE;
2724 g_list_free(element_bucket);
2728 return MM_ERROR_PLAYER_INTERNAL;
2732 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2734 MMPlayerGstElement *first_element = NULL;
2735 MMPlayerGstElement *audiobin = NULL;
2737 GstPad *ghostpad = NULL;
2738 GList *element_bucket = NULL;
2742 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2745 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2747 LOGE("failed to allocate memory for audiobin");
2748 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2752 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2753 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2754 if (!audiobin[MMPLAYER_A_BIN].gst) {
2755 LOGE("failed to create audiobin");
2760 player->pipeline->audiobin = audiobin;
2762 /* create audio filters and audiosink */
2763 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2766 /* adding created elements to bin */
2767 LOGD("adding created elements to bin");
2768 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2771 /* linking elements in the bucket by added order. */
2772 LOGD("Linking elements in the bucket by added order.");
2773 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2776 /* get first element's sinkpad for creating ghostpad */
2777 first_element = (MMPlayerGstElement *)element_bucket->data;
2778 if (!first_element) {
2779 LOGE("failed to get first elem");
2783 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2785 LOGE("failed to get pad from first element of audiobin");
2789 ghostpad = gst_ghost_pad_new("sink", pad);
2791 LOGE("failed to create ghostpad");
2795 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2796 LOGE("failed to add ghostpad to audiobin");
2800 gst_object_unref(pad);
2802 g_list_free(element_bucket);
2805 return MM_ERROR_NONE;
2808 LOGD("ERROR : releasing audiobin");
2811 gst_object_unref(GST_OBJECT(pad));
2814 gst_object_unref(GST_OBJECT(ghostpad));
2817 g_list_free(element_bucket);
2819 /* release element which are not added to bin */
2820 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2821 /* NOTE : skip bin */
2822 if (audiobin[i].gst) {
2823 GstObject *parent = NULL;
2824 parent = gst_element_get_parent(audiobin[i].gst);
2827 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2828 audiobin[i].gst = NULL;
2830 gst_object_unref(GST_OBJECT(parent));
2834 /* release audiobin with it's childs */
2835 if (audiobin[MMPLAYER_A_BIN].gst)
2836 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2838 MMPLAYER_FREEIF(audiobin);
2840 player->pipeline->audiobin = NULL;
2842 return MM_ERROR_PLAYER_INTERNAL;
2846 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2848 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2852 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2854 int ret = MM_ERROR_NONE;
2856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2857 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2859 MMPLAYER_VIDEO_BO_LOCK(player);
2861 if (player->video_bo_list) {
2862 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2863 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2864 if (tmp && tmp->bo == bo) {
2866 LOGD("release bo %p", bo);
2867 tbm_bo_unref(tmp->bo);
2868 MMPLAYER_VIDEO_BO_UNLOCK(player);
2869 MMPLAYER_VIDEO_BO_SIGNAL(player);
2874 /* hw codec is running or the list was reset for DRC. */
2875 LOGW("there is no bo list.");
2877 MMPLAYER_VIDEO_BO_UNLOCK(player);
2879 LOGW("failed to find bo %p", bo);
2884 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2889 MMPLAYER_RETURN_IF_FAIL(player);
2891 MMPLAYER_VIDEO_BO_LOCK(player);
2892 if (player->video_bo_list) {
2893 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2894 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2895 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2898 tbm_bo_unref(tmp->bo);
2902 g_list_free(player->video_bo_list);
2903 player->video_bo_list = NULL;
2905 player->video_bo_size = 0;
2906 MMPLAYER_VIDEO_BO_UNLOCK(player);
2913 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2916 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2917 gboolean ret = TRUE;
2919 /* check DRC, if it is, destroy the prev bo list to create again */
2920 if (player->video_bo_size != size) {
2921 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2922 __mmplayer_video_stream_destroy_bo_list(player);
2923 player->video_bo_size = size;
2926 MMPLAYER_VIDEO_BO_LOCK(player);
2928 if ((!player->video_bo_list) ||
2929 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2931 /* create bo list */
2933 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2935 if (player->video_bo_list) {
2936 /* if bo list did not created all, try it again. */
2937 idx = g_list_length(player->video_bo_list);
2938 LOGD("bo list exist(len: %d)", idx);
2941 for (; idx < player->ini.num_of_video_bo; idx++) {
2942 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2944 LOGE("Fail to alloc bo_info.");
2947 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2949 LOGE("Fail to tbm_bo_alloc.");
2950 MMPLAYER_FREEIF(bo_info);
2953 bo_info->used = FALSE;
2954 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2957 /* update video num buffers */
2958 player->video_num_buffers = idx;
2959 if (idx == player->ini.num_of_video_bo)
2960 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2963 MMPLAYER_VIDEO_BO_UNLOCK(player);
2967 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2971 /* get bo from list*/
2972 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2973 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2974 if (tmp && (tmp->used == FALSE)) {
2975 LOGD("found bo %p to use", tmp->bo);
2977 MMPLAYER_VIDEO_BO_UNLOCK(player);
2978 return tbm_bo_ref(tmp->bo);
2982 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
2983 MMPLAYER_VIDEO_BO_UNLOCK(player);
2987 if (player->ini.video_bo_timeout <= 0) {
2988 MMPLAYER_VIDEO_BO_WAIT(player);
2990 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
2991 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
2998 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3000 mm_player_t *player = (mm_player_t *)data;
3002 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3004 /* send prerolled pkt */
3005 player->video_stream_prerolled = false;
3007 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3009 /* not to send prerolled pkt again */
3010 player->video_stream_prerolled = true;
3014 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3016 mm_player_t *player = (mm_player_t *)data;
3017 MMPlayerVideoStreamDataType *stream = NULL;
3018 GstMemory *mem = NULL;
3021 MMPLAYER_RETURN_IF_FAIL(player);
3022 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3024 if (player->video_stream_prerolled) {
3025 player->video_stream_prerolled = false;
3026 LOGD("skip the prerolled pkt not to send it again");
3030 /* clear stream data structure */
3031 stream = __mmplayer_create_stream_from_pad(pad);
3033 LOGE("failed to alloc stream");
3037 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3039 /* set size and timestamp */
3040 mem = gst_buffer_peek_memory(buffer, 0);
3041 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3042 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3044 /* check zero-copy */
3045 if (player->set_mode.video_zc &&
3046 player->set_mode.media_packet_video_stream &&
3047 gst_is_tizen_memory(mem)) {
3048 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3049 stream->internal_buffer = gst_buffer_ref(buffer);
3050 } else { /* sw codec */
3051 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3054 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3058 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3059 LOGE("failed to send video stream data.");
3066 LOGE("release video stream resource.");
3067 if (gst_is_tizen_memory(mem)) {
3069 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3071 tbm_bo_unref(stream->bo[i]);
3074 /* unref gst buffer */
3075 if (stream->internal_buffer)
3076 gst_buffer_unref(stream->internal_buffer);
3079 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3081 MMPLAYER_FREEIF(stream);
3086 __mmplayer_gst_set_video360_property(mm_player_t *player)
3088 MMPlayerGstElement *videobin = NULL;
3091 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3093 videobin = player->pipeline->videobin;
3095 /* Set spatial media metadata and/or user settings to the element.
3097 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3098 "projection-type", player->video360_metadata.projection_type, NULL);
3100 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3101 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3103 if (player->video360_metadata.full_pano_width_pixels &&
3104 player->video360_metadata.full_pano_height_pixels &&
3105 player->video360_metadata.cropped_area_image_width &&
3106 player->video360_metadata.cropped_area_image_height) {
3107 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3108 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3109 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3110 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3111 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3112 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3113 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3117 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3118 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3119 "horizontal-fov", player->video360_horizontal_fov,
3120 "vertical-fov", player->video360_vertical_fov, NULL);
3123 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3124 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3125 "zoom", 1.0f / player->video360_zoom, NULL);
3128 if (player->video360_yaw_radians <= M_PI &&
3129 player->video360_yaw_radians >= -M_PI &&
3130 player->video360_pitch_radians <= M_PI_2 &&
3131 player->video360_pitch_radians >= -M_PI_2) {
3132 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3133 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3134 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3135 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3136 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3137 "pose-yaw", player->video360_metadata.init_view_heading,
3138 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3141 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3142 "passthrough", !player->is_video360_enabled, NULL);
3149 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3151 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3152 GList *element_bucket = NULL;
3155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3157 /* create video360 filter */
3158 if (player->is_360_feature_enabled && player->is_content_spherical) {
3159 LOGD("create video360 element");
3160 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3161 __mmplayer_gst_set_video360_property(player);
3165 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3166 LOGD("skip creating the videoconv and rotator");
3167 return MM_ERROR_NONE;
3170 /* in case of sw codec & overlay surface type, except 360 playback.
3171 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3172 LOGD("create video converter: %s", video_csc);
3173 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3175 /* set video rotator */
3176 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3179 *bucket = element_bucket;
3181 return MM_ERROR_NONE;
3183 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3184 g_list_free(element_bucket);
3188 return MM_ERROR_PLAYER_INTERNAL;
3192 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3194 gchar *factory_name = NULL;
3196 switch (surface_type) {
3197 case MM_DISPLAY_SURFACE_OVERLAY:
3198 if (strlen(player->ini.videosink_element_overlay) > 0)
3199 factory_name = player->ini.videosink_element_overlay;
3201 case MM_DISPLAY_SURFACE_REMOTE:
3202 case MM_DISPLAY_SURFACE_NULL:
3203 if (strlen(player->ini.videosink_element_fake) > 0)
3204 factory_name = player->ini.videosink_element_fake;
3207 LOGE("unidentified surface type");
3211 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3212 return factory_name;
3216 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3218 gchar *factory_name = NULL;
3219 MMPlayerGstElement *videobin = NULL;
3224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3226 videobin = player->pipeline->videobin;
3227 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3229 attrs = MMPLAYER_GET_ATTRS(player);
3231 LOGE("cannot get content attribute");
3232 return MM_ERROR_PLAYER_INTERNAL;
3235 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3236 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3237 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3239 /* support shard memory with S/W codec on HawkP */
3240 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3241 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3242 "use-tbm", use_tbm, NULL);
3246 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3247 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3250 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3252 LOGD("disable last-sample");
3253 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3256 if (player->set_mode.media_packet_video_stream) {
3258 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3259 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3260 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3262 __mmplayer_add_signal_connection(player,
3263 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3264 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3266 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3269 __mmplayer_add_signal_connection(player,
3270 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3271 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3273 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3277 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3278 return MM_ERROR_PLAYER_INTERNAL;
3280 if (videobin[MMPLAYER_V_SINK].gst) {
3281 GstPad *sink_pad = NULL;
3282 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3284 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3285 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3286 gst_object_unref(GST_OBJECT(sink_pad));
3288 LOGE("failed to get sink pad from videosink");
3292 return MM_ERROR_NONE;
3297 * - video overlay surface(arm/x86) : tizenwlsink
3300 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3303 GList *element_bucket = NULL;
3304 MMPlayerGstElement *first_element = NULL;
3305 MMPlayerGstElement *videobin = NULL;
3306 gchar *videosink_factory_name = NULL;
3309 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3312 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3314 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3316 player->pipeline->videobin = videobin;
3319 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3320 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3321 if (!videobin[MMPLAYER_V_BIN].gst) {
3322 LOGE("failed to create videobin");
3326 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3329 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3330 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3332 /* additional setting for sink plug-in */
3333 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3334 LOGE("failed to set video property");
3338 /* store it as it's sink element */
3339 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3341 /* adding created elements to bin */
3342 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3343 LOGE("failed to add elements");
3347 /* Linking elements in the bucket by added order */
3348 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3349 LOGE("failed to link elements");
3353 /* get first element's sinkpad for creating ghostpad */
3354 first_element = (MMPlayerGstElement *)element_bucket->data;
3355 if (!first_element) {
3356 LOGE("failed to get first element from bucket");
3360 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3362 LOGE("failed to get pad from first element");
3366 /* create ghostpad */
3367 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3368 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3369 LOGE("failed to add ghostpad to videobin");
3372 gst_object_unref(pad);
3374 /* done. free allocated variables */
3375 g_list_free(element_bucket);
3379 return MM_ERROR_NONE;
3382 LOGE("ERROR : releasing videobin");
3383 g_list_free(element_bucket);
3386 gst_object_unref(GST_OBJECT(pad));
3388 /* release videobin with it's childs */
3389 if (videobin[MMPLAYER_V_BIN].gst)
3390 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3392 MMPLAYER_FREEIF(videobin);
3393 player->pipeline->videobin = NULL;
3395 return MM_ERROR_PLAYER_INTERNAL;
3399 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3401 GList *element_bucket = NULL;
3402 MMPlayerGstElement *textbin = player->pipeline->textbin;
3404 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3405 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3406 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3407 "signal-handoffs", FALSE,
3410 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3411 __mmplayer_add_signal_connection(player,
3412 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3413 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3415 G_CALLBACK(__mmplayer_update_subtitle),
3418 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3419 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3421 if (!player->play_subtitle) {
3422 LOGD("add textbin sink as sink element of whole pipeline.");
3423 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3426 /* adding created elements to bin */
3427 LOGD("adding created elements to bin");
3428 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3429 LOGE("failed to add elements");
3433 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3434 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3435 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3437 /* linking elements in the bucket by added order. */
3438 LOGD("Linking elements in the bucket by added order.");
3439 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3440 LOGE("failed to link elements");
3444 /* done. free allocated variables */
3445 g_list_free(element_bucket);
3447 if (textbin[MMPLAYER_T_QUEUE].gst) {
3449 GstPad *ghostpad = NULL;
3451 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3453 LOGE("failed to get sink pad of text queue");
3457 ghostpad = gst_ghost_pad_new("text_sink", pad);
3458 gst_object_unref(pad);
3461 LOGE("failed to create ghostpad of textbin");
3465 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3466 LOGE("failed to add ghostpad to textbin");
3467 gst_object_unref(ghostpad);
3472 return MM_ERROR_NONE;
3475 g_list_free(element_bucket);
3477 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3478 LOGE("remove textbin sink from sink list");
3479 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3482 /* release element at __mmplayer_gst_create_text_sink_bin */
3483 return MM_ERROR_PLAYER_INTERNAL;
3487 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3489 MMPlayerGstElement *textbin = NULL;
3490 GList *element_bucket = NULL;
3491 int surface_type = 0;
3496 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3499 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3501 LOGE("failed to allocate memory for textbin");
3502 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3506 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3507 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3508 if (!textbin[MMPLAYER_T_BIN].gst) {
3509 LOGE("failed to create textbin");
3514 player->pipeline->textbin = textbin;
3517 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3518 LOGD("surface type for subtitle : %d", surface_type);
3519 switch (surface_type) {
3520 case MM_DISPLAY_SURFACE_OVERLAY:
3521 case MM_DISPLAY_SURFACE_NULL:
3522 case MM_DISPLAY_SURFACE_REMOTE:
3523 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3524 LOGE("failed to make plain text elements");
3535 return MM_ERROR_NONE;
3539 LOGD("ERROR : releasing textbin");
3541 g_list_free(element_bucket);
3543 /* release signal */
3544 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3546 /* release element which are not added to bin */
3547 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3548 /* NOTE : skip bin */
3549 if (textbin[i].gst) {
3550 GstObject *parent = NULL;
3551 parent = gst_element_get_parent(textbin[i].gst);
3554 gst_object_unref(GST_OBJECT(textbin[i].gst));
3555 textbin[i].gst = NULL;
3557 gst_object_unref(GST_OBJECT(parent));
3562 /* release textbin with it's childs */
3563 if (textbin[MMPLAYER_T_BIN].gst)
3564 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3566 MMPLAYER_FREEIF(player->pipeline->textbin);
3567 player->pipeline->textbin = NULL;
3570 return MM_ERROR_PLAYER_INTERNAL;
3574 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3576 MMPlayerGstElement *mainbin = NULL;
3577 MMPlayerGstElement *textbin = NULL;
3578 MMHandleType attrs = 0;
3579 GstElement *subsrc = NULL;
3580 GstElement *subparse = NULL;
3581 gchar *subtitle_uri = NULL;
3582 const gchar *charset = NULL;
3588 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3590 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3592 mainbin = player->pipeline->mainbin;
3594 attrs = MMPLAYER_GET_ATTRS(player);
3596 LOGE("cannot get content attribute");
3597 return MM_ERROR_PLAYER_INTERNAL;
3600 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3601 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3602 LOGE("subtitle uri is not proper filepath.");
3603 return MM_ERROR_PLAYER_INVALID_URI;
3606 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3607 LOGE("failed to get storage info of subtitle path");
3608 return MM_ERROR_PLAYER_INVALID_URI;
3611 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3613 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3614 player->subtitle_language_list = NULL;
3615 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3617 /* create the subtitle source */
3618 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3620 LOGE("failed to create filesrc element");
3623 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3625 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3626 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3628 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3629 LOGW("failed to add queue");
3630 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3631 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3632 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3637 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3639 LOGE("failed to create subparse element");
3643 charset = util_get_charset(subtitle_uri);
3645 LOGD("detected charset is %s", charset);
3646 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3649 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3650 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3652 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3653 LOGW("failed to add subparse");
3654 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3655 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3656 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3660 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3661 LOGW("failed to link subsrc and subparse");
3665 player->play_subtitle = TRUE;
3666 player->adjust_subtitle_pos = 0;
3668 LOGD("play subtitle using subtitle file");
3670 if (player->pipeline->textbin == NULL) {
3671 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3672 LOGE("failed to create text sink bin. continuing without text");
3676 textbin = player->pipeline->textbin;
3678 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3679 LOGW("failed to add textbin");
3681 /* release signal */
3682 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3684 /* release textbin with it's childs */
3685 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3686 MMPLAYER_FREEIF(player->pipeline->textbin);
3687 player->pipeline->textbin = textbin = NULL;
3691 LOGD("link text input selector and textbin ghost pad");
3693 player->textsink_linked = 1;
3694 player->external_text_idx = 0;
3695 LOGI("textsink is linked");
3697 textbin = player->pipeline->textbin;
3698 LOGD("text bin has been created. reuse it.");
3699 player->external_text_idx = 1;
3702 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3703 LOGW("failed to link subparse and textbin");
3707 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3709 LOGE("failed to get sink pad from textsink to probe data");
3713 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3714 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3716 gst_object_unref(pad);
3719 /* create dot. for debugging */
3720 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3723 return MM_ERROR_NONE;
3726 /* release text pipeline resource */
3727 player->textsink_linked = 0;
3729 /* release signal */
3730 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3732 if (player->pipeline->textbin) {
3733 LOGE("remove textbin");
3735 /* release textbin with it's childs */
3736 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3737 MMPLAYER_FREEIF(player->pipeline->textbin);
3738 player->pipeline->textbin = NULL;
3742 /* release subtitle elem */
3743 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3744 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3746 return MM_ERROR_PLAYER_INTERNAL;
3750 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3752 mm_player_t *player = (mm_player_t *)data;
3753 MMMessageParamType msg = {0, };
3754 GstClockTime duration = 0;
3755 gpointer text = NULL;
3756 guint text_size = 0;
3757 gboolean ret = TRUE;
3758 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3762 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3763 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3765 if (player->is_subtitle_force_drop) {
3766 LOGW("subtitle is dropped forcedly.");
3770 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3771 text = mapinfo.data;
3772 text_size = mapinfo.size;
3773 duration = GST_BUFFER_DURATION(buffer);
3775 if (player->set_mode.subtitle_off) {
3776 LOGD("subtitle is OFF.");
3780 if (!text || (text_size == 0)) {
3781 LOGD("There is no subtitle to be displayed.");
3785 msg.data = (void *)text;
3786 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3788 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3790 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3791 gst_buffer_unmap(buffer, &mapinfo);
3798 static GstPadProbeReturn
3799 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3801 mm_player_t *player = (mm_player_t *)u_data;
3802 GstClockTime cur_timestamp = 0;
3803 gint64 adjusted_timestamp = 0;
3804 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3806 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3808 if (player->set_mode.subtitle_off) {
3809 LOGD("subtitle is OFF.");
3813 if (player->adjust_subtitle_pos == 0) {
3814 LOGD("nothing to do");
3818 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3819 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3821 if (adjusted_timestamp < 0) {
3822 LOGD("adjusted_timestamp under zero");
3827 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3828 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3829 GST_TIME_ARGS(cur_timestamp),
3830 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3832 return GST_PAD_PROBE_OK;
3836 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3840 /* check player and subtitlebin are created */
3841 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3842 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3844 if (position == 0) {
3845 LOGD("nothing to do");
3847 return MM_ERROR_NONE;
3851 case MM_PLAYER_POS_FORMAT_TIME:
3853 /* check current postion */
3854 player->adjust_subtitle_pos = position;
3856 LOGD("save adjust_subtitle_pos in player") ;
3862 LOGW("invalid format.");
3864 return MM_ERROR_INVALID_ARGUMENT;
3870 return MM_ERROR_NONE;
3874 * This function is to create audio or video pipeline for playing.
3876 * @param player [in] handle of player
3878 * @return This function returns zero on success.
3883 __mmplayer_gst_create_pipeline(mm_player_t *player)
3885 int ret = MM_ERROR_NONE;
3886 MMPlayerGstElement *mainbin = NULL;
3887 MMHandleType attrs = 0;
3890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3892 /* get profile attribute */
3893 attrs = MMPLAYER_GET_ATTRS(player);
3895 LOGE("failed to get content attribute");
3899 /* create pipeline handles */
3900 if (player->pipeline) {
3901 LOGE("pipeline should be released before create new one");
3905 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3906 if (player->pipeline == NULL)
3909 /* create mainbin */
3910 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3911 if (mainbin == NULL)
3914 /* create pipeline */
3915 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3916 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3917 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3918 LOGE("failed to create pipeline");
3923 player->pipeline->mainbin = mainbin;
3925 /* create the source and decoder elements */
3926 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3927 ret = __mmplayer_gst_build_es_pipeline(player);
3929 ret = __mmplayer_gst_build_pipeline(player);
3931 if (ret != MM_ERROR_NONE) {
3932 LOGE("failed to create some elements");
3936 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3937 if (__mmplayer_check_subtitle(player)
3938 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3939 LOGE("failed to create text pipeline");
3942 ret = __mmplayer_gst_add_bus_watch(player);
3943 if (ret != MM_ERROR_NONE) {
3944 LOGE("failed to add bus watch");
3949 return MM_ERROR_NONE;
3952 __mmplayer_gst_destroy_pipeline(player);
3953 return MM_ERROR_PLAYER_INTERNAL;
3957 __mmplayer_reset_gapless_state(mm_player_t *player)
3960 MMPLAYER_RETURN_IF_FAIL(player
3962 && player->pipeline->audiobin
3963 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3965 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3972 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
3975 int ret = MM_ERROR_NONE;
3979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
3981 /* cleanup stuffs */
3982 MMPLAYER_FREEIF(player->type);
3983 player->no_more_pad = FALSE;
3984 player->num_dynamic_pad = 0;
3985 player->demux_pad_index = 0;
3987 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3988 player->subtitle_language_list = NULL;
3989 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3991 __mmplayer_reset_gapless_state(player);
3993 if (player->streamer) {
3994 __mm_player_streaming_initialize(player->streamer, FALSE);
3995 __mm_player_streaming_destroy(player->streamer);
3996 player->streamer = NULL;
3999 /* cleanup unlinked mime type */
4000 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4001 MMPLAYER_FREEIF(player->unlinked_video_mime);
4002 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4004 /* cleanup running stuffs */
4005 __mmplayer_cancel_eos_timer(player);
4007 /* cleanup gst stuffs */
4008 if (player->pipeline) {
4009 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4010 GstTagList *tag_list = player->pipeline->tag_list;
4012 /* first we need to disconnect all signal hander */
4013 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4016 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4017 MMPlayerGstElement *videobin = player->pipeline->videobin;
4018 MMPlayerGstElement *textbin = player->pipeline->textbin;
4019 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4020 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4021 gst_object_unref(bus);
4023 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4024 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4025 if (ret != MM_ERROR_NONE) {
4026 LOGE("fail to change state to NULL");
4027 return MM_ERROR_PLAYER_INTERNAL;
4030 LOGW("succeeded in changing state to NULL");
4032 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4035 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4036 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4038 /* free avsysaudiosink
4039 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4040 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4042 MMPLAYER_FREEIF(audiobin);
4043 MMPLAYER_FREEIF(videobin);
4044 MMPLAYER_FREEIF(textbin);
4045 MMPLAYER_FREEIF(mainbin);
4049 gst_tag_list_unref(tag_list);
4051 MMPLAYER_FREEIF(player->pipeline);
4053 MMPLAYER_FREEIF(player->album_art);
4055 if (player->v_stream_caps) {
4056 gst_caps_unref(player->v_stream_caps);
4057 player->v_stream_caps = NULL;
4060 if (player->a_stream_caps) {
4061 gst_caps_unref(player->a_stream_caps);
4062 player->a_stream_caps = NULL;
4065 if (player->s_stream_caps) {
4066 gst_caps_unref(player->s_stream_caps);
4067 player->s_stream_caps = NULL;
4069 __mmplayer_track_destroy(player);
4071 if (player->sink_elements)
4072 g_list_free(player->sink_elements);
4073 player->sink_elements = NULL;
4075 if (player->bufmgr) {
4076 tbm_bufmgr_deinit(player->bufmgr);
4077 player->bufmgr = NULL;
4080 LOGW("finished destroy pipeline");
4088 __mmplayer_gst_realize(mm_player_t *player)
4091 int ret = MM_ERROR_NONE;
4095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4097 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4099 ret = __mmplayer_gst_create_pipeline(player);
4101 LOGE("failed to create pipeline");
4105 /* set pipeline state to READY */
4106 /* NOTE : state change to READY must be performed sync. */
4107 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4108 ret = __mmplayer_gst_set_state(player,
4109 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4111 if (ret != MM_ERROR_NONE) {
4112 /* return error if failed to set state */
4113 LOGE("failed to set READY state");
4117 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4119 /* create dot before error-return. for debugging */
4120 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4128 __mmplayer_gst_unrealize(mm_player_t *player)
4130 int ret = MM_ERROR_NONE;
4134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4136 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4137 MMPLAYER_PRINT_STATE(player);
4139 /* release miscellaneous information */
4140 __mmplayer_release_misc(player);
4142 /* destroy pipeline */
4143 ret = __mmplayer_gst_destroy_pipeline(player);
4144 if (ret != MM_ERROR_NONE) {
4145 LOGE("failed to destory pipeline");
4149 /* release miscellaneous information.
4150 these info needs to be released after pipeline is destroyed. */
4151 __mmplayer_release_misc_post(player);
4153 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4161 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4166 LOGW("set_message_callback is called with invalid player handle");
4167 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4170 player->msg_cb = callback;
4171 player->msg_cb_param = user_param;
4173 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4177 return MM_ERROR_NONE;
4181 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4183 int ret = MM_ERROR_NONE;
4188 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4189 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4190 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4192 memset(data, 0, sizeof(MMPlayerParseProfile));
4194 if (strstr(uri, "es_buff://")) {
4195 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4196 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4197 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4198 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4200 tmp = g_ascii_strdown(uri, strlen(uri));
4201 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4202 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4204 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4206 } else if (strstr(uri, "mms://")) {
4207 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4208 } else if ((path = strstr(uri, "mem://"))) {
4209 ret = __mmplayer_set_mem_uri(data, path, param);
4211 ret = __mmplayer_set_file_uri(data, uri);
4214 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4215 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4216 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4217 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4219 /* dump parse result */
4220 SECURE_LOGW("incoming uri : %s", uri);
4221 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4222 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4230 __mmplayer_can_do_interrupt(mm_player_t *player)
4232 if (!player || !player->pipeline || !player->attrs) {
4233 LOGW("not initialized");
4237 if (player->audio_stream_render_cb) {
4238 LOGW("not support in pcm extraction mode");
4242 /* check if seeking */
4243 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4244 MMMessageParamType msg_param;
4245 memset(&msg_param, 0, sizeof(MMMessageParamType));
4246 msg_param.code = MM_ERROR_PLAYER_SEEK;
4247 player->seek_state = MMPLAYER_SEEK_NONE;
4248 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4252 /* check other thread */
4253 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4254 LOGW("locked already, cmd state : %d", player->cmd);
4256 /* check application command */
4257 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4258 LOGW("playing.. should wait cmd lock then, will be interrupted");
4260 /* lock will be released at mrp_resource_release_cb() */
4261 MMPLAYER_CMD_LOCK(player);
4264 LOGW("nothing to do");
4267 LOGW("can interrupt immediately");
4271 FAILED: /* with CMD UNLOCKED */
4274 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4279 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4282 mm_player_t *player = NULL;
4286 if (user_data == NULL) {
4287 LOGE("- user_data is null");
4290 player = (mm_player_t *)user_data;
4292 /* do something to release resource here.
4293 * player stop and interrupt forwarding */
4294 if (!__mmplayer_can_do_interrupt(player)) {
4295 LOGW("no need to interrupt, so leave");
4297 MMMessageParamType msg = {0, };
4300 player->interrupted_by_resource = TRUE;
4302 /* get last play position */
4303 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4304 LOGW("failed to get play position.");
4306 msg.union_type = MM_MSG_UNION_TIME;
4307 msg.time.elapsed = pos;
4308 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4310 LOGD("video resource conflict so, resource will be freed by unrealizing");
4311 if (_mmplayer_unrealize((MMHandleType)player))
4312 LOGW("failed to unrealize");
4314 /* lock is called in __mmplayer_can_do_interrupt() */
4315 MMPLAYER_CMD_UNLOCK(player);
4318 if (res == player->video_overlay_resource)
4319 player->video_overlay_resource = FALSE;
4321 player->video_decoder_resource = FALSE;
4329 __mmplayer_initialize_video_roi(mm_player_t *player)
4331 player->video_roi.scale_x = 0.0;
4332 player->video_roi.scale_y = 0.0;
4333 player->video_roi.scale_width = 1.0;
4334 player->video_roi.scale_height = 1.0;
4338 _mmplayer_create_player(MMHandleType handle)
4340 int ret = MM_ERROR_PLAYER_INTERNAL;
4341 bool enabled = false;
4343 mm_player_t *player = MM_PLAYER_CAST(handle);
4347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4349 /* initialize player state */
4350 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4351 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4352 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4353 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4355 /* check current state */
4356 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4358 /* construct attributes */
4359 player->attrs = _mmplayer_construct_attribute(handle);
4361 if (!player->attrs) {
4362 LOGE("Failed to construct attributes");
4366 /* initialize gstreamer with configured parameter */
4367 if (!__mmplayer_init_gstreamer(player)) {
4368 LOGE("Initializing gstreamer failed");
4369 _mmplayer_deconstruct_attribute(handle);
4373 /* create lock. note that g_tread_init() has already called in gst_init() */
4374 g_mutex_init(&player->fsink_lock);
4376 /* create update tag lock */
4377 g_mutex_init(&player->update_tag_lock);
4379 /* create gapless play mutex */
4380 g_mutex_init(&player->gapless_play_thread_mutex);
4382 /* create gapless play cond */
4383 g_cond_init(&player->gapless_play_thread_cond);
4385 /* create gapless play thread */
4386 player->gapless_play_thread =
4387 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4388 if (!player->gapless_play_thread) {
4389 LOGE("failed to create gapless play thread");
4390 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4391 g_mutex_clear(&player->gapless_play_thread_mutex);
4392 g_cond_clear(&player->gapless_play_thread_cond);
4396 player->bus_msg_q = g_queue_new();
4397 if (!player->bus_msg_q) {
4398 LOGE("failed to create queue for bus_msg");
4399 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4403 ret = _mmplayer_initialize_video_capture(player);
4404 if (ret != MM_ERROR_NONE) {
4405 LOGE("failed to initialize video capture");
4409 /* initialize resource manager */
4410 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4411 __resource_release_cb, player, &player->resource_manager)
4412 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4413 LOGE("failed to initialize resource manager");
4414 ret = MM_ERROR_PLAYER_INTERNAL;
4418 /* create video bo lock and cond */
4419 g_mutex_init(&player->video_bo_mutex);
4420 g_cond_init(&player->video_bo_cond);
4422 /* create media stream callback mutex */
4423 g_mutex_init(&player->media_stream_cb_lock);
4425 /* create subtitle info lock and cond */
4426 g_mutex_init(&player->subtitle_info_mutex);
4427 g_cond_init(&player->subtitle_info_cond);
4429 player->streaming_type = STREAMING_SERVICE_NONE;
4431 /* give default value of audio effect setting */
4432 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4433 player->sound.rg_enable = false;
4434 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4436 player->play_subtitle = FALSE;
4437 player->has_closed_caption = FALSE;
4438 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4439 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4440 player->pending_resume = FALSE;
4441 if (player->ini.dump_element_keyword[0][0] == '\0')
4442 player->ini.set_dump_element_flag = FALSE;
4444 player->ini.set_dump_element_flag = TRUE;
4446 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4447 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4448 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4450 /* Set video360 settings to their defaults for just-created player.
4453 player->is_360_feature_enabled = FALSE;
4454 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4455 LOGI("spherical feature info: %d", enabled);
4457 player->is_360_feature_enabled = TRUE;
4459 LOGE("failed to get spherical feature info");
4462 player->is_content_spherical = FALSE;
4463 player->is_video360_enabled = TRUE;
4464 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4465 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4466 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4467 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4468 player->video360_zoom = 1.0f;
4469 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4470 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4472 __mmplayer_initialize_video_roi(player);
4474 /* set player state to null */
4475 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4476 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4480 return MM_ERROR_NONE;
4484 g_mutex_clear(&player->fsink_lock);
4485 /* free update tag lock */
4486 g_mutex_clear(&player->update_tag_lock);
4487 g_queue_free(player->bus_msg_q);
4488 /* free gapless play thread */
4489 if (player->gapless_play_thread) {
4490 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4491 player->gapless_play_thread_exit = TRUE;
4492 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4493 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4495 g_thread_join(player->gapless_play_thread);
4496 player->gapless_play_thread = NULL;
4498 g_mutex_clear(&player->gapless_play_thread_mutex);
4499 g_cond_clear(&player->gapless_play_thread_cond);
4502 /* release attributes */
4503 _mmplayer_deconstruct_attribute(handle);
4511 __mmplayer_init_gstreamer(mm_player_t *player)
4513 static gboolean initialized = FALSE;
4514 static const int max_argc = 50;
4516 gchar **argv = NULL;
4517 gchar **argv2 = NULL;
4523 LOGD("gstreamer already initialized.");
4528 argc = malloc(sizeof(int));
4529 argv = malloc(sizeof(gchar *) * max_argc);
4530 argv2 = malloc(sizeof(gchar *) * max_argc);
4532 if (!argc || !argv || !argv2)
4535 memset(argv, 0, sizeof(gchar *) * max_argc);
4536 memset(argv2, 0, sizeof(gchar *) * max_argc);
4540 argv[0] = g_strdup("mmplayer");
4543 for (i = 0; i < 5; i++) {
4544 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4545 if (strlen(player->ini.gst_param[i]) > 0) {
4546 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4551 /* we would not do fork for scanning plugins */
4552 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4555 /* check disable registry scan */
4556 if (player->ini.skip_rescan) {
4557 argv[*argc] = g_strdup("--gst-disable-registry-update");
4561 /* check disable segtrap */
4562 if (player->ini.disable_segtrap) {
4563 argv[*argc] = g_strdup("--gst-disable-segtrap");
4567 LOGD("initializing gstreamer with following parameter");
4568 LOGD("argc : %d", *argc);
4571 for (i = 0; i < arg_count; i++) {
4573 LOGD("argv[%d] : %s", i, argv2[i]);
4576 /* initializing gstreamer */
4577 if (!gst_init_check(argc, &argv, &err)) {
4578 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4585 for (i = 0; i < arg_count; i++) {
4586 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4587 MMPLAYER_FREEIF(argv2[i]);
4590 MMPLAYER_FREEIF(argv);
4591 MMPLAYER_FREEIF(argv2);
4592 MMPLAYER_FREEIF(argc);
4602 for (i = 0; i < arg_count; i++) {
4603 LOGD("free[%d] : %s", i, argv2[i]);
4604 MMPLAYER_FREEIF(argv2[i]);
4607 MMPLAYER_FREEIF(argv);
4608 MMPLAYER_FREEIF(argv2);
4609 MMPLAYER_FREEIF(argc);
4615 __mmplayer_check_async_state_transition(mm_player_t *player)
4617 GstState element_state = GST_STATE_VOID_PENDING;
4618 GstState element_pending_state = GST_STATE_VOID_PENDING;
4619 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4620 GstElement *element = NULL;
4621 gboolean async = FALSE;
4623 /* check player handle */
4624 MMPLAYER_RETURN_IF_FAIL(player &&
4626 player->pipeline->mainbin &&
4627 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4630 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4632 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4633 LOGD("don't need to check the pipeline state");
4637 MMPLAYER_PRINT_STATE(player);
4639 /* wait for state transition */
4640 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4641 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4643 if (ret == GST_STATE_CHANGE_FAILURE) {
4644 LOGE(" [%s] state : %s pending : %s",
4645 GST_ELEMENT_NAME(element),
4646 gst_element_state_get_name(element_state),
4647 gst_element_state_get_name(element_pending_state));
4649 /* dump state of all element */
4650 __mmplayer_dump_pipeline_state(player);
4655 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4660 _mmplayer_destroy(MMHandleType handle)
4662 mm_player_t *player = MM_PLAYER_CAST(handle);
4666 /* check player handle */
4667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4669 /* destroy can called at anytime */
4670 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4672 /* check async state transition */
4673 __mmplayer_check_async_state_transition(player);
4675 /* release gapless play thread */
4676 if (player->gapless_play_thread) {
4677 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4678 player->gapless_play_thread_exit = TRUE;
4679 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4680 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4682 LOGD("waitting for gapless play thread exit");
4683 g_thread_join(player->gapless_play_thread);
4684 g_mutex_clear(&player->gapless_play_thread_mutex);
4685 g_cond_clear(&player->gapless_play_thread_cond);
4686 LOGD("gapless play thread released");
4689 _mmplayer_release_video_capture(player);
4691 /* de-initialize resource manager */
4692 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4693 player->resource_manager))
4694 LOGE("failed to deinitialize resource manager");
4696 /* release pipeline */
4697 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4698 LOGE("failed to destory pipeline");
4699 return MM_ERROR_PLAYER_INTERNAL;
4702 g_queue_free(player->bus_msg_q);
4704 /* release subtitle info lock and cond */
4705 g_mutex_clear(&player->subtitle_info_mutex);
4706 g_cond_clear(&player->subtitle_info_cond);
4708 __mmplayer_release_dump_list(player->dump_list);
4710 /* release miscellaneous information */
4711 __mmplayer_release_misc(player);
4713 /* release miscellaneous information.
4714 these info needs to be released after pipeline is destroyed. */
4715 __mmplayer_release_misc_post(player);
4717 /* release attributes */
4718 _mmplayer_deconstruct_attribute(handle);
4721 g_mutex_clear(&player->fsink_lock);
4724 g_mutex_clear(&player->update_tag_lock);
4726 /* release video bo lock and cond */
4727 g_mutex_clear(&player->video_bo_mutex);
4728 g_cond_clear(&player->video_bo_cond);
4730 /* release media stream callback lock */
4731 g_mutex_clear(&player->media_stream_cb_lock);
4735 return MM_ERROR_NONE;
4739 _mmplayer_realize(MMHandleType hplayer)
4741 mm_player_t *player = (mm_player_t *)hplayer;
4744 MMHandleType attrs = 0;
4745 int ret = MM_ERROR_NONE;
4749 /* check player handle */
4750 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4752 /* check current state */
4753 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4755 attrs = MMPLAYER_GET_ATTRS(player);
4757 LOGE("fail to get attributes.");
4758 return MM_ERROR_PLAYER_INTERNAL;
4760 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4761 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4763 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4764 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4766 if (ret != MM_ERROR_NONE) {
4767 LOGE("failed to parse profile");
4772 if (uri && (strstr(uri, "es_buff://"))) {
4773 if (strstr(uri, "es_buff://push_mode"))
4774 player->es_player_push_mode = TRUE;
4776 player->es_player_push_mode = FALSE;
4779 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4780 LOGW("mms protocol is not supported format.");
4781 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4784 if (MMPLAYER_IS_STREAMING(player))
4785 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4787 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4789 player->smooth_streaming = FALSE;
4790 player->videodec_linked = 0;
4791 player->audiodec_linked = 0;
4792 player->textsink_linked = 0;
4793 player->is_external_subtitle_present = FALSE;
4794 player->is_external_subtitle_added_now = FALSE;
4795 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4796 player->video360_metadata.is_spherical = -1;
4797 player->is_openal_plugin_used = FALSE;
4798 player->demux_pad_index = 0;
4799 player->subtitle_language_list = NULL;
4800 player->is_subtitle_force_drop = FALSE;
4801 player->last_multiwin_status = FALSE;
4803 __mmplayer_track_initialize(player);
4804 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4806 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4807 player->streamer = __mm_player_streaming_create();
4808 __mm_player_streaming_initialize(player->streamer, TRUE);
4811 /* realize pipeline */
4812 ret = __mmplayer_gst_realize(player);
4813 if (ret != MM_ERROR_NONE)
4814 LOGE("fail to realize the player.");
4816 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4824 _mmplayer_unrealize(MMHandleType hplayer)
4826 mm_player_t *player = (mm_player_t *)hplayer;
4827 int ret = MM_ERROR_NONE;
4831 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4833 MMPLAYER_CMD_UNLOCK(player);
4834 /* destroy the gst bus msg thread which is created during realize.
4835 this funct have to be called before getting cmd lock. */
4836 __mmplayer_bus_msg_thread_destroy(player);
4837 MMPLAYER_CMD_LOCK(player);
4839 /* check current state */
4840 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4842 /* check async state transition */
4843 __mmplayer_check_async_state_transition(player);
4845 /* unrealize pipeline */
4846 ret = __mmplayer_gst_unrealize(player);
4848 /* set asm stop if success */
4849 if (MM_ERROR_NONE == ret) {
4850 if (!player->interrupted_by_resource) {
4851 if (player->video_decoder_resource != NULL) {
4852 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4853 player->video_decoder_resource);
4854 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4855 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4857 player->video_decoder_resource = NULL;
4860 if (player->video_overlay_resource != NULL) {
4861 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4862 player->video_overlay_resource);
4863 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4864 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4866 player->video_overlay_resource = NULL;
4869 ret = mm_resource_manager_commit(player->resource_manager);
4870 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4871 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4874 LOGE("failed and don't change asm state to stop");
4882 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4884 mm_player_t *player = (mm_player_t *)hplayer;
4886 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4888 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4892 _mmplayer_get_state(MMHandleType hplayer, int *state)
4894 mm_player_t *player = (mm_player_t *)hplayer;
4896 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4898 *state = MMPLAYER_CURRENT_STATE(player);
4900 return MM_ERROR_NONE;
4905 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4907 mm_player_t *player = (mm_player_t *)hplayer;
4908 GstElement *vol_element = NULL;
4913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4915 LOGD("volume [L]=%f:[R]=%f",
4916 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4918 /* invalid factor range or not */
4919 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4920 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4921 LOGE("Invalid factor!(valid factor:0~1.0)");
4922 return MM_ERROR_INVALID_ARGUMENT;
4926 /* not support to set other value into each channel */
4927 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4928 return MM_ERROR_INVALID_ARGUMENT;
4930 /* Save volume to handle. Currently the first array element will be saved. */
4931 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4933 /* check pipeline handle */
4934 if (!player->pipeline || !player->pipeline->audiobin) {
4935 LOGD("audiobin is not created yet");
4936 LOGD("but, current stored volume will be set when it's created.");
4938 /* NOTE : stored volume will be used in create_audiobin
4939 * returning MM_ERROR_NONE here makes application to able to
4940 * set volume at anytime.
4942 return MM_ERROR_NONE;
4945 /* setting volume to volume element */
4946 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4949 LOGD("volume is set [%f]", player->sound.volume);
4950 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4955 return MM_ERROR_NONE;
4959 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
4961 mm_player_t *player = (mm_player_t *)hplayer;
4966 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4967 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4969 /* returning stored volume */
4970 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4971 volume->level[i] = player->sound.volume;
4975 return MM_ERROR_NONE;
4979 _mmplayer_set_mute(MMHandleType hplayer, int mute)
4981 mm_player_t *player = (mm_player_t *)hplayer;
4982 GstElement *vol_element = NULL;
4986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4988 /* mute value shoud 0 or 1 */
4989 if (mute != 0 && mute != 1) {
4990 LOGE("bad mute value");
4992 /* FIXIT : definitly, we need _BAD_PARAM error code */
4993 return MM_ERROR_INVALID_ARGUMENT;
4996 player->sound.mute = mute;
4998 /* just hold mute value if pipeline is not ready */
4999 if (!player->pipeline || !player->pipeline->audiobin) {
5000 LOGD("pipeline is not ready. holding mute value");
5001 return MM_ERROR_NONE;
5004 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5006 /* NOTE : volume will only created when the bt is enabled */
5008 LOGD("mute : %d", mute);
5009 g_object_set(vol_element, "mute", mute, NULL);
5011 LOGD("volume elemnet is not created. using volume in audiosink");
5015 return MM_ERROR_NONE;
5019 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5021 mm_player_t *player = (mm_player_t *)hplayer;
5025 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5026 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5028 /* just hold mute value if pipeline is not ready */
5029 if (!player->pipeline || !player->pipeline->audiobin) {
5030 LOGD("pipeline is not ready. returning stored value");
5031 *pmute = player->sound.mute;
5032 return MM_ERROR_NONE;
5035 *pmute = player->sound.mute;
5039 return MM_ERROR_NONE;
5043 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5045 mm_player_t *player = (mm_player_t *)hplayer;
5049 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5051 player->video_stream_changed_cb = callback;
5052 player->video_stream_changed_cb_user_param = user_param;
5053 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5057 return MM_ERROR_NONE;
5061 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5063 mm_player_t *player = (mm_player_t *)hplayer;
5067 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5069 player->audio_stream_changed_cb = callback;
5070 player->audio_stream_changed_cb_user_param = user_param;
5071 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5075 return MM_ERROR_NONE;
5079 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5081 mm_player_t *player = (mm_player_t *)hplayer;
5085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5087 player->audio_stream_render_cb = callback;
5088 player->audio_stream_cb_user_param = user_param;
5089 player->audio_stream_sink_sync = sync;
5090 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5094 return MM_ERROR_NONE;
5098 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5100 mm_player_t *player = (mm_player_t *)hplayer;
5104 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106 if (callback && !player->bufmgr)
5107 player->bufmgr = tbm_bufmgr_init(-1);
5109 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5110 player->video_stream_cb = callback;
5111 player->video_stream_cb_user_param = user_param;
5113 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5117 return MM_ERROR_NONE;
5121 _mmplayer_start(MMHandleType hplayer)
5123 mm_player_t *player = (mm_player_t *)hplayer;
5124 gint ret = MM_ERROR_NONE;
5128 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5130 /* check current state */
5131 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5133 /* start pipeline */
5134 ret = __mmplayer_gst_start(player);
5135 if (ret != MM_ERROR_NONE)
5136 LOGE("failed to start player.");
5138 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5139 LOGD("force playing start even during buffering");
5140 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5148 /* NOTE: post "not supported codec message" to application
5149 * when one codec is not found during AUTOPLUGGING in MSL.
5150 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5151 * And, if any codec is not found, don't send message here.
5152 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5155 __mmplayer_handle_missed_plugin(mm_player_t *player)
5157 MMMessageParamType msg_param;
5158 memset(&msg_param, 0, sizeof(MMMessageParamType));
5159 gboolean post_msg_direct = FALSE;
5163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5165 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5166 player->not_supported_codec, player->can_support_codec);
5168 if (player->not_found_demuxer) {
5169 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5170 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5172 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5173 MMPLAYER_FREEIF(msg_param.data);
5175 return MM_ERROR_NONE;
5178 if (player->not_supported_codec) {
5179 if (player->can_support_codec) {
5180 // There is one codec to play
5181 post_msg_direct = TRUE;
5183 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5184 post_msg_direct = TRUE;
5187 if (post_msg_direct) {
5188 MMMessageParamType msg_param;
5189 memset(&msg_param, 0, sizeof(MMMessageParamType));
5191 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5192 LOGW("not found AUDIO codec, posting error code to application.");
5194 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5195 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5196 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5197 LOGW("not found VIDEO codec, posting error code to application.");
5199 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5200 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5203 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5205 MMPLAYER_FREEIF(msg_param.data);
5207 return MM_ERROR_NONE;
5209 // no any supported codec case
5210 LOGW("not found any codec, posting error code to application.");
5212 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5213 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5214 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5216 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5217 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5220 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5222 MMPLAYER_FREEIF(msg_param.data);
5228 return MM_ERROR_NONE;
5232 __mmplayer_check_pipeline(mm_player_t *player)
5234 GstState element_state = GST_STATE_VOID_PENDING;
5235 GstState element_pending_state = GST_STATE_VOID_PENDING;
5237 int ret = MM_ERROR_NONE;
5239 if (!player->gapless.reconfigure)
5242 LOGW("pipeline is under construction.");
5244 MMPLAYER_PLAYBACK_LOCK(player);
5245 MMPLAYER_PLAYBACK_UNLOCK(player);
5247 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5249 /* wait for state transition */
5250 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5251 if (ret == GST_STATE_CHANGE_FAILURE)
5252 LOGE("failed to change pipeline state within %d sec", timeout);
5255 /* NOTE : it should be able to call 'stop' anytime*/
5257 _mmplayer_stop(MMHandleType hplayer)
5259 mm_player_t *player = (mm_player_t *)hplayer;
5260 int ret = MM_ERROR_NONE;
5264 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5266 /* check current state */
5267 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5269 /* check pipline building state */
5270 __mmplayer_check_pipeline(player);
5271 __mmplayer_reset_gapless_state(player);
5273 /* NOTE : application should not wait for EOS after calling STOP */
5274 __mmplayer_cancel_eos_timer(player);
5277 player->seek_state = MMPLAYER_SEEK_NONE;
5280 ret = __mmplayer_gst_stop(player);
5282 if (ret != MM_ERROR_NONE)
5283 LOGE("failed to stop player.");
5291 _mmplayer_pause(MMHandleType hplayer)
5293 mm_player_t *player = (mm_player_t *)hplayer;
5294 gint64 pos_nsec = 0;
5295 gboolean async = FALSE;
5296 gint ret = MM_ERROR_NONE;
5300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5302 /* check current state */
5303 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5305 /* check pipline building state */
5306 __mmplayer_check_pipeline(player);
5308 switch (MMPLAYER_CURRENT_STATE(player)) {
5309 case MM_PLAYER_STATE_READY:
5311 /* check prepare async or not.
5312 * In the case of streaming playback, it's recommned to avoid blocking wait.
5314 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5315 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5317 /* Changing back sync of rtspsrc to async */
5318 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5319 LOGD("async prepare working mode for rtsp");
5325 case MM_PLAYER_STATE_PLAYING:
5327 /* NOTE : store current point to overcome some bad operation
5328 *(returning zero when getting current position in paused state) of some
5331 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5332 LOGW("getting current position failed in paused");
5334 player->last_position = pos_nsec;
5336 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5337 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5338 This causes problem is position calculation during normal pause resume scenarios also.
5339 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5340 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5341 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5342 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5348 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5349 LOGD("doing async pause in case of ms buff src");
5353 /* pause pipeline */
5354 ret = __mmplayer_gst_pause(player, async);
5356 if (ret != MM_ERROR_NONE)
5357 LOGE("failed to pause player. ret : 0x%x", ret);
5359 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5360 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5361 LOGE("failed to update display_rotation");
5369 /* in case of streaming, pause could take long time.*/
5371 _mmplayer_abort_pause(MMHandleType hplayer)
5373 mm_player_t *player = (mm_player_t *)hplayer;
5374 int ret = MM_ERROR_NONE;
5378 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5380 player->pipeline->mainbin,
5381 MM_ERROR_PLAYER_NOT_INITIALIZED);
5383 LOGD("set the pipeline state to READY");
5385 /* set state to READY */
5386 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5387 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5388 if (ret != MM_ERROR_NONE) {
5389 LOGE("fail to change state to READY");
5390 return MM_ERROR_PLAYER_INTERNAL;
5393 LOGD("succeeded in changing state to READY");
5398 _mmplayer_resume(MMHandleType hplayer)
5400 mm_player_t *player = (mm_player_t *)hplayer;
5401 int ret = MM_ERROR_NONE;
5402 gboolean async = FALSE;
5406 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5408 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5409 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5410 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5414 /* Changing back sync mode rtspsrc to async */
5415 LOGD("async resume for rtsp case");
5419 /* check current state */
5420 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5422 ret = __mmplayer_gst_resume(player, async);
5423 if (ret != MM_ERROR_NONE)
5424 LOGE("failed to resume player.");
5426 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5427 LOGD("force resume even during buffering");
5428 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5437 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5439 mm_player_t *player = (mm_player_t *)hplayer;
5440 gint64 pos_nsec = 0;
5441 int ret = MM_ERROR_NONE;
5443 signed long long start = 0, stop = 0;
5444 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5447 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5448 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5450 /* The sound of video is not supported under 0.0 and over 2.0. */
5451 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5452 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5455 _mmplayer_set_mute(hplayer, mute);
5457 if (player->playback_rate == rate)
5458 return MM_ERROR_NONE;
5460 /* If the position is reached at start potion during fast backward, EOS is posted.
5461 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5463 player->playback_rate = rate;
5465 current_state = MMPLAYER_CURRENT_STATE(player);
5467 if (current_state != MM_PLAYER_STATE_PAUSED)
5468 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5470 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5472 if ((current_state == MM_PLAYER_STATE_PAUSED)
5473 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5474 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5475 pos_nsec = player->last_position;
5480 stop = GST_CLOCK_TIME_NONE;
5482 start = GST_CLOCK_TIME_NONE;
5486 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5487 player->playback_rate,
5489 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5490 GST_SEEK_TYPE_SET, start,
5491 GST_SEEK_TYPE_SET, stop)) {
5492 LOGE("failed to set speed playback");
5493 return MM_ERROR_PLAYER_SEEK;
5496 LOGD("succeeded to set speed playback as %0.1f", rate);
5500 return MM_ERROR_NONE;;
5504 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5506 mm_player_t *player = (mm_player_t *)hplayer;
5507 int ret = MM_ERROR_NONE;
5511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5513 /* check pipline building state */
5514 __mmplayer_check_pipeline(player);
5516 ret = __mmplayer_gst_set_position(player, position, FALSE);
5524 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5526 mm_player_t *player = (mm_player_t *)hplayer;
5527 int ret = MM_ERROR_NONE;
5529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5531 ret = __mmplayer_gst_get_position(player, position);
5537 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5539 mm_player_t *player = (mm_player_t *)hplayer;
5540 int ret = MM_ERROR_NONE;
5542 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5543 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5545 *duration = player->duration;
5550 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5552 mm_player_t *player = (mm_player_t *)hplayer;
5553 int ret = MM_ERROR_NONE;
5555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5557 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5563 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5565 mm_player_t *player = (mm_player_t *)hplayer;
5566 int ret = MM_ERROR_NONE;
5570 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5572 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5580 __mmplayer_is_midi_type(gchar *str_caps)
5582 if ((g_strrstr(str_caps, "audio/midi")) ||
5583 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5584 (g_strrstr(str_caps, "application/x-smaf")) ||
5585 (g_strrstr(str_caps, "audio/x-imelody")) ||
5586 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5587 (g_strrstr(str_caps, "audio/xmf")) ||
5588 (g_strrstr(str_caps, "audio/mxmf"))) {
5597 __mmplayer_is_only_mp3_type(gchar *str_caps)
5599 if (g_strrstr(str_caps, "application/x-id3") ||
5600 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5606 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5608 GstStructure *caps_structure = NULL;
5609 gint samplerate = 0;
5613 MMPLAYER_RETURN_IF_FAIL(player && caps);
5615 caps_structure = gst_caps_get_structure(caps, 0);
5617 /* set stream information */
5618 gst_structure_get_int(caps_structure, "rate", &samplerate);
5619 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5621 gst_structure_get_int(caps_structure, "channels", &channels);
5622 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5624 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5628 __mmplayer_update_content_type_info(mm_player_t *player)
5631 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5633 if (__mmplayer_is_midi_type(player->type)) {
5634 player->bypass_audio_effect = TRUE;
5638 if (!player->streamer) {
5639 LOGD("no need to check streaming type");
5643 if (g_strrstr(player->type, "application/x-hls")) {
5644 /* If it can't know exact type when it parses uri because of redirection case,
5645 * it will be fixed by typefinder or when doing autoplugging.
5647 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5648 player->streamer->is_adaptive_streaming = TRUE;
5649 } else if (g_strrstr(player->type, "application/dash+xml")) {
5650 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5651 player->streamer->is_adaptive_streaming = TRUE;
5654 if (player->streamer->is_adaptive_streaming) {
5655 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5657 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) /* if user did not set the rebuffer value */
5658 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5661 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5666 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5667 GstCaps *caps, gpointer data)
5669 mm_player_t *player = (mm_player_t *)data;
5674 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5676 /* store type string */
5677 MMPLAYER_FREEIF(player->type);
5678 player->type = gst_caps_to_string(caps);
5680 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5681 player, player->type, probability, gst_caps_get_size(caps));
5683 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5684 (g_strrstr(player->type, "audio/x-raw-int"))) {
5685 LOGE("not support media format");
5687 if (player->msg_posted == FALSE) {
5688 MMMessageParamType msg_param;
5689 memset(&msg_param, 0, sizeof(MMMessageParamType));
5691 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5692 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5694 /* don't post more if one was sent already */
5695 player->msg_posted = TRUE;
5700 __mmplayer_update_content_type_info(player);
5702 pad = gst_element_get_static_pad(tf, "src");
5704 LOGE("fail to get typefind src pad.");
5708 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5709 gboolean async = FALSE;
5710 LOGE("failed to autoplug %s", player->type);
5712 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5714 if (async && player->msg_posted == FALSE)
5715 __mmplayer_handle_missed_plugin(player);
5721 gst_object_unref(GST_OBJECT(pad));
5729 __mmplayer_gst_make_decodebin(mm_player_t *player)
5731 GstElement *decodebin = NULL;
5735 /* create decodebin */
5736 decodebin = gst_element_factory_make("decodebin", NULL);
5739 LOGE("fail to create decodebin");
5743 /* raw pad handling signal */
5744 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5745 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5747 /* no-more-pad pad handling signal */
5748 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5749 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5751 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5752 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5754 /* This signal is emitted when a pad for which there is no further possible
5755 decoding is added to the decodebin.*/
5756 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5757 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5759 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5760 before looking for any elements that can handle that stream.*/
5761 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5762 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5764 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5765 before looking for any elements that can handle that stream.*/
5766 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5767 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5769 /* This signal is emitted once decodebin has finished decoding all the data.*/
5770 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5771 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5773 /* This signal is emitted when a element is added to the bin.*/
5774 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5775 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5782 __mmplayer_gst_make_queue2(mm_player_t *player)
5784 GstElement *queue2 = NULL;
5785 gint64 dur_bytes = 0L;
5786 MMPlayerGstElement *mainbin = NULL;
5787 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5790 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5792 mainbin = player->pipeline->mainbin;
5794 queue2 = gst_element_factory_make("queue2", "queue2");
5796 LOGE("failed to create buffering queue element");
5800 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5801 * skip the pull mode(file or ring buffering) setting. */
5802 if (g_strrstr(player->type, "video/mpegts"))
5805 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5806 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5808 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5810 if (dur_bytes > 0) {
5811 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5812 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5817 __mm_player_streaming_set_queue2(player->streamer,
5821 (guint64)dur_bytes);
5827 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5829 MMPlayerGstElement *mainbin = NULL;
5830 GstElement *decodebin = NULL;
5831 GstElement *queue2 = NULL;
5832 GstPad *sinkpad = NULL;
5833 GstPad *qsrcpad = NULL;
5836 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5838 mainbin = player->pipeline->mainbin;
5840 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5842 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5843 LOGW("need to check: muxed buffer is not null");
5846 queue2 = __mmplayer_gst_make_queue2(player);
5848 LOGE("failed to make queue2");
5852 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5853 LOGE("failed to add buffering queue");
5857 sinkpad = gst_element_get_static_pad(queue2, "sink");
5858 qsrcpad = gst_element_get_static_pad(queue2, "src");
5860 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5861 LOGE("failed to link [%s:%s]-[%s:%s]",
5862 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5866 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5867 LOGE("failed to sync queue2 state with parent");
5871 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5872 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5876 gst_object_unref(GST_OBJECT(sinkpad));
5880 /* create decodebin */
5881 decodebin = __mmplayer_gst_make_decodebin(player);
5883 LOGE("failed to make decodebin");
5887 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5888 LOGE("failed to add decodebin");
5892 /* to force caps on the decodebin element and avoid reparsing stuff by
5893 * typefind. It also avoids a deadlock in the way typefind activates pads in
5894 * the state change */
5895 g_object_set(decodebin, "sink-caps", caps, NULL);
5897 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5899 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5900 LOGE("failed to link [%s:%s]-[%s:%s]",
5901 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5905 gst_object_unref(GST_OBJECT(sinkpad));
5908 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5909 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5911 /* set decodebin property about buffer in streaming playback. *
5912 * in case of HLS/DASH, it does not need to have big buffer *
5913 * because it is kind of adaptive streaming. */
5914 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5915 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5916 gint high_percent = 0;
5918 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5919 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5921 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5923 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5925 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5926 "high-percent", high_percent,
5927 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
5928 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
5929 "max-size-buffers", 0, NULL); // disable or automatic
5932 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
5933 LOGE("failed to sync decodebin state with parent");
5944 gst_object_unref(GST_OBJECT(sinkpad));
5947 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5948 * You need to explicitly set elements to the NULL state before
5949 * dropping the final reference, to allow them to clean up.
5951 gst_element_set_state(queue2, GST_STATE_NULL);
5953 /* And, it still has a parent "player".
5954 * You need to let the parent manage the object instead of unreffing the object directly.
5956 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5957 gst_object_unref(queue2);
5962 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5963 * You need to explicitly set elements to the NULL state before
5964 * dropping the final reference, to allow them to clean up.
5966 gst_element_set_state(decodebin, GST_STATE_NULL);
5968 /* And, it still has a parent "player".
5969 * You need to let the parent manage the object instead of unreffing the object directly.
5972 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5973 gst_object_unref(decodebin);
5981 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
5985 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5986 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
5988 LOGD("class : %s, mime : %s", factory_class, mime);
5990 /* add missing plugin */
5991 /* NOTE : msl should check missing plugin for image mime type.
5992 * Some motion jpeg clips can have playable audio track.
5993 * So, msl have to play audio after displaying popup written video format not supported.
5995 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
5996 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
5997 LOGD("not found demuxer");
5998 player->not_found_demuxer = TRUE;
5999 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6005 if (!g_strrstr(factory_class, "Demuxer")) {
6006 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6007 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6008 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6010 /* check that clip have multi tracks or not */
6011 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6012 LOGD("video plugin is already linked");
6014 LOGW("add VIDEO to missing plugin");
6015 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6016 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6018 } else if (g_str_has_prefix(mime, "audio")) {
6019 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6020 LOGD("audio plugin is already linked");
6022 LOGW("add AUDIO to missing plugin");
6023 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6024 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6032 return MM_ERROR_NONE;
6036 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6038 mm_player_t *player = (mm_player_t *)data;
6042 MMPLAYER_RETURN_IF_FAIL(player);
6044 /* remove fakesink. */
6045 if (!__mmplayer_gst_remove_fakesink(player,
6046 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6047 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6048 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6049 * source element are not same. To overcome this situation, this function will called
6050 * several places and several times. Therefore, this is not an error case.
6055 LOGD("[handle: %p] pipeline has completely constructed", player);
6057 if ((player->ini.async_start) &&
6058 (player->msg_posted == FALSE) &&
6059 (player->cmd >= MMPLAYER_COMMAND_START))
6060 __mmplayer_handle_missed_plugin(player);
6062 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6066 __mmplayer_check_profile(void)
6069 static int profile_tv = -1;
6071 if (__builtin_expect(profile_tv != -1, 1))
6074 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6075 switch (*profileName) {
6090 __mmplayer_get_next_uri(mm_player_t *player)
6092 MMPlayerParseProfile profile;
6094 guint num_of_list = 0;
6097 num_of_list = g_list_length(player->uri_info.uri_list);
6098 uri_idx = player->uri_info.uri_idx;
6100 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6101 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6102 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6104 LOGW("next uri does not exist");
6108 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6109 LOGE("failed to parse profile");
6113 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6114 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6115 LOGW("uri type is not supported(%d)", profile.uri_type);
6119 LOGD("success to find next uri %d", uri_idx);
6123 if (uri_idx == num_of_list) {
6124 LOGE("failed to find next uri");
6128 player->uri_info.uri_idx = uri_idx;
6129 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6131 if (mm_attrs_commit_all(player->attrs)) {
6132 LOGE("failed to commit");
6136 SECURE_LOGD("next playback uri: %s", uri);
6141 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6143 #define REPEAT_COUNT_INFINITELY -1
6144 #define REPEAT_COUNT_MIN 2
6146 MMHandleType attrs = 0;
6150 guint num_of_list = 0;
6151 int profile_tv = -1;
6155 LOGD("checking for gapless play option");
6157 if (player->pipeline->textbin) {
6158 LOGE("subtitle path is enabled. gapless play is not supported.");
6162 attrs = MMPLAYER_GET_ATTRS(player);
6164 LOGE("fail to get attributes.");
6168 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6170 /* gapless playback is not supported in case of video at TV profile. */
6171 profile_tv = __mmplayer_check_profile();
6172 if (profile_tv && video) {
6173 LOGW("not support video gapless playback");
6177 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6178 LOGE("failed to get play count");
6180 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6181 LOGE("failed to get gapless mode");
6183 /* check repeat count in case of audio */
6185 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6186 LOGW("gapless is disabled");
6190 num_of_list = g_list_length(player->uri_info.uri_list);
6192 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6194 if (num_of_list == 0) {
6195 /* audio looping path */
6196 if (count >= REPEAT_COUNT_MIN) {
6197 /* decrease play count */
6198 /* we succeeded to rewind. update play count and then wait for next EOS */
6200 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6201 /* commit attribute */
6202 if (mm_attrs_commit_all(attrs))
6203 LOGE("failed to commit attribute");
6205 } else if (count != REPEAT_COUNT_INFINITELY) {
6206 LOGD("there is no next uri and no repeat");
6209 LOGD("looping cnt %d", count);
6211 /* gapless playback path */
6212 if (!__mmplayer_get_next_uri(player)) {
6213 LOGE("failed to get next uri");
6220 LOGE("unable to play gapless path. EOS will be posted soon");
6225 __mmplayer_initialize_gapless_play(mm_player_t *player)
6231 player->smooth_streaming = FALSE;
6232 player->videodec_linked = 0;
6233 player->audiodec_linked = 0;
6234 player->textsink_linked = 0;
6235 player->is_external_subtitle_present = FALSE;
6236 player->is_external_subtitle_added_now = FALSE;
6237 player->not_supported_codec = MISSING_PLUGIN_NONE;
6238 player->can_support_codec = FOUND_PLUGIN_NONE;
6239 player->pending_seek.is_pending = false;
6240 player->pending_seek.pos = 0;
6241 player->msg_posted = FALSE;
6242 player->has_many_types = FALSE;
6243 player->no_more_pad = FALSE;
6244 player->not_found_demuxer = 0;
6245 player->seek_state = MMPLAYER_SEEK_NONE;
6246 player->is_subtitle_force_drop = FALSE;
6247 player->play_subtitle = FALSE;
6248 player->adjust_subtitle_pos = 0;
6250 player->total_bitrate = 0;
6251 player->total_maximum_bitrate = 0;
6253 __mmplayer_track_initialize(player);
6254 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6256 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6257 player->bitrate[i] = 0;
6258 player->maximum_bitrate[i] = 0;
6261 if (player->v_stream_caps) {
6262 gst_caps_unref(player->v_stream_caps);
6263 player->v_stream_caps = NULL;
6266 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6268 /* clean found parsers */
6269 if (player->parsers) {
6270 GList *parsers = player->parsers;
6271 for (; parsers; parsers = g_list_next(parsers)) {
6272 gchar *name = parsers->data;
6273 MMPLAYER_FREEIF(name);
6275 g_list_free(player->parsers);
6276 player->parsers = NULL;
6279 /* clean found audio decoders */
6280 if (player->audio_decoders) {
6281 GList *a_dec = player->audio_decoders;
6282 for (; a_dec; a_dec = g_list_next(a_dec)) {
6283 gchar *name = a_dec->data;
6284 MMPLAYER_FREEIF(name);
6286 g_list_free(player->audio_decoders);
6287 player->audio_decoders = NULL;
6294 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6296 MMPlayerGstElement *mainbin = NULL;
6297 MMMessageParamType msg_param = {0,};
6298 GstElement *element = NULL;
6299 MMHandleType attrs = 0;
6301 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6305 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6306 LOGE("player is not initialized");
6310 mainbin = player->pipeline->mainbin;
6311 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6313 attrs = MMPLAYER_GET_ATTRS(player);
6315 LOGE("fail to get attributes");
6319 /* Initialize Player values */
6320 __mmplayer_initialize_gapless_play(player);
6322 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6324 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6325 LOGE("failed to parse profile");
6326 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6330 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6331 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6332 LOGE("dash or hls is not supportable");
6333 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6337 element = __mmplayer_gst_create_source(player);
6339 LOGE("no source element was created");
6343 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6344 LOGE("failed to add source element to pipeline");
6345 gst_object_unref(GST_OBJECT(element));
6350 /* take source element */
6351 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6352 mainbin[MMPLAYER_M_SRC].gst = element;
6356 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6357 if (player->streamer == NULL) {
6358 player->streamer = __mm_player_streaming_create();
6359 __mm_player_streaming_initialize(player->streamer, TRUE);
6362 elem_idx = MMPLAYER_M_TYPEFIND;
6363 element = gst_element_factory_make("typefind", "typefinder");
6364 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6365 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6367 elem_idx = MMPLAYER_M_AUTOPLUG;
6368 element = __mmplayer_gst_make_decodebin(player);
6371 /* check autoplug element is OK */
6373 LOGE("can not create element(%d)", elem_idx);
6377 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6378 LOGE("failed to add sinkbin to pipeline");
6379 gst_object_unref(GST_OBJECT(element));
6384 mainbin[elem_idx].id = elem_idx;
6385 mainbin[elem_idx].gst = element;
6387 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6388 LOGE("Failed to link src - autoplug(or typefind)");
6392 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6393 LOGE("Failed to change state of src element");
6397 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6398 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6399 LOGE("Failed to change state of decodebin");
6403 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6404 LOGE("Failed to change state of src element");
6409 player->gapless.stream_changed = TRUE;
6410 player->gapless.running = TRUE;
6416 MMPLAYER_PLAYBACK_UNLOCK(player);
6418 if (!player->msg_posted) {
6419 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6420 player->msg_posted = TRUE;
6427 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6429 mm_player_selector_t *selector = &player->selector[type];
6430 MMPlayerGstElement *sinkbin = NULL;
6431 enum MainElementID selectorId = MMPLAYER_M_NUM;
6432 enum MainElementID sinkId = MMPLAYER_M_NUM;
6433 GstPad *srcpad = NULL;
6434 GstPad *sinkpad = NULL;
6435 gboolean send_notice = FALSE;
6438 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6440 LOGD("type %d", type);
6443 case MM_PLAYER_TRACK_TYPE_AUDIO:
6444 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6445 sinkId = MMPLAYER_A_BIN;
6446 sinkbin = player->pipeline->audiobin;
6448 case MM_PLAYER_TRACK_TYPE_VIDEO:
6449 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6450 sinkId = MMPLAYER_V_BIN;
6451 sinkbin = player->pipeline->videobin;
6454 case MM_PLAYER_TRACK_TYPE_TEXT:
6455 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6456 sinkId = MMPLAYER_T_BIN;
6457 sinkbin = player->pipeline->textbin;
6460 LOGE("requested type is not supportable");
6465 if (player->pipeline->mainbin[selectorId].gst) {
6468 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6470 if (selector->event_probe_id != 0)
6471 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6472 selector->event_probe_id = 0;
6474 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6475 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6477 if (srcpad && sinkpad) {
6478 /* after getting drained signal there is no data flows, so no need to do pad_block */
6479 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6480 gst_pad_unlink(srcpad, sinkpad);
6482 /* send custom event to sink pad to handle it at video sink */
6484 LOGD("send custom event to sinkpad");
6485 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6486 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6487 gst_pad_send_event(sinkpad, event);
6491 gst_object_unref(sinkpad);
6494 gst_object_unref(srcpad);
6497 LOGD("selector release");
6499 /* release and unref requests pad from the selector */
6500 for (n = 0; n < selector->channels->len; n++) {
6501 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6502 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6504 g_ptr_array_set_size(selector->channels, 0);
6506 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6507 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6509 player->pipeline->mainbin[selectorId].gst = NULL;
6517 __mmplayer_deactivate_old_path(mm_player_t *player)
6520 MMPLAYER_RETURN_IF_FAIL(player);
6522 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6523 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6524 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6525 LOGE("deactivate selector error");
6529 __mmplayer_track_destroy(player);
6530 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6532 if (player->streamer) {
6533 __mm_player_streaming_initialize(player->streamer, FALSE);
6534 __mm_player_streaming_destroy(player->streamer);
6535 player->streamer = NULL;
6538 MMPLAYER_PLAYBACK_LOCK(player);
6539 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6546 if (!player->msg_posted) {
6547 MMMessageParamType msg = {0,};
6550 msg.code = MM_ERROR_PLAYER_INTERNAL;
6551 LOGE("gapless_uri_play> deactivate error");
6553 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6554 player->msg_posted = TRUE;
6560 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6562 int result = MM_ERROR_NONE;
6563 mm_player_t *player = (mm_player_t *)hplayer;
6566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6568 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6569 if (mm_attrs_commit_all(player->attrs)) {
6570 LOGE("failed to commit the original uri.");
6571 result = MM_ERROR_PLAYER_INTERNAL;
6573 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6574 LOGE("failed to add the original uri in the uri list.");
6582 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6584 mm_player_t *player = (mm_player_t *)hplayer;
6585 guint num_of_list = 0;
6589 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6590 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6592 if (player->pipeline && player->pipeline->textbin) {
6593 LOGE("subtitle path is enabled.");
6594 return MM_ERROR_PLAYER_INVALID_STATE;
6597 num_of_list = g_list_length(player->uri_info.uri_list);
6599 if (is_first_path) {
6600 if (num_of_list == 0) {
6601 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6602 LOGD("add original path : %s", uri);
6604 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6605 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6607 LOGD("change original path : %s", uri);
6610 MMHandleType attrs = 0;
6611 attrs = MMPLAYER_GET_ATTRS(player);
6613 if (num_of_list == 0) {
6614 char *original_uri = NULL;
6617 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6619 if (!original_uri) {
6620 LOGE("there is no original uri.");
6621 return MM_ERROR_PLAYER_INVALID_STATE;
6624 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6625 player->uri_info.uri_idx = 0;
6627 LOGD("add original path at first : %s", original_uri);
6631 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6632 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6636 return MM_ERROR_NONE;
6640 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6642 mm_player_t *player = (mm_player_t *)hplayer;
6643 char *next_uri = NULL;
6644 guint num_of_list = 0;
6647 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6649 num_of_list = g_list_length(player->uri_info.uri_list);
6651 if (num_of_list > 0) {
6652 gint uri_idx = player->uri_info.uri_idx;
6654 if (uri_idx < num_of_list-1)
6659 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6660 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6662 *uri = g_strdup(next_uri);
6666 return MM_ERROR_NONE;
6670 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6671 GstCaps *caps, gpointer data)
6673 mm_player_t *player = (mm_player_t *)data;
6674 const gchar *klass = NULL;
6675 const gchar *mime = NULL;
6676 gchar *caps_str = NULL;
6678 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6679 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6680 caps_str = gst_caps_to_string(caps);
6682 LOGW("unknown type of caps : %s from %s",
6683 caps_str, GST_ELEMENT_NAME(elem));
6685 MMPLAYER_FREEIF(caps_str);
6687 /* There is no available codec. */
6688 __mmplayer_check_not_supported_codec(player, klass, mime);
6692 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6693 GstCaps *caps, gpointer data)
6695 mm_player_t *player = (mm_player_t *)data;
6696 const char *mime = NULL;
6697 gboolean ret = TRUE;
6699 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6700 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6702 if (g_str_has_prefix(mime, "audio")) {
6703 GstStructure *caps_structure = NULL;
6704 gint samplerate = 0;
6706 gchar *caps_str = NULL;
6708 caps_structure = gst_caps_get_structure(caps, 0);
6709 gst_structure_get_int(caps_structure, "rate", &samplerate);
6710 gst_structure_get_int(caps_structure, "channels", &channels);
6712 if ((channels > 0 && samplerate == 0)) {
6713 LOGD("exclude audio...");
6717 caps_str = gst_caps_to_string(caps);
6718 /* set it directly because not sent by TAG */
6719 if (g_strrstr(caps_str, "mobile-xmf"))
6720 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6721 MMPLAYER_FREEIF(caps_str);
6722 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6723 MMMessageParamType msg_param;
6724 memset(&msg_param, 0, sizeof(MMMessageParamType));
6725 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6726 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6727 LOGD("video file is not supported on this device");
6729 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6730 LOGD("already video linked");
6733 LOGD("found new stream");
6740 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6742 int ret = MM_ERROR_NONE;
6744 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6746 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6747 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6749 LOGD("audio codec type: %d", codec_type);
6750 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6751 /* sw codec will be skipped */
6752 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6753 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6754 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6755 ret = MM_ERROR_PLAYER_INTERNAL;
6759 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6760 /* hw codec will be skipped */
6761 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6762 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6763 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6764 ret = MM_ERROR_PLAYER_INTERNAL;
6769 /* set stream information */
6770 if (!player->audiodec_linked)
6771 __mmplayer_set_audio_attrs(player, caps);
6773 /* update codec info */
6774 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6775 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6776 player->audiodec_linked = 1;
6778 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6780 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6782 LOGD("video codec type: %d", codec_type);
6783 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6784 /* sw codec is skipped */
6785 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6786 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6787 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6788 ret = MM_ERROR_PLAYER_INTERNAL;
6792 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6793 /* hw codec is skipped */
6794 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6795 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6796 ret = MM_ERROR_PLAYER_INTERNAL;
6801 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6802 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6804 /* mark video decoder for acquire */
6805 if (player->video_decoder_resource == NULL) {
6806 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6807 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6808 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6809 &player->video_decoder_resource)
6810 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6811 LOGE("could not mark video_decoder resource for acquire");
6812 ret = MM_ERROR_PLAYER_INTERNAL;
6816 LOGW("video decoder resource is already acquired, skip it.");
6817 ret = MM_ERROR_PLAYER_INTERNAL;
6821 player->interrupted_by_resource = FALSE;
6822 /* acquire resources for video playing */
6823 if (mm_resource_manager_commit(player->resource_manager)
6824 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6825 LOGE("could not acquire resources for video decoding");
6826 ret = MM_ERROR_PLAYER_INTERNAL;
6831 /* update codec info */
6832 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6833 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6834 player->videodec_linked = 1;
6842 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6843 GstCaps *caps, GstElementFactory *factory, gpointer data)
6845 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6846 We are defining our own and will be removed when it actually exposed */
6848 GST_AUTOPLUG_SELECT_TRY,
6849 GST_AUTOPLUG_SELECT_EXPOSE,
6850 GST_AUTOPLUG_SELECT_SKIP
6851 } GstAutoplugSelectResult;
6853 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6854 mm_player_t *player = (mm_player_t *)data;
6856 gchar *factory_name = NULL;
6857 gchar *caps_str = NULL;
6858 const gchar *klass = NULL;
6861 factory_name = GST_OBJECT_NAME(factory);
6862 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6863 caps_str = gst_caps_to_string(caps);
6865 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6867 /* store type string */
6868 if (player->type == NULL) {
6869 player->type = gst_caps_to_string(caps);
6870 __mmplayer_update_content_type_info(player);
6873 /* filtering exclude keyword */
6874 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6875 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6876 LOGW("skipping [%s] by exculde keyword [%s]",
6877 factory_name, player->ini.exclude_element_keyword[idx]);
6879 result = GST_AUTOPLUG_SELECT_SKIP;
6884 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6885 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6886 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6887 factory_name, player->ini.unsupported_codec_keyword[idx]);
6888 result = GST_AUTOPLUG_SELECT_SKIP;
6893 /* exclude webm format */
6894 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6895 * because webm format is not supportable.
6896 * If webm is disabled in "autoplug-continue", there is no state change
6897 * failure or error because the decodebin will expose the pad directly.
6898 * It make MSL invoke _prepare_async_callback.
6899 * So, we need to disable webm format in "autoplug-select" */
6900 if (caps_str && strstr(caps_str, "webm")) {
6901 LOGW("webm is not supported");
6902 result = GST_AUTOPLUG_SELECT_SKIP;
6906 /* check factory class for filtering */
6907 /* NOTE : msl don't need to use image plugins.
6908 * So, those plugins should be skipped for error handling.
6910 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6911 LOGD("skipping [%s] by not required", factory_name);
6912 result = GST_AUTOPLUG_SELECT_SKIP;
6916 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6917 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6918 // TO CHECK : subtitle if needed, add subparse exception.
6919 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
6920 result = GST_AUTOPLUG_SELECT_SKIP;
6924 if (g_strrstr(factory_name, "mpegpsdemux")) {
6925 LOGD("skipping PS container - not support");
6926 result = GST_AUTOPLUG_SELECT_SKIP;
6930 if (g_strrstr(factory_name, "mssdemux"))
6931 player->smooth_streaming = TRUE;
6933 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6934 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6937 GstStructure *str = NULL;
6938 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6940 /* don't make video because of not required */
6941 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6942 (!player->set_mode.media_packet_video_stream)) {
6943 LOGD("no need video decoding, expose pad");
6944 result = GST_AUTOPLUG_SELECT_EXPOSE;
6948 /* get w/h for omx state-tune */
6949 /* FIXME: deprecated? */
6950 str = gst_caps_get_structure(caps, 0);
6951 gst_structure_get_int(str, "width", &width);
6954 if (player->v_stream_caps) {
6955 gst_caps_unref(player->v_stream_caps);
6956 player->v_stream_caps = NULL;
6959 player->v_stream_caps = gst_caps_copy(caps);
6960 LOGD("take caps for video state tune");
6961 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
6965 if (g_strrstr(klass, "Codec/Decoder")) {
6966 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
6967 LOGD("skipping %s codec", factory_name);
6968 result = GST_AUTOPLUG_SELECT_SKIP;
6974 MMPLAYER_FREEIF(caps_str);
6980 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
6983 //mm_player_t *player = (mm_player_t *)data;
6984 GstCaps *caps = NULL;
6986 LOGD("[Decodebin2] pad-removed signal");
6988 caps = gst_pad_query_caps(new_pad, NULL);
6990 LOGW("query caps is NULL");
6994 gchar *caps_str = NULL;
6995 caps_str = gst_caps_to_string(caps);
6997 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
6999 MMPLAYER_FREEIF(caps_str);
7000 gst_caps_unref(caps);
7004 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7006 mm_player_t *player = (mm_player_t *)data;
7007 GstIterator *iter = NULL;
7008 GValue item = { 0, };
7010 gboolean done = FALSE;
7011 gboolean is_all_drained = TRUE;
7014 MMPLAYER_RETURN_IF_FAIL(player);
7016 LOGD("__mmplayer_gst_decode_drained");
7018 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7019 LOGW("Fail to get cmd lock");
7023 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7024 !__mmplayer_verify_gapless_play_path(player)) {
7025 LOGD("decoding is finished.");
7026 __mmplayer_reset_gapless_state(player);
7027 MMPLAYER_CMD_UNLOCK(player);
7031 player->gapless.reconfigure = TRUE;
7033 /* check decodebin src pads whether they received EOS or not */
7034 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7037 switch (gst_iterator_next(iter, &item)) {
7038 case GST_ITERATOR_OK:
7039 pad = g_value_get_object(&item);
7040 if (pad && !GST_PAD_IS_EOS(pad)) {
7041 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7042 is_all_drained = FALSE;
7045 g_value_reset(&item);
7047 case GST_ITERATOR_RESYNC:
7048 gst_iterator_resync(iter);
7050 case GST_ITERATOR_ERROR:
7051 case GST_ITERATOR_DONE:
7056 g_value_unset(&item);
7057 gst_iterator_free(iter);
7059 if (!is_all_drained) {
7060 LOGD("Wait util the all pads get EOS.");
7061 MMPLAYER_CMD_UNLOCK(player);
7066 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7067 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7069 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7070 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7071 __mmplayer_deactivate_old_path(player);
7072 MMPLAYER_CMD_UNLOCK(player);
7078 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7080 mm_player_t *player = (mm_player_t *)data;
7081 const gchar *klass = NULL;
7082 gchar *factory_name = NULL;
7084 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7085 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7087 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7089 if (__mmplayer_add_dump_buffer_probe(player, element))
7090 LOGD("add buffer probe");
7093 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7094 gchar *selected = NULL;
7095 selected = g_strdup(GST_ELEMENT_NAME(element));
7096 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7100 if (g_strrstr(klass, "Parser")) {
7101 gchar *selected = NULL;
7103 selected = g_strdup(factory_name);
7104 player->parsers = g_list_append(player->parsers, selected);
7107 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7108 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7109 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7111 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7112 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7114 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7115 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7116 "max-video-width", player->adaptive_info.limit.width,
7117 "max-video-height", player->adaptive_info.limit.height, NULL);
7119 } else if (g_strrstr(klass, "Demuxer")) {
7120 //LOGD("plugged element is demuxer. take it");
7121 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7122 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7125 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7126 int surface_type = 0;
7128 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7131 // to support trust-zone only
7132 if (g_strrstr(factory_name, "asfdemux")) {
7133 LOGD("set file-location %s", player->profile.uri);
7134 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7135 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7136 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7137 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7138 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7139 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7140 (__mmplayer_is_only_mp3_type(player->type))) {
7141 LOGD("[mpegaudioparse] set streaming pull mode.");
7142 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7144 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7145 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7148 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7149 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7150 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7152 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7153 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7155 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7156 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7157 (MMPLAYER_IS_DASH_STREAMING(player))) {
7158 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7159 __mm_player_streaming_set_multiqueue(player->streamer, element);
7160 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7169 __mmplayer_release_misc(mm_player_t *player)
7172 bool cur_mode = player->set_mode.rich_audio;
7175 MMPLAYER_RETURN_IF_FAIL(player);
7177 player->video_stream_cb = NULL;
7178 player->video_stream_cb_user_param = NULL;
7179 player->video_stream_prerolled = false;
7181 player->audio_stream_render_cb = NULL;
7182 player->audio_stream_cb_user_param = NULL;
7183 player->audio_stream_sink_sync = false;
7185 player->video_stream_changed_cb = NULL;
7186 player->video_stream_changed_cb_user_param = NULL;
7188 player->audio_stream_changed_cb = NULL;
7189 player->audio_stream_changed_cb_user_param = NULL;
7191 player->sent_bos = FALSE;
7192 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7194 player->seek_state = MMPLAYER_SEEK_NONE;
7196 player->total_bitrate = 0;
7197 player->total_maximum_bitrate = 0;
7199 player->not_found_demuxer = 0;
7201 player->last_position = 0;
7202 player->duration = 0;
7203 player->http_content_size = 0;
7204 player->not_supported_codec = MISSING_PLUGIN_NONE;
7205 player->can_support_codec = FOUND_PLUGIN_NONE;
7206 player->pending_seek.is_pending = false;
7207 player->pending_seek.pos = 0;
7208 player->msg_posted = FALSE;
7209 player->has_many_types = FALSE;
7210 player->is_subtitle_force_drop = FALSE;
7211 player->play_subtitle = FALSE;
7212 player->adjust_subtitle_pos = 0;
7213 player->last_multiwin_status = FALSE;
7214 player->has_closed_caption = FALSE;
7215 player->set_mode.media_packet_video_stream = false;
7216 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7217 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7219 player->set_mode.rich_audio = cur_mode;
7221 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7222 player->bitrate[i] = 0;
7223 player->maximum_bitrate[i] = 0;
7226 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7228 /* remove media stream cb(appsrc cb) */
7229 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7230 player->media_stream_buffer_status_cb[i] = NULL;
7231 player->media_stream_seek_data_cb[i] = NULL;
7232 player->buffer_cb_user_param[i] = NULL;
7233 player->seek_cb_user_param[i] = NULL;
7235 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7237 /* free memory related to audio effect */
7238 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7240 if (player->adaptive_info.var_list) {
7241 g_list_free_full(player->adaptive_info.var_list, g_free);
7242 player->adaptive_info.var_list = NULL;
7245 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7246 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7247 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7249 /* Reset video360 settings to their defaults in case if the pipeline is to be
7252 player->video360_metadata.is_spherical = -1;
7253 player->is_openal_plugin_used = FALSE;
7255 player->is_content_spherical = FALSE;
7256 player->is_video360_enabled = TRUE;
7257 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7258 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7259 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7260 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7261 player->video360_zoom = 1.0f;
7262 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7263 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7265 player->sound.rg_enable = false;
7267 __mmplayer_initialize_video_roi(player);
7272 __mmplayer_release_misc_post(mm_player_t *player)
7274 char *original_uri = NULL;
7277 /* player->pipeline is already released before. */
7279 MMPLAYER_RETURN_IF_FAIL(player);
7281 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7283 /* clean found parsers */
7284 if (player->parsers) {
7285 GList *parsers = player->parsers;
7286 for (; parsers; parsers = g_list_next(parsers)) {
7287 gchar *name = parsers->data;
7288 MMPLAYER_FREEIF(name);
7290 g_list_free(player->parsers);
7291 player->parsers = NULL;
7294 /* clean found audio decoders */
7295 if (player->audio_decoders) {
7296 GList *a_dec = player->audio_decoders;
7297 for (; a_dec; a_dec = g_list_next(a_dec)) {
7298 gchar *name = a_dec->data;
7299 MMPLAYER_FREEIF(name);
7301 g_list_free(player->audio_decoders);
7302 player->audio_decoders = NULL;
7305 /* clean the uri list except original uri */
7306 if (player->uri_info.uri_list) {
7307 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7309 if (player->attrs) {
7310 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7311 LOGD("restore original uri = %s", original_uri);
7313 if (mm_attrs_commit_all(player->attrs))
7314 LOGE("failed to commit the original uri.");
7317 GList *uri_list = player->uri_info.uri_list;
7318 for (; uri_list; uri_list = g_list_next(uri_list)) {
7319 gchar *uri = uri_list->data;
7320 MMPLAYER_FREEIF(uri);
7322 g_list_free(player->uri_info.uri_list);
7323 player->uri_info.uri_list = NULL;
7326 /* clear the audio stream buffer list */
7327 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7329 /* clear the video stream bo list */
7330 __mmplayer_video_stream_destroy_bo_list(player);
7331 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7333 if (player->profile.input_mem.buf) {
7334 free(player->profile.input_mem.buf);
7335 player->profile.input_mem.buf = NULL;
7337 player->profile.input_mem.len = 0;
7338 player->profile.input_mem.offset = 0;
7340 player->uri_info.uri_idx = 0;
7345 __mmplayer_check_subtitle(mm_player_t *player)
7347 MMHandleType attrs = 0;
7348 char *subtitle_uri = NULL;
7352 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7354 /* get subtitle attribute */
7355 attrs = MMPLAYER_GET_ATTRS(player);
7359 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7360 if (!subtitle_uri || !strlen(subtitle_uri))
7363 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7364 player->is_external_subtitle_present = TRUE;
7372 __mmplayer_cancel_eos_timer(mm_player_t *player)
7374 MMPLAYER_RETURN_IF_FAIL(player);
7376 if (player->eos_timer) {
7377 LOGD("cancel eos timer");
7378 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7379 player->eos_timer = 0;
7386 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7390 MMPLAYER_RETURN_IF_FAIL(player);
7391 MMPLAYER_RETURN_IF_FAIL(sink);
7393 player->sink_elements = g_list_append(player->sink_elements, sink);
7399 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7403 MMPLAYER_RETURN_IF_FAIL(player);
7404 MMPLAYER_RETURN_IF_FAIL(sink);
7406 player->sink_elements = g_list_remove(player->sink_elements, sink);
7412 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7413 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7415 MMPlayerSignalItem *item = NULL;
7418 MMPLAYER_RETURN_IF_FAIL(player);
7420 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7421 LOGE("invalid signal type [%d]", type);
7425 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7427 LOGE("cannot connect signal [%s]", signal);
7432 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7433 player->signals[type] = g_list_append(player->signals[type], item);
7439 /* NOTE : be careful with calling this api. please refer to below glib comment
7440 * glib comment : Note that there is a bug in GObject that makes this function much
7441 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7442 * will no longer be called, but, the signal handler is not currently disconnected.
7443 * If the instance is itself being freed at the same time than this doesn't matter,
7444 * since the signal will automatically be removed, but if instance persists,
7445 * then the signal handler will leak. You should not remove the signal yourself
7446 * because in a future versions of GObject, the handler will automatically be
7449 * It's possible to work around this problem in a way that will continue to work
7450 * with future versions of GObject by checking that the signal handler is still
7451 * connected before disconnected it:
7453 * if (g_signal_handler_is_connected(instance, id))
7454 * g_signal_handler_disconnect(instance, id);
7457 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7459 GList *sig_list = NULL;
7460 MMPlayerSignalItem *item = NULL;
7464 MMPLAYER_RETURN_IF_FAIL(player);
7466 LOGD("release signals type : %d", type);
7468 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7469 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7470 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7471 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7472 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7473 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7477 sig_list = player->signals[type];
7479 for (; sig_list; sig_list = sig_list->next) {
7480 item = sig_list->data;
7482 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7483 if (g_signal_handler_is_connected(item->obj, item->sig))
7484 g_signal_handler_disconnect(item->obj, item->sig);
7487 MMPLAYER_FREEIF(item);
7490 g_list_free(player->signals[type]);
7491 player->signals[type] = NULL;
7499 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7501 mm_player_t *player = 0;
7502 int prev_display_surface_type = 0;
7503 void *prev_display_overlay = NULL;
7507 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7508 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7510 player = MM_PLAYER_CAST(handle);
7512 /* check video sinkbin is created */
7513 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7514 LOGE("Videosink is already created");
7515 return MM_ERROR_NONE;
7518 LOGD("videosink element is not yet ready");
7520 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7521 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7523 return MM_ERROR_INVALID_ARGUMENT;
7526 /* load previous attributes */
7527 if (player->attrs) {
7528 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7529 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7530 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7531 if (prev_display_surface_type == surface_type) {
7532 LOGD("incoming display surface type is same as previous one, do nothing..");
7534 return MM_ERROR_NONE;
7537 LOGE("failed to load attributes");
7539 return MM_ERROR_PLAYER_INTERNAL;
7542 /* videobin is not created yet, so we just set attributes related to display surface */
7543 LOGD("store display attribute for given surface type(%d)", surface_type);
7544 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7545 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7546 if (mm_attrs_commit_all(player->attrs)) {
7547 LOGE("failed to commit attribute");
7549 return MM_ERROR_PLAYER_INTERNAL;
7553 return MM_ERROR_NONE;
7556 /* Note : if silent is true, then subtitle would not be displayed. :*/
7558 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7560 mm_player_t *player = (mm_player_t *)hplayer;
7564 /* check player handle */
7565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7567 player->set_mode.subtitle_off = silent;
7569 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7573 return MM_ERROR_NONE;
7577 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7579 MMPlayerGstElement *mainbin = NULL;
7580 MMPlayerGstElement *textbin = NULL;
7581 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7582 GstState current_state = GST_STATE_VOID_PENDING;
7583 GstState element_state = GST_STATE_VOID_PENDING;
7584 GstState element_pending_state = GST_STATE_VOID_PENDING;
7586 GstEvent *event = NULL;
7587 int result = MM_ERROR_NONE;
7589 GstClock *curr_clock = NULL;
7590 GstClockTime base_time, start_time, curr_time;
7595 /* check player handle */
7596 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7598 player->pipeline->mainbin &&
7599 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7601 mainbin = player->pipeline->mainbin;
7602 textbin = player->pipeline->textbin;
7604 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7606 // sync clock with current pipeline
7607 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7608 curr_time = gst_clock_get_time(curr_clock);
7610 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7611 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7613 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7614 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7616 if (current_state > GST_STATE_READY) {
7617 // sync state with current pipeline
7618 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7619 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7620 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7622 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7623 if (GST_STATE_CHANGE_FAILURE == ret) {
7624 LOGE("fail to state change.");
7625 result = MM_ERROR_PLAYER_INTERNAL;
7629 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7630 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7633 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7634 gst_object_unref(curr_clock);
7637 // seek to current position
7638 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7639 result = MM_ERROR_PLAYER_INVALID_STATE;
7640 LOGE("gst_element_query_position failed, invalid state");
7644 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7645 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);
7647 __mmplayer_gst_send_event_to_sink(player, event);
7649 result = MM_ERROR_PLAYER_INTERNAL;
7650 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7654 /* sync state with current pipeline */
7655 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7656 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7657 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7659 return MM_ERROR_NONE;
7662 /* release text pipeline resource */
7663 player->textsink_linked = 0;
7665 /* release signal */
7666 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7668 /* release textbin with it's childs */
7669 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7670 MMPLAYER_FREEIF(player->pipeline->textbin);
7671 player->pipeline->textbin = NULL;
7673 /* release subtitle elem */
7674 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7675 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7681 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7683 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7684 GstState current_state = GST_STATE_VOID_PENDING;
7686 MMHandleType attrs = 0;
7687 MMPlayerGstElement *mainbin = NULL;
7688 MMPlayerGstElement *textbin = NULL;
7690 gchar *subtitle_uri = NULL;
7691 int result = MM_ERROR_NONE;
7692 const gchar *charset = NULL;
7696 /* check player handle */
7697 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7699 player->pipeline->mainbin &&
7700 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7701 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7703 mainbin = player->pipeline->mainbin;
7704 textbin = player->pipeline->textbin;
7706 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7707 if (current_state < GST_STATE_READY) {
7708 result = MM_ERROR_PLAYER_INVALID_STATE;
7709 LOGE("Pipeline is not in proper state");
7713 attrs = MMPLAYER_GET_ATTRS(player);
7715 LOGE("cannot get content attribute");
7716 result = MM_ERROR_PLAYER_INTERNAL;
7720 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7721 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7722 LOGE("subtitle uri is not proper filepath");
7723 result = MM_ERROR_PLAYER_INVALID_URI;
7727 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7728 LOGE("failed to get storage info of subtitle path");
7729 result = MM_ERROR_PLAYER_INVALID_URI;
7733 LOGD("old subtitle file path is [%s]", subtitle_uri);
7734 LOGD("new subtitle file path is [%s]", filepath);
7736 if (!strcmp(filepath, subtitle_uri)) {
7737 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7740 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7741 if (mm_attrs_commit_all(player->attrs)) {
7742 LOGE("failed to commit.");
7747 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7748 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7749 player->subtitle_language_list = NULL;
7750 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7752 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7753 if (ret != GST_STATE_CHANGE_SUCCESS) {
7754 LOGE("failed to change state of textbin to READY");
7755 result = MM_ERROR_PLAYER_INTERNAL;
7759 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7760 if (ret != GST_STATE_CHANGE_SUCCESS) {
7761 LOGE("failed to change state of subparse to READY");
7762 result = MM_ERROR_PLAYER_INTERNAL;
7766 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7767 if (ret != GST_STATE_CHANGE_SUCCESS) {
7768 LOGE("failed to change state of filesrc to READY");
7769 result = MM_ERROR_PLAYER_INTERNAL;
7773 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7775 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7777 charset = util_get_charset(filepath);
7779 LOGD("detected charset is %s", charset);
7780 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7783 result = _mmplayer_sync_subtitle_pipeline(player);
7790 /* API to switch between external subtitles */
7792 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7794 int result = MM_ERROR_NONE;
7795 mm_player_t *player = (mm_player_t *)hplayer;
7800 /* check player handle */
7801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7803 /* filepath can be null in idle state */
7805 /* check file path */
7806 if ((path = strstr(filepath, "file://")))
7807 result = util_exist_file_path(path + 7);
7809 result = util_exist_file_path(filepath);
7811 if (result != MM_ERROR_NONE) {
7812 LOGE("invalid subtitle path 0x%X", result);
7813 return result; /* file not found or permission denied */
7817 if (!player->pipeline) {
7819 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7820 if (mm_attrs_commit_all(player->attrs)) {
7821 LOGE("failed to commit"); /* subtitle path will not be created */
7822 return MM_ERROR_PLAYER_INTERNAL;
7825 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7826 /* check filepath */
7827 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7829 if (!__mmplayer_check_subtitle(player)) {
7830 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7831 if (mm_attrs_commit_all(player->attrs)) {
7832 LOGE("failed to commit");
7833 return MM_ERROR_PLAYER_INTERNAL;
7836 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7837 LOGE("fail to create text pipeline");
7838 return MM_ERROR_PLAYER_INTERNAL;
7841 result = _mmplayer_sync_subtitle_pipeline(player);
7843 result = __mmplayer_change_external_subtitle_language(player, filepath);
7846 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7847 player->is_external_subtitle_added_now = TRUE;
7849 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7850 if (!player->subtitle_language_list) {
7851 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7852 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7853 LOGW("subtitle language list is not updated yet");
7855 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7863 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7865 int result = MM_ERROR_NONE;
7866 gchar *change_pad_name = NULL;
7867 GstPad *sinkpad = NULL;
7868 MMPlayerGstElement *mainbin = NULL;
7869 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7870 GstCaps *caps = NULL;
7871 gint total_track_num = 0;
7875 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7876 MM_ERROR_PLAYER_NOT_INITIALIZED);
7878 LOGD("Change Track(%d) to %d", type, index);
7880 mainbin = player->pipeline->mainbin;
7882 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7883 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7884 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7885 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7887 /* Changing Video Track is not supported. */
7888 LOGE("Track Type Error");
7892 if (mainbin[elem_idx].gst == NULL) {
7893 result = MM_ERROR_PLAYER_NO_OP;
7894 LOGD("Req track doesn't exist");
7898 total_track_num = player->selector[type].total_track_num;
7899 if (total_track_num <= 0) {
7900 result = MM_ERROR_PLAYER_NO_OP;
7901 LOGD("Language list is not available");
7905 if ((index < 0) || (index >= total_track_num)) {
7906 result = MM_ERROR_INVALID_ARGUMENT;
7907 LOGD("Not a proper index : %d", index);
7911 /*To get the new pad from the selector*/
7912 change_pad_name = g_strdup_printf("sink_%u", index);
7913 if (change_pad_name == NULL) {
7914 result = MM_ERROR_PLAYER_INTERNAL;
7915 LOGD("Pad does not exists");
7919 LOGD("new active pad name: %s", change_pad_name);
7921 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7922 if (sinkpad == NULL) {
7923 LOGD("sinkpad is NULL");
7924 result = MM_ERROR_PLAYER_INTERNAL;
7928 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
7929 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7931 caps = gst_pad_get_current_caps(sinkpad);
7932 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7935 gst_object_unref(sinkpad);
7937 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7938 __mmplayer_set_audio_attrs(player, caps);
7941 MMPLAYER_FREEIF(change_pad_name);
7946 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7948 int result = MM_ERROR_NONE;
7949 mm_player_t *player = NULL;
7950 MMPlayerGstElement *mainbin = NULL;
7952 gint current_active_index = 0;
7954 GstState current_state = GST_STATE_VOID_PENDING;
7955 GstEvent *event = NULL;
7960 player = (mm_player_t *)hplayer;
7961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7963 if (!player->pipeline) {
7964 LOGE("Track %d pre setting -> %d", type, index);
7966 player->selector[type].active_pad_index = index;
7970 mainbin = player->pipeline->mainbin;
7972 current_active_index = player->selector[type].active_pad_index;
7974 /*If index is same as running index no need to change the pad*/
7975 if (current_active_index == index)
7978 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7979 result = MM_ERROR_PLAYER_INVALID_STATE;
7983 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7984 if (current_state < GST_STATE_PAUSED) {
7985 result = MM_ERROR_PLAYER_INVALID_STATE;
7986 LOGW("Pipeline not in porper state");
7990 result = __mmplayer_change_selector_pad(player, type, index);
7991 if (result != MM_ERROR_NONE) {
7992 LOGE("change selector pad error");
7996 player->selector[type].active_pad_index = index;
7998 if (current_state == GST_STATE_PLAYING) {
7999 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8000 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8001 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8003 __mmplayer_gst_send_event_to_sink(player, event);
8005 result = MM_ERROR_PLAYER_INTERNAL;
8015 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8017 mm_player_t *player = (mm_player_t *)hplayer;
8021 /* check player handle */
8022 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8024 *silent = player->set_mode.subtitle_off;
8026 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8030 return MM_ERROR_NONE;
8034 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8036 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8037 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8039 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8040 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8044 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8045 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8046 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8047 mm_player_dump_t *dump_s;
8048 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8049 if (dump_s == NULL) {
8050 LOGE("malloc fail");
8054 dump_s->dump_element_file = NULL;
8055 dump_s->dump_pad = NULL;
8056 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8058 if (dump_s->dump_pad) {
8059 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8060 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]);
8061 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8062 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);
8063 /* add list for removed buffer probe and close FILE */
8064 player->dump_list = g_list_append(player->dump_list, dump_s);
8065 LOGD("%s sink pad added buffer probe for dump", factory_name);
8068 MMPLAYER_FREEIF(dump_s);
8069 LOGE("failed to get %s sink pad added", factory_name);
8076 static GstPadProbeReturn
8077 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8079 FILE *dump_data = (FILE *)u_data;
8081 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8082 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8084 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8086 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8088 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8090 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8092 return GST_PAD_PROBE_OK;
8096 __mmplayer_release_dump_list(GList *dump_list)
8098 GList *d_list = dump_list;
8103 for (; d_list; d_list = g_list_next(d_list)) {
8104 mm_player_dump_t *dump_s = d_list->data;
8105 if (dump_s->dump_pad) {
8106 if (dump_s->probe_handle_id)
8107 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8109 if (dump_s->dump_element_file) {
8110 fclose(dump_s->dump_element_file);
8111 dump_s->dump_element_file = NULL;
8113 MMPLAYER_FREEIF(dump_s);
8115 g_list_free(dump_list);
8120 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8122 mm_player_t *player = (mm_player_t *)hplayer;
8126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8127 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8129 *exist = (bool)player->has_closed_caption;
8133 return MM_ERROR_NONE;
8137 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8141 // LOGD("unref internal gst buffer %p", buffer);
8142 gst_buffer_unref((GstBuffer *)buffer);
8149 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8151 mm_player_t *player = (mm_player_t *)hplayer;
8155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8156 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8158 if (MMPLAYER_IS_STREAMING(player))
8159 *timeout = (int)player->ini.live_state_change_timeout;
8161 *timeout = (int)player->ini.localplayback_state_change_timeout;
8163 LOGD("timeout = %d", *timeout);
8166 return MM_ERROR_NONE;
8170 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8172 mm_player_t *player = (mm_player_t *)hplayer;
8176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8177 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8179 *num = player->video_num_buffers;
8180 *extra_num = player->video_extra_num_buffers;
8182 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8185 return MM_ERROR_NONE;
8189 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8193 MMPLAYER_RETURN_IF_FAIL(player);
8195 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8197 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8198 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8199 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8200 player->storage_info[i].id = -1;
8201 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8203 if (path_type != MMPLAYER_PATH_MAX)
8212 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8214 int ret = MM_ERROR_NONE;
8215 mm_player_t *player = (mm_player_t *)hplayer;
8216 MMMessageParamType msg_param = {0, };
8219 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8221 LOGW("state changed storage %d:%d", id, state);
8223 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8224 return MM_ERROR_NONE;
8226 /* FIXME: text path should be handled seperately. */
8227 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8228 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8229 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8230 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8231 LOGW("external storage is removed");
8233 if (player->msg_posted == FALSE) {
8234 memset(&msg_param, 0, sizeof(MMMessageParamType));
8235 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8236 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8237 player->msg_posted = TRUE;
8240 /* unrealize the player */
8241 ret = _mmplayer_unrealize(hplayer);
8242 if (ret != MM_ERROR_NONE)
8243 LOGE("failed to unrealize");
8251 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8253 int ret = MM_ERROR_NONE;
8254 mm_player_t *player = (mm_player_t *)hplayer;
8255 int idx = 0, total = 0;
8256 gchar *result = NULL, *tmp = NULL;
8259 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8260 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8262 total = *num = g_list_length(player->adaptive_info.var_list);
8264 LOGW("There is no stream variant info.");
8268 result = g_strdup("");
8269 for (idx = 0 ; idx < total ; idx++) {
8270 VariantData *v_data = NULL;
8271 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8274 gchar data[64] = {0};
8275 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8277 tmp = g_strconcat(result, data, NULL);
8281 LOGW("There is no variant data in %d", idx);
8286 *var_info = (char *)result;
8288 LOGD("variant info %d:%s", *num, *var_info);
8294 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8296 int ret = MM_ERROR_NONE;
8297 mm_player_t *player = (mm_player_t *)hplayer;
8300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8302 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8304 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8305 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8306 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8308 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8309 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8310 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8311 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8313 /* FIXME: seek to current position for applying new variant limitation */
8322 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8324 int ret = MM_ERROR_NONE;
8325 mm_player_t *player = (mm_player_t *)hplayer;
8328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8329 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8331 *bandwidth = player->adaptive_info.limit.bandwidth;
8332 *width = player->adaptive_info.limit.width;
8333 *height = player->adaptive_info.limit.height;
8335 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8342 _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8344 int ret = MM_ERROR_NONE;
8345 mm_player_t *player = (mm_player_t *)hplayer;
8348 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8350 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8351 LOGW("buffer_ms will not be applied.");
8353 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8355 if (player->streamer == NULL) {
8356 player->streamer = __mm_player_streaming_create();
8357 __mm_player_streaming_initialize(player->streamer, TRUE);
8361 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8363 if (rebuffer_ms >= 0)
8364 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8372 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8374 int ret = MM_ERROR_NONE;
8375 mm_player_t *player = (mm_player_t *)hplayer;
8378 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8379 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8381 if (player->streamer == NULL) {
8382 player->streamer = __mm_player_streaming_create();
8383 __mm_player_streaming_initialize(player->streamer, TRUE);
8386 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8387 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8389 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8396 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8398 #define IDX_FIRST_SW_CODEC 0
8399 mm_player_t *player = (mm_player_t *)hplayer;
8400 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8401 MMHandleType attrs = 0;
8404 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8406 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8407 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8408 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8410 switch (stream_type) {
8411 case MM_PLAYER_STREAM_TYPE_AUDIO:
8412 /* to support audio codec selection, codec info have to be added in ini file as below.
8413 audio codec element hw = xxxx
8414 audio codec element sw = avdec */
8415 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8416 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8417 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8418 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8419 LOGE("There is no audio codec info for codec_type %d", codec_type);
8420 return MM_ERROR_PLAYER_NO_OP;
8423 case MM_PLAYER_STREAM_TYPE_VIDEO:
8424 /* to support video codec selection, codec info have to be added in ini file as below.
8425 video codec element hw = omx
8426 video codec element sw = avdec */
8427 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8428 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8429 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8430 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8431 LOGE("There is no video codec info for codec_type %d", codec_type);
8432 return MM_ERROR_PLAYER_NO_OP;
8436 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8437 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8441 LOGD("update %s codec_type to %d", attr_name, codec_type);
8443 attrs = MMPLAYER_GET_ATTRS(player);
8444 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8446 if (mm_attrs_commit_all(player->attrs)) {
8447 LOGE("failed to commit codec_type attributes");
8448 return MM_ERROR_PLAYER_INTERNAL;
8452 return MM_ERROR_NONE;
8456 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8458 mm_player_t *player = (mm_player_t *)hplayer;
8459 GstElement *rg_vol_element = NULL;
8463 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8465 player->sound.rg_enable = enabled;
8467 /* just hold rgvolume enable value if pipeline is not ready */
8468 if (!player->pipeline || !player->pipeline->audiobin) {
8469 LOGD("pipeline is not ready. holding rgvolume enable value");
8470 return MM_ERROR_NONE;
8473 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8475 if (!rg_vol_element) {
8476 LOGD("rgvolume element is not created");
8477 return MM_ERROR_PLAYER_INTERNAL;
8481 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8483 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8487 return MM_ERROR_NONE;
8491 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8493 mm_player_t *player = (mm_player_t *)hplayer;
8494 GstElement *rg_vol_element = NULL;
8495 gboolean enable = FALSE;
8499 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8500 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8502 /* just hold enable_rg value if pipeline is not ready */
8503 if (!player->pipeline || !player->pipeline->audiobin) {
8504 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8505 *enabled = player->sound.rg_enable;
8506 return MM_ERROR_NONE;
8509 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8511 if (!rg_vol_element) {
8512 LOGD("rgvolume element is not created");
8513 return MM_ERROR_PLAYER_INTERNAL;
8516 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8517 *enabled = (bool)enable;
8521 return MM_ERROR_NONE;
8525 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8527 mm_player_t *player = (mm_player_t *)hplayer;
8528 MMHandleType attrs = 0;
8529 void *handle = NULL;
8530 int ret = MM_ERROR_NONE;
8534 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8536 attrs = MMPLAYER_GET_ATTRS(player);
8537 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8539 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8541 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8542 return MM_ERROR_PLAYER_INTERNAL;
8545 player->video_roi.scale_x = scale_x;
8546 player->video_roi.scale_y = scale_y;
8547 player->video_roi.scale_width = scale_width;
8548 player->video_roi.scale_height = scale_height;
8550 /* check video sinkbin is created */
8551 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8552 return MM_ERROR_NONE;
8554 if (!gst_video_overlay_set_video_roi_area(
8555 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8556 scale_x, scale_y, scale_width, scale_height))
8557 ret = MM_ERROR_PLAYER_INTERNAL;
8559 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8560 scale_x, scale_y, scale_width, scale_height);
8568 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8570 mm_player_t *player = (mm_player_t *)hplayer;
8571 int ret = MM_ERROR_NONE;
8575 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8576 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8578 *scale_x = player->video_roi.scale_x;
8579 *scale_y = player->video_roi.scale_y;
8580 *scale_width = player->video_roi.scale_width;
8581 *scale_height = player->video_roi.scale_height;
8583 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8584 *scale_x, *scale_y, *scale_width, *scale_height);
8590 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8592 gboolean ret = FALSE;
8593 gint64 dur_nsec = 0;
8594 LOGD("try to update duration");
8596 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8597 player->duration = dur_nsec;
8598 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8602 if (player->duration < 0) {
8603 LOGW("duration is Non-Initialized !!!");
8604 player->duration = 0;
8607 /* update streaming service type */
8608 player->streaming_type = __mmplayer_get_stream_service_type(player);
8610 /* check duration is OK */
8611 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8612 /* FIXIT : find another way to get duration here. */
8613 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8619 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8621 /* update audio params
8622 NOTE : We need original audio params and it can be only obtained from src pad of audio
8623 decoder. Below code only valid when we are not using 'resampler' just before
8624 'audioconverter'. */
8625 GstCaps *caps_a = NULL;
8627 gint samplerate = 0, channels = 0;
8628 GstStructure *p = NULL;
8630 LOGD("try to update audio attrs");
8632 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8633 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8635 pad = gst_element_get_static_pad(
8636 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8639 LOGW("failed to get pad from audiosink");
8643 caps_a = gst_pad_get_current_caps(pad);
8645 LOGW("not ready to get audio caps");
8646 gst_object_unref(pad);
8650 p = gst_caps_get_structure(caps_a, 0);
8652 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8654 gst_structure_get_int(p, "rate", &samplerate);
8655 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8657 gst_structure_get_int(p, "channels", &channels);
8658 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8660 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8662 gst_caps_unref(caps_a);
8663 gst_object_unref(pad);
8669 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8671 LOGD("try to update video attrs");
8673 GstCaps *caps_v = NULL;
8677 GstStructure *p = NULL;
8679 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8680 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8682 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8684 LOGD("no videosink sink pad");
8688 caps_v = gst_pad_get_current_caps(pad);
8689 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8690 if (!caps_v && player->v_stream_caps) {
8691 caps_v = player->v_stream_caps;
8692 gst_caps_ref(caps_v);
8696 LOGD("no negitiated caps from videosink");
8697 gst_object_unref(pad);
8701 p = gst_caps_get_structure(caps_v, 0);
8702 gst_structure_get_int(p, "width", &width);
8703 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8705 gst_structure_get_int(p, "height", &height);
8706 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8708 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8710 SECURE_LOGD("width : %d height : %d", width, height);
8712 gst_caps_unref(caps_v);
8713 gst_object_unref(pad);
8716 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8717 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8724 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8726 gboolean ret = FALSE;
8727 guint64 data_size = 0;
8731 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8732 if (!player->duration)
8735 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8736 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8737 if (stat(path, &sb) == 0)
8738 data_size = (guint64)sb.st_size;
8740 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8741 data_size = player->http_content_size;
8744 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8747 guint64 bitrate = 0;
8748 guint64 msec_dur = 0;
8750 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8752 bitrate = data_size * 8 * 1000 / msec_dur;
8753 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8754 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8758 LOGD("player duration is less than 0");
8762 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8763 if (player->total_bitrate) {
8764 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8773 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8775 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8776 data->uri_type = uri_type;
8780 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8782 int ret = MM_ERROR_PLAYER_INVALID_URI;
8784 char *buffer = NULL;
8785 char *seperator = strchr(path, ',');
8786 char ext[100] = {0,}, size[100] = {0,};
8789 if ((buffer = strstr(path, "ext="))) {
8790 buffer += strlen("ext=");
8792 if (strlen(buffer)) {
8793 strncpy(ext, buffer, 99);
8795 if ((seperator = strchr(ext, ','))
8796 || (seperator = strchr(ext, ' '))
8797 || (seperator = strchr(ext, '\0'))) {
8798 seperator[0] = '\0';
8803 if ((buffer = strstr(path, "size="))) {
8804 buffer += strlen("size=");
8806 if (strlen(buffer) > 0) {
8807 strncpy(size, buffer, 99);
8809 if ((seperator = strchr(size, ','))
8810 || (seperator = strchr(size, ' '))
8811 || (seperator = strchr(size, '\0'))) {
8812 seperator[0] = '\0';
8815 mem_size = atoi(size);
8820 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8822 if (mem_size && param) {
8823 if (data->input_mem.buf)
8824 free(data->input_mem.buf);
8825 data->input_mem.buf = malloc(mem_size);
8827 if (data->input_mem.buf) {
8828 memcpy(data->input_mem.buf, param, mem_size);
8829 data->input_mem.len = mem_size;
8830 ret = MM_ERROR_NONE;
8832 LOGE("failed to alloc mem %d", mem_size);
8833 ret = MM_ERROR_PLAYER_INTERNAL;
8836 data->input_mem.offset = 0;
8837 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8844 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8846 gchar *location = NULL;
8849 int ret = MM_ERROR_NONE;
8851 if ((path = strstr(uri, "file://"))) {
8852 location = g_filename_from_uri(uri, NULL, &err);
8853 if (!location || (err != NULL)) {
8854 LOGE("Invalid URI '%s' for filesrc: %s", path,
8855 (err != NULL) ? err->message : "unknown error");
8859 MMPLAYER_FREEIF(location);
8861 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8862 return MM_ERROR_PLAYER_INVALID_URI;
8864 LOGD("path from uri: %s", location);
8867 path = (location != NULL) ? (location) : ((char *)uri);
8870 ret = util_exist_file_path(path);
8872 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8873 if (ret == MM_ERROR_NONE) {
8874 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8875 if (util_is_sdp_file(path)) {
8876 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8877 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8879 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8881 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8882 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8884 LOGE("invalid uri, could not play..");
8885 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8888 MMPLAYER_FREEIF(location);
8893 static MMPlayerVideoStreamDataType *
8894 __mmplayer_create_stream_from_pad(GstPad *pad)
8896 GstCaps *caps = NULL;
8897 GstStructure *structure = NULL;
8898 unsigned int fourcc = 0;
8899 const gchar *string_format = NULL;
8900 MMPlayerVideoStreamDataType *stream = NULL;
8902 MMPixelFormatType format;
8904 caps = gst_pad_get_current_caps(pad);
8906 LOGE("Caps is NULL.");
8910 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8911 structure = gst_caps_get_structure(caps, 0);
8912 gst_structure_get_int(structure, "width", &width);
8913 gst_structure_get_int(structure, "height", &height);
8914 string_format = gst_structure_get_string(structure, "format");
8916 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8917 format = util_get_pixtype(fourcc);
8918 gst_caps_unref(caps);
8921 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8922 LOGE("Wrong condition!!");
8926 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
8928 LOGE("failed to alloc mem for video data");
8932 stream->width = width;
8933 stream->height = height;
8934 stream->format = format;
8940 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8942 unsigned int pitch = 0;
8944 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8946 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8947 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8948 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8949 stream->stride[index] = pitch;
8950 stream->elevation[index] = stream->height;
8955 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8957 if (stream->format == MM_PIXEL_FORMAT_I420) {
8958 int ret = TBM_SURFACE_ERROR_NONE;
8959 tbm_surface_h surface;
8960 tbm_surface_info_s info;
8962 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8964 ret = tbm_surface_get_info(surface, &info);
8965 if (ret != TBM_SURFACE_ERROR_NONE) {
8966 tbm_surface_destroy(surface);
8970 tbm_surface_destroy(surface);
8971 stream->stride[0] = info.planes[0].stride;
8972 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
8973 stream->stride[1] = info.planes[1].stride;
8974 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
8975 stream->stride[2] = info.planes[2].stride;
8976 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
8977 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
8978 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
8979 stream->stride[0] = stream->width * 4;
8980 stream->elevation[0] = stream->height;
8981 stream->bo_size = stream->stride[0] * stream->height;
8983 LOGE("Not support format %d", stream->format);
8991 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8993 tbm_bo_handle thandle;
8995 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
8996 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
8997 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9001 unsigned char *src = NULL;
9002 unsigned char *dest = NULL;
9003 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9005 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9007 LOGE("fail to gst_memory_map");
9011 if (!mapinfo.data) {
9012 LOGE("data pointer is wrong");
9016 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9017 if (!stream->bo[0]) {
9018 LOGE("Fail to tbm_bo_alloc!!");
9022 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9024 LOGE("thandle pointer is wrong");
9028 if (stream->format == MM_PIXEL_FORMAT_I420) {
9029 src_stride[0] = GST_ROUND_UP_4(stream->width);
9030 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9031 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9032 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9035 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9036 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9038 for (i = 0; i < 3; i++) {
9039 src = mapinfo.data + src_offset[i];
9040 dest = thandle.ptr + dest_offset[i];
9045 for (j = 0; j < stream->height >> k; j++) {
9046 memcpy(dest, src, stream->width>>k);
9047 src += src_stride[i];
9048 dest += stream->stride[i];
9051 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9052 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9054 LOGE("Not support format %d", stream->format);
9058 tbm_bo_unmap(stream->bo[0]);
9059 gst_memory_unmap(mem, &mapinfo);
9065 tbm_bo_unmap(stream->bo[0]);
9068 gst_memory_unmap(mem, &mapinfo);
9074 __mmplayer_set_pause_state(mm_player_t *player)
9076 if (player->sent_bos)
9079 /* rtsp case, get content attrs by GstMessage */
9080 if (MMPLAYER_IS_RTSP_STREAMING(player))
9083 /* it's first time to update all content attrs. */
9084 __mmplayer_update_content_attrs(player, ATTR_ALL);
9088 __mmplayer_set_playing_state(mm_player_t *player)
9090 gchar *audio_codec = NULL;
9092 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9093 /* initialize because auto resume is done well. */
9094 player->resumed_by_rewind = FALSE;
9095 player->playback_rate = 1.0;
9098 if (player->sent_bos)
9101 /* try to get content metadata */
9103 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9104 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9105 * legacy mmfw-player api
9107 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9109 if ((player->cmd == MMPLAYER_COMMAND_START)
9110 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9111 __mmplayer_handle_missed_plugin(player);
9114 /* check audio codec field is set or not
9115 * we can get it from typefinder or codec's caps.
9117 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9119 /* The codec format can't be sent for audio only case like amr, mid etc.
9120 * Because, parser don't make related TAG.
9121 * So, if it's not set yet, fill it with found data.
9124 if (g_strrstr(player->type, "audio/midi"))
9125 audio_codec = "MIDI";
9126 else if (g_strrstr(player->type, "audio/x-amr"))
9127 audio_codec = "AMR";
9128 else if (g_strrstr(player->type, "audio/mpeg")
9129 && !g_strrstr(player->type, "mpegversion= (int)1"))
9130 audio_codec = "AAC";
9132 audio_codec = "unknown";
9134 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9136 if (mm_attrs_commit_all(player->attrs))
9137 LOGE("failed to update attributes");
9139 LOGD("set audio codec type with caps");