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>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
94 #define PLAYER_DISPLAY_MODE_DST_ROI 5
96 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
98 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
99 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
100 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
101 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
103 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
104 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
106 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
108 /*---------------------------------------------------------------------------
109 | LOCAL CONSTANT DEFINITIONS: |
110 ---------------------------------------------------------------------------*/
112 /*---------------------------------------------------------------------------
113 | LOCAL DATA TYPE DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
115 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
116 We are defining our own and will be removed when it actually exposed */
118 GST_AUTOPLUG_SELECT_TRY,
119 GST_AUTOPLUG_SELECT_EXPOSE,
120 GST_AUTOPLUG_SELECT_SKIP
121 } GstAutoplugSelectResult;
123 /*---------------------------------------------------------------------------
124 | GLOBAL VARIABLE DEFINITIONS: |
125 ---------------------------------------------------------------------------*/
127 /*---------------------------------------------------------------------------
128 | LOCAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
130 static sound_stream_info_h stream_info;
132 /*---------------------------------------------------------------------------
133 | LOCAL FUNCTION PROTOTYPES: |
134 ---------------------------------------------------------------------------*/
135 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
136 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
137 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
138 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
139 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
140 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
142 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
143 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
144 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
145 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
146 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
147 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
148 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
149 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
150 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
151 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
152 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
154 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_release_misc(mm_player_t *player);
156 static void __mmplayer_release_misc_post(mm_player_t *player);
157 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
158 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
159 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
160 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
161 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
163 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
164 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
165 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
166 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
167 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
168 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
169 static gpointer __mmplayer_gapless_play_thread(gpointer data);
170 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
171 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
172 static void __mmplayer_release_dump_list(GList *dump_list);
173 static int __mmplayer_gst_realize(mm_player_t *player);
174 static int __mmplayer_gst_unrealize(mm_player_t *player);
175 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
176 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
179 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
180 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
181 static void __mmplayer_check_pipeline(mm_player_t *player);
182 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
183 static void __mmplayer_deactivate_old_path(mm_player_t *player);
184 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
185 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
186 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
187 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
188 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
189 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
190 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
199 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mm_player_t *player);
205 static void __mmplayer_set_playing_state(mm_player_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
214 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
218 count = gst_tag_list_get_tag_size(list, tag);
220 LOGD("count = %d", count);
222 for (i = 0; i < count; i++) {
225 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
226 if (!gst_tag_list_get_string_index(list, tag, i, &str))
227 g_assert_not_reached();
229 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
233 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
235 g_print(" : %s", str);
242 /* This function should be called after the pipeline goes PAUSED or higher
245 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
247 static gboolean has_duration = FALSE;
248 static gboolean has_video_attrs = FALSE;
249 static gboolean has_audio_attrs = FALSE;
250 static gboolean has_bitrate = FALSE;
251 gboolean missing_only = FALSE;
252 gboolean all = FALSE;
253 MMHandleType attrs = 0;
257 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
259 /* check player state here */
260 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
261 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
262 /* give warning now only */
263 LOGW("be careful. content attributes may not available in this state ");
266 /* get content attribute first */
267 attrs = MMPLAYER_GET_ATTRS(player);
269 LOGE("cannot get content attribute");
273 /* get update flag */
275 if (flag & ATTR_MISSING_ONLY) {
277 LOGD("updating missed attr only");
280 if (flag & ATTR_ALL) {
282 has_duration = FALSE;
283 has_video_attrs = FALSE;
284 has_audio_attrs = FALSE;
287 LOGD("updating all attrs");
290 if (missing_only && all) {
291 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
292 missing_only = FALSE;
295 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
296 has_duration = __mmplayer_update_duration_value(player);
298 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
299 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
301 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
302 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
304 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
305 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
308 if (mm_attrs_commit_all(attrs)) {
309 LOGE("failed to update attributes");
319 __mmplayer_get_stream_service_type(mm_player_t *player)
321 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
325 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
327 player->pipeline->mainbin &&
328 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
329 STREAMING_SERVICE_NONE);
331 /* streaming service type if streaming */
332 if (!MMPLAYER_IS_STREAMING(player))
333 return STREAMING_SERVICE_NONE;
335 streaming_type = (player->duration == 0) ?
336 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
338 switch (streaming_type) {
339 case STREAMING_SERVICE_LIVE:
340 LOGD("it's live streaming");
342 case STREAMING_SERVICE_VOD:
343 LOGD("it's vod streaming");
346 LOGE("should not get here");
352 return streaming_type;
355 /* this function sets the player state and also report
356 * it to applicaton by calling callback function
359 __mmplayer_set_state(mm_player_t *player, int state)
361 MMMessageParamType msg = {0, };
363 MMPLAYER_RETURN_IF_FAIL(player);
365 if (MMPLAYER_CURRENT_STATE(player) == state) {
366 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
371 /* update player states */
372 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
373 MMPLAYER_CURRENT_STATE(player) = state;
375 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
376 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
379 MMPLAYER_PRINT_STATE(player);
381 switch (MMPLAYER_CURRENT_STATE(player)) {
382 case MM_PLAYER_STATE_NULL:
383 case MM_PLAYER_STATE_READY:
385 case MM_PLAYER_STATE_PAUSED:
386 __mmplayer_set_pause_state(player);
388 case MM_PLAYER_STATE_PLAYING:
389 __mmplayer_set_playing_state(player);
391 case MM_PLAYER_STATE_NONE:
393 LOGW("invalid target state, there is nothing to do.");
398 /* post message to application */
399 if (MMPLAYER_TARGET_STATE(player) == state) {
400 /* fill the message with state of player */
401 msg.union_type = MM_MSG_UNION_STATE;
402 msg.state.previous = MMPLAYER_PREV_STATE(player);
403 msg.state.current = MMPLAYER_CURRENT_STATE(player);
405 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
407 /* state changed by resource callback */
408 if (player->interrupted_by_resource)
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
410 else /* state changed by usecase */
411 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
414 LOGD("intermediate state, do nothing.");
415 MMPLAYER_PRINT_STATE(player);
419 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
420 && !player->sent_bos) {
421 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
422 player->sent_bos = TRUE;
429 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
431 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
432 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
436 //LOGD("incomming command : %d ", command);
438 current_state = MMPLAYER_CURRENT_STATE(player);
439 pending_state = MMPLAYER_PENDING_STATE(player);
441 MMPLAYER_PRINT_STATE(player);
444 case MMPLAYER_COMMAND_CREATE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL ||
449 current_state == MM_PLAYER_STATE_READY ||
450 current_state == MM_PLAYER_STATE_PAUSED ||
451 current_state == MM_PLAYER_STATE_PLAYING)
456 case MMPLAYER_COMMAND_DESTROY:
458 /* destroy can called anytime */
460 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
464 case MMPLAYER_COMMAND_REALIZE:
466 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
468 if (pending_state != MM_PLAYER_STATE_NONE) {
471 /* need ready state to realize */
472 if (current_state == MM_PLAYER_STATE_READY)
475 if (current_state != MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_UNREALIZE:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
485 if (current_state == MM_PLAYER_STATE_NULL)
490 case MMPLAYER_COMMAND_START:
492 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
494 if (pending_state == MM_PLAYER_STATE_NONE) {
495 if (current_state == MM_PLAYER_STATE_PLAYING)
497 else if (current_state != MM_PLAYER_STATE_READY &&
498 current_state != MM_PLAYER_STATE_PAUSED)
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
503 LOGD("player is going to paused state, just change the pending state as playing");
510 case MMPLAYER_COMMAND_STOP:
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
514 if (current_state == MM_PLAYER_STATE_READY)
517 /* need playing/paused state to stop */
518 if (current_state != MM_PLAYER_STATE_PLAYING &&
519 current_state != MM_PLAYER_STATE_PAUSED)
524 case MMPLAYER_COMMAND_PAUSE:
526 if (MMPLAYER_IS_LIVE_STREAMING(player))
529 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
530 goto NOT_COMPLETED_SEEK;
532 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
534 if (pending_state == MM_PLAYER_STATE_NONE) {
535 if (current_state == MM_PLAYER_STATE_PAUSED)
537 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
539 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
541 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
542 if (current_state == MM_PLAYER_STATE_PAUSED)
543 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
550 case MMPLAYER_COMMAND_RESUME:
552 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
553 goto NOT_COMPLETED_SEEK;
555 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
557 if (pending_state == MM_PLAYER_STATE_NONE) {
558 if (current_state == MM_PLAYER_STATE_PLAYING)
560 else if (current_state != MM_PLAYER_STATE_PAUSED)
562 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
564 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
565 LOGD("player is going to paused state, just change the pending state as playing");
575 player->cmd = command;
577 return MM_ERROR_NONE;
580 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
581 MMPLAYER_STATE_GET_NAME(current_state), command);
582 return MM_ERROR_PLAYER_INVALID_STATE;
585 LOGW("not completed seek");
586 return MM_ERROR_PLAYER_DOING_SEEK;
589 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
590 return MM_ERROR_PLAYER_NO_OP;
593 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
594 return MM_ERROR_PLAYER_NO_OP;
598 __mmplayer_gapless_play_thread(gpointer data)
600 mm_player_t *player = (mm_player_t *)data;
601 MMPlayerGstElement *mainbin = NULL;
603 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
605 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
606 while (!player->gapless_play_thread_exit) {
607 LOGD("gapless play thread started. waiting for signal.");
608 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
610 LOGD("reconfigure pipeline for gapless play.");
612 if (player->gapless_play_thread_exit) {
613 if (player->gapless.reconfigure) {
614 player->gapless.reconfigure = false;
615 MMPLAYER_PLAYBACK_UNLOCK(player);
617 LOGD("exiting gapless play thread");
621 mainbin = player->pipeline->mainbin;
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
626 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
627 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
629 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
631 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
637 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
639 GSource *source = NULL;
643 source = g_main_context_find_source_by_id(context, source_id);
644 if (source != NULL) {
645 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
646 g_source_destroy(source);
653 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
655 mm_player_t *player = (mm_player_t *)hplayer;
656 GstMessage *msg = NULL;
657 GQueue *queue = NULL;
660 MMPLAYER_RETURN_IF_FAIL(player);
662 /* disconnecting bus watch */
663 if (player->bus_watcher)
664 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
665 player->bus_watcher = 0;
667 /* destroy the gst bus msg thread */
668 if (player->bus_msg_thread) {
669 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
670 player->bus_msg_thread_exit = TRUE;
671 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
672 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
674 LOGD("gst bus msg thread exit.");
675 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
676 player->bus_msg_thread = NULL;
678 g_mutex_clear(&player->bus_msg_thread_mutex);
679 g_cond_clear(&player->bus_msg_thread_cond);
682 g_mutex_lock(&player->bus_msg_q_lock);
683 queue = player->bus_msg_q;
684 while (!g_queue_is_empty(queue)) {
685 msg = (GstMessage *)g_queue_pop_head(queue);
690 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
691 gst_message_unref(msg);
693 g_mutex_unlock(&player->bus_msg_q_lock);
699 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
701 GstElement *parent = NULL;
703 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
705 /* if we have no fakesink. this meas we are using decodebin which doesn'
706 t need to add extra fakesink */
707 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
710 MMPLAYER_FSINK_LOCK(player);
715 /* get parent of fakesink */
716 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
718 LOGD("fakesink already removed");
722 gst_element_set_locked_state(fakesink->gst, TRUE);
724 /* setting the state to NULL never returns async
725 * so no need to wait for completion of state transiton
727 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
728 LOGE("fakesink state change failure!");
729 /* FIXIT : should I return here? or try to proceed to next? */
732 /* remove fakesink from it's parent */
733 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
734 LOGE("failed to remove fakesink");
736 gst_object_unref(parent);
741 gst_object_unref(parent);
743 LOGD("state-holder removed");
745 gst_element_set_locked_state(fakesink->gst, FALSE);
747 MMPLAYER_FSINK_UNLOCK(player);
752 gst_element_set_locked_state(fakesink->gst, FALSE);
754 MMPLAYER_FSINK_UNLOCK(player);
758 static GstPadProbeReturn
759 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
761 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
762 return GST_PAD_PROBE_OK;
766 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
768 gint64 stop_running_time = 0;
769 gint64 position_running_time = 0;
773 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
774 if ((player->gapless.update_segment[idx] == TRUE) ||
775 !(player->selector[idx].event_probe_id)) {
776 /* LOGW("[%d] skip", idx); */
780 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
782 gst_segment_to_running_time(&player->gapless.segment[idx],
783 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
784 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
786 gst_segment_to_running_time(&player->gapless.segment[idx],
787 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
789 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
791 gst_segment_to_running_time(&player->gapless.segment[idx],
792 GST_FORMAT_TIME, player->duration);
795 position_running_time =
796 gst_segment_to_running_time(&player->gapless.segment[idx],
797 GST_FORMAT_TIME, player->gapless.segment[idx].position);
799 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
800 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
802 GST_TIME_ARGS(stop_running_time),
803 GST_TIME_ARGS(position_running_time),
804 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
805 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
807 position_running_time = MAX(position_running_time, stop_running_time);
808 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
809 GST_FORMAT_TIME, player->gapless.segment[idx].start);
810 position_running_time = MAX(0, position_running_time);
811 position = MAX(position, position_running_time);
815 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
816 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
817 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
819 player->gapless.start_time[stream_type] += position;
825 static GstPadProbeReturn
826 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
828 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
829 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
830 mm_player_t *player = (mm_player_t *)data;
831 GstCaps *caps = NULL;
832 GstStructure *str = NULL;
833 const gchar *name = NULL;
834 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
835 gboolean caps_ret = TRUE;
837 if (GST_EVENT_IS_DOWNSTREAM(event) &&
838 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
839 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
840 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
841 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
843 } else if (GST_EVENT_IS_UPSTREAM(event) &&
844 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
848 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
852 if (strstr(name, "audio")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
854 } else if (strstr(name, "video")) {
855 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
857 /* text track is not supportable */
858 LOGE("invalid name %s", name);
862 switch (GST_EVENT_TYPE(event)) {
865 /* in case of gapless, drop eos event not to send it to sink */
866 if (player->gapless.reconfigure && !player->msg_posted) {
867 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
868 ret = GST_PAD_PROBE_DROP;
872 case GST_EVENT_STREAM_START:
874 __mmplayer_gst_selector_update_start_time(player, stream_type);
877 case GST_EVENT_FLUSH_STOP:
879 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
880 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
881 player->gapless.start_time[stream_type] = 0;
884 case GST_EVENT_SEGMENT:
889 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
890 gst_event_copy_segment(event, &segment);
892 if (segment.format != GST_FORMAT_TIME)
895 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
896 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
897 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
898 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
899 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
900 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
902 /* keep the all the segment ev to cover the seeking */
903 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
904 player->gapless.update_segment[stream_type] = TRUE;
906 if (!player->gapless.running)
909 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
911 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
913 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
914 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
915 gst_event_unref(event);
916 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
922 gdouble proportion = 0.0;
923 GstClockTimeDiff diff = 0;
924 GstClockTime timestamp = 0;
925 gint64 running_time_diff = -1;
927 GstEvent *tmpev = NULL;
929 running_time_diff = player->gapless.segment[stream_type].base;
931 if (running_time_diff <= 0) /* don't need to adjust */
934 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
935 gst_event_unref(event);
937 if (timestamp < running_time_diff) {
938 LOGW("QOS event from previous group");
939 ret = GST_PAD_PROBE_DROP;
943 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
944 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
945 stream_type, GST_TIME_ARGS(timestamp),
946 GST_TIME_ARGS(running_time_diff),
947 GST_TIME_ARGS(timestamp - running_time_diff));
949 timestamp -= running_time_diff;
951 /* That case is invalid for QoS events */
952 if (diff < 0 && -diff > timestamp) {
953 LOGW("QOS event from previous group");
954 ret = GST_PAD_PROBE_DROP;
958 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
959 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
969 gst_caps_unref(caps);
973 /* create fakesink for audio or video path witout audiobin or videobin */
975 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
977 GstElement *pipeline = NULL;
978 GstElement *fakesink = NULL;
979 GstPad *sinkpad = NULL;
982 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
984 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
987 fakesink = gst_element_factory_make("fakesink", NULL);
988 if (fakesink == NULL) {
989 LOGE("failed to create fakesink");
993 /* store it as it's sink element */
994 __mmplayer_add_sink(player, fakesink);
996 gst_bin_add(GST_BIN(pipeline), fakesink);
999 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1001 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1003 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1004 LOGE("failed to link fakesink");
1005 gst_object_unref(GST_OBJECT(fakesink));
1009 if (strstr(name, "video")) {
1010 if (player->v_stream_caps) {
1011 gst_caps_unref(player->v_stream_caps);
1012 player->v_stream_caps = NULL;
1014 if (player->ini.set_dump_element_flag)
1015 __mmplayer_add_dump_buffer_probe(player, fakesink);
1018 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1019 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1023 gst_object_unref(GST_OBJECT(sinkpad));
1030 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1032 GstElement *pipeline = NULL;
1033 GstElement *selector = NULL;
1034 GstPad *srcpad = NULL;
1037 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1039 selector = gst_element_factory_make("input-selector", NULL);
1041 LOGE("failed to create input-selector");
1044 g_object_set(selector, "sync-streams", TRUE, NULL);
1046 player->pipeline->mainbin[elem_idx].id = elem_idx;
1047 player->pipeline->mainbin[elem_idx].gst = selector;
1049 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1051 srcpad = gst_element_get_static_pad(selector, "src");
1053 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1054 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1055 __mmplayer_gst_selector_blocked, NULL, NULL);
1056 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1057 __mmplayer_gst_selector_event_probe, player, NULL);
1059 gst_element_set_state(selector, GST_STATE_PAUSED);
1061 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1062 gst_bin_add(GST_BIN(pipeline), selector);
1064 gst_object_unref(GST_OBJECT(srcpad));
1071 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1073 mm_player_t *player = (mm_player_t *)data;
1074 GstElement *selector = NULL;
1075 GstCaps *caps = NULL;
1076 GstStructure *str = NULL;
1077 const gchar *name = NULL;
1078 GstPad *sinkpad = NULL;
1079 gboolean first_track = FALSE;
1080 gboolean caps_ret = TRUE;
1082 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1083 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1086 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1087 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1089 LOGD("pad-added signal handling");
1091 /* get mimetype from caps */
1092 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1096 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1097 /* LOGD("detected mimetype : %s", name); */
1099 if (strstr(name, "video")) {
1101 gchar *caps_str = NULL;
1103 caps_str = gst_caps_to_string(caps);
1104 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1105 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1106 player->set_mode.video_zc = true;
1108 MMPLAYER_FREEIF(caps_str);
1110 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1111 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1113 LOGD("surface type : %d", stype);
1115 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1116 __mmplayer_gst_create_sinkbin(elem, pad, player);
1120 /* in case of exporting video frame, it requires the 360 video filter.
1121 * it will be handled in _no_more_pads(). */
1122 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1123 __mmplayer_gst_make_fakesink(player, pad, name);
1127 LOGD("video selector is required");
1128 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1129 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1130 } else if (strstr(name, "audio")) {
1131 gint samplerate = 0;
1134 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1135 if (player->build_audio_offload)
1136 player->no_more_pad = TRUE; /* remove state holder */
1137 __mmplayer_gst_create_sinkbin(elem, pad, player);
1141 gst_structure_get_int(str, "rate", &samplerate);
1142 gst_structure_get_int(str, "channels", &channels);
1144 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1145 __mmplayer_gst_make_fakesink(player, pad, name);
1149 LOGD("audio selector is required");
1150 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1151 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1153 } else if (strstr(name, "text")) {
1154 LOGD("text selector is required");
1155 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1156 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1158 LOGE("invalid caps info");
1162 /* check selector and create it */
1163 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1164 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1169 LOGD("input-selector is already created.");
1173 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1175 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1177 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1178 LOGE("failed to link selector");
1179 gst_object_unref(GST_OBJECT(selector));
1184 LOGD("this track will be activated");
1185 g_object_set(selector, "active-pad", sinkpad, NULL);
1188 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1194 gst_caps_unref(caps);
1197 gst_object_unref(GST_OBJECT(sinkpad));
1205 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1207 GstPad *srcpad = NULL;
1210 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1212 LOGD("type %d", type);
1215 LOGD("there is no %d track", type);
1219 srcpad = gst_element_get_static_pad(selector, "src");
1221 LOGE("failed to get srcpad from selector");
1225 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1227 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1229 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1230 if (player->selector[type].block_id) {
1231 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1232 player->selector[type].block_id = 0;
1236 gst_object_unref(GST_OBJECT(srcpad));
1245 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1247 MMHandleType attrs = 0;
1248 gint active_index = 0;
1251 MMPLAYER_RETURN_IF_FAIL(player);
1253 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1255 /* change track to active pad */
1256 active_index = player->selector[type].active_pad_index;
1257 if ((active_index != DEFAULT_TRACK) &&
1258 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1259 LOGW("failed to change %d type track to %d", type, active_index);
1260 player->selector[type].active_pad_index = DEFAULT_TRACK;
1264 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1265 attrs = MMPLAYER_GET_ATTRS(player);
1267 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1268 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1270 if (mm_attrs_commit_all(attrs))
1271 LOGW("failed to commit attrs.");
1273 LOGW("cannot get content attribute");
1282 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1285 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1287 if (!audio_selector) {
1288 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1290 /* in case the source is changed, output can be changed. */
1291 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1292 LOGD("remove previous audiobin if it exist");
1294 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1295 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1297 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1298 MMPLAYER_FREEIF(player->pipeline->audiobin);
1301 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1302 __mmplayer_pipeline_complete(NULL, player);
1307 /* apply the audio track information */
1308 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1310 /* create audio sink path */
1311 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1312 LOGE("failed to create audio sink path");
1321 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1324 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1326 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1327 LOGD("text path is not supproted");
1331 /* apply the text track information */
1332 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1334 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1335 player->has_closed_caption = TRUE;
1337 /* create text decode path */
1338 player->no_more_pad = TRUE;
1340 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1341 LOGE("failed to create text sink path");
1350 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1352 gint64 dur_bytes = 0L;
1355 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1356 player->pipeline->mainbin && player->streamer, FALSE);
1358 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1359 LOGE("fail to get duration.");
1361 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1362 * use file information was already set on Q2 when it was created. */
1363 __mm_player_streaming_set_queue2(player->streamer,
1364 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1365 TRUE, /* use_buffering */
1366 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1367 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1374 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1376 mm_player_t *player = NULL;
1377 GstElement *video_selector = NULL;
1378 GstElement *audio_selector = NULL;
1379 GstElement *text_selector = NULL;
1382 player = (mm_player_t *)data;
1384 LOGD("no-more-pad signal handling");
1386 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1387 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1388 LOGW("player is shutting down");
1392 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1393 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1394 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1395 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1396 LOGE("failed to set queue2 buffering");
1401 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1402 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1403 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1405 if (!video_selector && !audio_selector && !text_selector) {
1406 LOGW("there is no selector");
1407 player->no_more_pad = TRUE;
1411 /* create video path followed by video-select */
1412 if (video_selector && !audio_selector && !text_selector)
1413 player->no_more_pad = TRUE;
1415 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1418 /* create audio path followed by audio-select */
1419 if (audio_selector && !text_selector)
1420 player->no_more_pad = TRUE;
1422 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1425 /* create text path followed by text-select */
1426 __mmplayer_create_text_sink_path(player, text_selector);
1429 if (player->gapless.reconfigure) {
1430 player->gapless.reconfigure = FALSE;
1431 MMPLAYER_PLAYBACK_UNLOCK(player);
1438 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1440 gboolean ret = FALSE;
1441 GstElement *pipeline = NULL;
1442 GstPad *sinkpad = NULL;
1445 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1446 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1448 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1450 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1452 LOGE("failed to get pad from sinkbin");
1458 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1459 LOGE("failed to link sinkbin for reusing");
1460 goto EXIT; /* exit either pass or fail */
1464 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1465 LOGE("failed to set state(READY) to sinkbin");
1470 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1471 LOGE("failed to add sinkbin to pipeline");
1476 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1477 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1482 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1483 LOGE("failed to set state(PAUSED) to sinkbin");
1492 gst_object_unref(GST_OBJECT(sinkpad));
1500 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1502 mm_player_t *player = NULL;
1503 GstCaps *caps = NULL;
1504 gchar *caps_str = NULL;
1505 GstStructure *str = NULL;
1506 const gchar *name = NULL;
1507 GstElement *sinkbin = NULL;
1508 gboolean reusing = FALSE;
1509 gboolean caps_ret = TRUE;
1510 gchar *sink_pad_name = "sink";
1513 player = (mm_player_t *)data;
1516 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1517 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1519 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1523 caps_str = gst_caps_to_string(caps);
1525 /* LOGD("detected mimetype : %s", name); */
1526 if (strstr(name, "audio")) {
1527 if (player->pipeline->audiobin == NULL) {
1528 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1529 LOGE("failed to create audiobin. continuing without audio");
1533 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1534 LOGD("creating audiobin success");
1537 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1538 LOGD("reusing audiobin");
1539 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1541 } else if (strstr(name, "video")) {
1542 /* 1. zero copy is updated at _decode_pad_added()
1543 * 2. NULL surface type is handled in _decode_pad_added() */
1544 LOGD("zero copy %d", player->set_mode.video_zc);
1545 if (player->pipeline->videobin == NULL) {
1546 int surface_type = 0;
1547 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1548 LOGD("display_surface_type (%d)", surface_type);
1550 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1551 LOGD("mark video overlay for acquire");
1552 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1553 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1554 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1555 &player->video_overlay_resource)
1556 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1557 LOGE("could not mark video_overlay resource for acquire");
1562 player->interrupted_by_resource = FALSE;
1564 if (mm_resource_manager_commit(player->resource_manager) !=
1565 MM_RESOURCE_MANAGER_ERROR_NONE) {
1566 LOGE("could not acquire resources for video playing");
1570 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1571 LOGE("failed to create videobin. continuing without video");
1575 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1576 LOGD("creating videosink bin success");
1579 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1580 LOGD("re-using videobin");
1581 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1583 } else if (strstr(name, "text")) {
1584 if (player->pipeline->textbin == NULL) {
1585 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1586 LOGE("failed to create text sink bin. continuing without text");
1590 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1591 player->textsink_linked = 1;
1592 LOGD("creating textsink bin success");
1594 if (!player->textsink_linked) {
1595 LOGD("re-using textbin");
1597 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1598 player->textsink_linked = 1;
1600 /* linked textbin exist which means that the external subtitle path exist already */
1601 LOGW("ignoring internal subtutle since external subtitle is available");
1604 sink_pad_name = "text_sink";
1606 LOGW("unknown mime type %s, ignoring it", name);
1610 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1613 LOGD("[handle: %p] success to create and link sink bin", player);
1615 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1616 * streaming task. if the task blocked, then buffer will not flow to the next element
1617 *(autoplugging element). so this is special hack for streaming. please try to remove it
1619 /* dec stream count. we can remove fakesink if it's zero */
1620 if (player->num_dynamic_pad)
1621 player->num_dynamic_pad--;
1623 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1625 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1626 __mmplayer_pipeline_complete(NULL, player);
1630 MMPLAYER_FREEIF(caps_str);
1633 gst_caps_unref(caps);
1639 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1641 int required_angle = 0; /* Angle required for straight view */
1642 int rotation_angle = 0;
1644 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1645 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1647 /* Counter clockwise */
1648 switch (orientation) {
1653 required_angle = 270;
1656 required_angle = 180;
1659 required_angle = 90;
1663 rotation_angle = display_angle + required_angle;
1664 if (rotation_angle >= 360)
1665 rotation_angle -= 360;
1667 /* chech if supported or not */
1668 if (rotation_angle % 90) {
1669 LOGD("not supported rotation angle = %d", rotation_angle);
1673 switch (rotation_angle) {
1675 *value = MM_DISPLAY_ROTATION_NONE;
1678 *value = MM_DISPLAY_ROTATION_90;
1681 *value = MM_DISPLAY_ROTATION_180;
1684 *value = MM_DISPLAY_ROTATION_270;
1688 LOGD("setting rotation property value : %d", *value);
1694 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1696 /* check video sinkbin is created */
1697 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1699 player->pipeline->videobin &&
1700 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1701 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1702 MM_ERROR_PLAYER_NOT_INITIALIZED);
1704 return MM_ERROR_NONE;
1708 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1710 int display_rotation = 0;
1711 gchar *org_orient = NULL;
1712 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1715 LOGE("cannot get content attribute");
1716 return MM_ERROR_PLAYER_INTERNAL;
1719 if (display_angle) {
1720 /* update user roation */
1721 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1723 /* Counter clockwise */
1724 switch (display_rotation) {
1725 case MM_DISPLAY_ROTATION_NONE:
1728 case MM_DISPLAY_ROTATION_90:
1729 *display_angle = 90;
1731 case MM_DISPLAY_ROTATION_180:
1732 *display_angle = 180;
1734 case MM_DISPLAY_ROTATION_270:
1735 *display_angle = 270;
1738 LOGW("wrong angle type : %d", display_rotation);
1741 LOGD("check user angle: %d", *display_angle);
1745 /* Counter clockwise */
1746 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1749 if (!strcmp(org_orient, "rotate-90"))
1751 else if (!strcmp(org_orient, "rotate-180"))
1753 else if (!strcmp(org_orient, "rotate-270"))
1756 LOGD("original rotation is %s", org_orient);
1758 LOGD("content_video_orientation get fail");
1761 LOGD("check orientation: %d", *orientation);
1764 return MM_ERROR_NONE;
1768 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1770 int rotation_value = 0;
1771 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1772 int display_angle = 0;
1775 /* check video sinkbin is created */
1776 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1779 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1781 /* get rotation value to set */
1782 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1783 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1784 LOGD("set video param : rotate %d", rotation_value);
1788 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1790 MMHandleType attrs = 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_visible", &visible);
1802 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1803 LOGD("set video param : visible %d", visible);
1807 __mmplayer_video_param_set_display_method(mm_player_t *player)
1809 MMHandleType attrs = 0;
1810 int display_method = 0;
1813 /* check video sinkbin is created */
1814 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1817 attrs = MMPLAYER_GET_ATTRS(player);
1818 MMPLAYER_RETURN_IF_FAIL(attrs);
1820 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1821 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1822 LOGD("set video param : method %d", display_method);
1826 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1828 MMHandleType attrs = 0;
1829 void *handle = NULL;
1832 /* check video sinkbin is created */
1833 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1834 LOGW("There is no video sink");
1838 attrs = MMPLAYER_GET_ATTRS(player);
1839 MMPLAYER_RETURN_IF_FAIL(attrs);
1840 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1842 gst_video_overlay_set_video_roi_area(
1843 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1844 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1845 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1846 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1851 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1853 MMHandleType attrs = 0;
1854 void *handle = NULL;
1858 int win_roi_width = 0;
1859 int win_roi_height = 0;
1862 /* check video sinkbin is created */
1863 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1864 LOGW("There is no video sink");
1868 attrs = MMPLAYER_GET_ATTRS(player);
1869 MMPLAYER_RETURN_IF_FAIL(attrs);
1871 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1874 /* It should be set after setting window */
1875 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1876 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1877 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1878 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1880 /* After setting window handle, set display roi area */
1881 gst_video_overlay_set_display_roi_area(
1882 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1883 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1884 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1885 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1890 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1892 MMHandleType attrs = 0;
1893 void *handle = NULL;
1895 /* check video sinkbin is created */
1896 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1899 attrs = MMPLAYER_GET_ATTRS(player);
1900 MMPLAYER_RETURN_IF_FAIL(attrs);
1902 /* common case if using overlay surface */
1903 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1906 /* default is using wl_surface_id */
1907 unsigned int wl_surface_id = 0;
1908 wl_surface_id = *(int *)handle;
1909 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1910 gst_video_overlay_set_wl_window_wl_surface_id(
1911 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1914 /* FIXIT : is it error case? */
1915 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1920 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1922 gboolean update_all_param = FALSE;
1925 /* check video sinkbin is created */
1926 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1927 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1929 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1930 LOGE("can not find tizenwlsink");
1931 return MM_ERROR_PLAYER_INTERNAL;
1934 LOGD("param_name : %s", param_name);
1935 if (!g_strcmp0(param_name, "update_all_param"))
1936 update_all_param = TRUE;
1938 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1939 __mmplayer_video_param_set_display_overlay(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1941 __mmplayer_video_param_set_display_method(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1943 __mmplayer_video_param_set_display_visible(player);
1944 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1945 __mmplayer_video_param_set_display_rotation(player);
1946 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1947 __mmplayer_video_param_set_roi_area(player);
1948 if (update_all_param)
1949 __mmplayer_video_param_set_video_roi_area(player);
1951 return MM_ERROR_NONE;
1955 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1957 MMHandleType attrs = 0;
1958 int surface_type = 0;
1959 int ret = MM_ERROR_NONE;
1963 /* check video sinkbin is created */
1964 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1965 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1967 attrs = MMPLAYER_GET_ATTRS(player);
1969 LOGE("cannot get content attribute");
1970 return MM_ERROR_PLAYER_INTERNAL;
1972 LOGD("param_name : %s", param_name);
1974 /* update display surface */
1975 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1976 LOGD("check display surface type attribute: %d", surface_type);
1978 /* configuring display */
1979 switch (surface_type) {
1980 case MM_DISPLAY_SURFACE_OVERLAY:
1982 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1983 if (ret != MM_ERROR_NONE)
1991 return MM_ERROR_NONE;
1995 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1997 gboolean disable_overlay = FALSE;
1998 mm_player_t *player = (mm_player_t *)hplayer;
1999 int ret = MM_ERROR_NONE;
2002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2003 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2004 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2005 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2007 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2008 LOGW("Display control is not supported");
2009 return MM_ERROR_PLAYER_INTERNAL;
2012 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2014 if (audio_only == (bool)disable_overlay) {
2015 LOGE("It's the same with current setting: (%d)", audio_only);
2016 return MM_ERROR_NONE;
2020 LOGE("disable overlay");
2021 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2023 /* release overlay resource */
2024 if (player->video_overlay_resource != NULL) {
2025 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2026 player->video_overlay_resource);
2027 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2028 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2031 player->video_overlay_resource = NULL;
2034 ret = mm_resource_manager_commit(player->resource_manager);
2035 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2036 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2040 /* mark video overlay for acquire */
2041 if (player->video_overlay_resource == NULL) {
2042 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2043 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2044 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2045 &player->video_overlay_resource);
2046 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2047 LOGE("could not prepare for video_overlay resource");
2052 player->interrupted_by_resource = FALSE;
2053 /* acquire resources for video overlay */
2054 ret = mm_resource_manager_commit(player->resource_manager);
2055 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2056 LOGE("could not acquire resources for video playing");
2060 LOGD("enable overlay");
2061 __mmplayer_video_param_set_display_overlay(player);
2062 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2067 return MM_ERROR_NONE;
2071 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2073 mm_player_t *player = (mm_player_t *)hplayer;
2074 gboolean disable_overlay = FALSE;
2078 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2079 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2080 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2081 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2082 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2084 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2085 LOGW("Display control is not supported");
2086 return MM_ERROR_PLAYER_INTERNAL;
2089 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2091 *paudio_only = (bool)disable_overlay;
2093 LOGD("audio_only : %d", *paudio_only);
2097 return MM_ERROR_NONE;
2101 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2103 GList *bucket = element_bucket;
2104 MMPlayerGstElement *element = NULL;
2105 MMPlayerGstElement *prv_element = NULL;
2106 gint successful_link_count = 0;
2110 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2112 prv_element = (MMPlayerGstElement *)bucket->data;
2113 bucket = bucket->next;
2115 for (; bucket; bucket = bucket->next) {
2116 element = (MMPlayerGstElement *)bucket->data;
2118 if (element && element->gst) {
2119 if (prv_element && prv_element->gst) {
2120 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2121 LOGD("linking [%s] to [%s] success",
2122 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2123 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2124 successful_link_count++;
2126 LOGD("linking [%s] to [%s] failed",
2127 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2128 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2134 prv_element = element;
2139 return successful_link_count;
2143 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2145 GList *bucket = element_bucket;
2146 MMPlayerGstElement *element = NULL;
2147 int successful_add_count = 0;
2151 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2152 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2154 for (; bucket; bucket = bucket->next) {
2155 element = (MMPlayerGstElement *)bucket->data;
2157 if (element && element->gst) {
2158 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2159 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2160 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2161 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2164 successful_add_count++;
2170 return successful_add_count;
2174 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2176 mm_player_t *player = (mm_player_t *)data;
2177 GstCaps *caps = NULL;
2178 GstStructure *str = NULL;
2180 gboolean caps_ret = TRUE;
2184 MMPLAYER_RETURN_IF_FAIL(pad);
2185 MMPLAYER_RETURN_IF_FAIL(unused);
2186 MMPLAYER_RETURN_IF_FAIL(data);
2188 caps = gst_pad_get_current_caps(pad);
2192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2196 LOGD("name = %s", name);
2198 if (strstr(name, "audio")) {
2199 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2201 if (player->audio_stream_changed_cb) {
2202 LOGE("call the audio stream changed cb");
2203 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2205 } else if (strstr(name, "video")) {
2206 if ((name = gst_structure_get_string(str, "format")))
2207 player->set_mode.video_zc = name[0] == 'S';
2209 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2211 if (player->video_stream_changed_cb) {
2212 LOGE("call the video stream changed cb");
2213 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2216 LOGW("invalid caps info");
2221 gst_caps_unref(caps);
2229 * This function is to create audio pipeline for playing.
2231 * @param player [in] handle of player
2233 * @return This function returns zero on success.
2235 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2237 /* macro for code readability. just for sinkbin-creation functions */
2238 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2240 x_bin[x_id].id = x_id;\
2241 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2242 if (!x_bin[x_id].gst) {\
2243 LOGE("failed to create %s", x_factory);\
2246 if (x_player->ini.set_dump_element_flag)\
2247 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2250 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2254 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2259 MMPLAYER_RETURN_IF_FAIL(player);
2261 if (player->audio_stream_buff_list) {
2262 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2263 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2266 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2267 __mmplayer_audio_stream_send_data(player, tmp);
2269 MMPLAYER_FREEIF(tmp->pcm_data);
2270 MMPLAYER_FREEIF(tmp);
2273 g_list_free(player->audio_stream_buff_list);
2274 player->audio_stream_buff_list = NULL;
2281 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2283 MMPlayerAudioStreamDataType audio_stream = { 0, };
2286 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2288 audio_stream.bitrate = a_buffer->bitrate;
2289 audio_stream.channel = a_buffer->channel;
2290 audio_stream.depth = a_buffer->depth;
2291 audio_stream.is_little_endian = a_buffer->is_little_endian;
2292 audio_stream.channel_mask = a_buffer->channel_mask;
2293 audio_stream.data_size = a_buffer->data_size;
2294 audio_stream.data = a_buffer->pcm_data;
2296 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2297 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2303 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2305 mm_player_t *player = (mm_player_t *)data;
2309 gint endianness = 0;
2310 guint64 channel_mask = 0;
2311 void *a_data = NULL;
2313 mm_player_audio_stream_buff_t *a_buffer = NULL;
2314 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2318 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2320 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2321 a_data = mapinfo.data;
2322 a_size = mapinfo.size;
2324 GstCaps *caps = gst_pad_get_current_caps(pad);
2325 GstStructure *structure = gst_caps_get_structure(caps, 0);
2327 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2328 gst_structure_get_int(structure, "rate", &rate);
2329 gst_structure_get_int(structure, "channels", &channel);
2330 gst_structure_get_int(structure, "depth", &depth);
2331 gst_structure_get_int(structure, "endianness", &endianness);
2332 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2333 gst_caps_unref(GST_CAPS(caps));
2335 /* In case of the sync is false, use buffer list. *
2336 * The num of buffer list depends on the num of audio channels */
2337 if (player->audio_stream_buff_list) {
2338 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2339 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2341 if (channel_mask == tmp->channel_mask) {
2342 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2343 if (tmp->data_size + a_size < tmp->buff_size) {
2344 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2345 tmp->data_size += a_size;
2347 /* send data to client */
2348 __mmplayer_audio_stream_send_data(player, tmp);
2350 if (a_size > tmp->buff_size) {
2351 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2352 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2353 if (tmp->pcm_data == NULL) {
2354 LOGE("failed to realloc data.");
2357 tmp->buff_size = a_size;
2359 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2360 memcpy(tmp->pcm_data, a_data, a_size);
2361 tmp->data_size = a_size;
2366 LOGE("data is empty in list.");
2372 /* create new audio stream data */
2373 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2374 if (a_buffer == NULL) {
2375 LOGE("failed to alloc data.");
2378 a_buffer->bitrate = rate;
2379 a_buffer->channel = channel;
2380 a_buffer->depth = depth;
2381 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2382 a_buffer->channel_mask = channel_mask;
2383 a_buffer->data_size = a_size;
2385 if (!player->audio_stream_sink_sync) {
2386 /* If sync is FALSE, use buffer list to reduce the IPC. */
2387 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2388 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2389 if (a_buffer->pcm_data == NULL) {
2390 LOGE("failed to alloc data.");
2391 MMPLAYER_FREEIF(a_buffer);
2394 memcpy(a_buffer->pcm_data, a_data, a_size);
2395 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2396 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2398 /* If sync is TRUE, send data directly. */
2399 a_buffer->pcm_data = a_data;
2400 __mmplayer_audio_stream_send_data(player, a_buffer);
2401 MMPLAYER_FREEIF(a_buffer);
2405 gst_buffer_unmap(buffer, &mapinfo);
2410 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2412 mm_player_t *player = (mm_player_t *)data;
2413 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2414 GstPad *sinkpad = NULL;
2415 GstElement *queue = NULL, *sink = NULL;
2418 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2420 queue = gst_element_factory_make("queue", NULL);
2421 if (queue == NULL) {
2422 LOGD("fail make queue");
2426 sink = gst_element_factory_make("fakesink", NULL);
2428 LOGD("fail make fakesink");
2432 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2434 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2435 LOGW("failed to link queue & sink");
2439 sinkpad = gst_element_get_static_pad(queue, "sink");
2441 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2442 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2446 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2448 gst_object_unref(sinkpad);
2449 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2450 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2452 gst_element_set_state(sink, GST_STATE_PAUSED);
2453 gst_element_set_state(queue, GST_STATE_PAUSED);
2455 __mmplayer_add_signal_connection(player,
2457 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2459 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2466 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2468 gst_object_unref(GST_OBJECT(queue));
2472 gst_object_unref(GST_OBJECT(sink));
2476 gst_object_unref(GST_OBJECT(sinkpad));
2484 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2486 #define MAX_PROPS_LEN 128
2487 gint latency_mode = 0;
2488 gchar *stream_type = NULL;
2489 gchar *latency = NULL;
2491 gchar stream_props[MAX_PROPS_LEN] = {0,};
2492 GstStructure *props = NULL;
2495 * It should be set after player creation through attribute.
2496 * But, it can not be changed during playing.
2499 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2501 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2502 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2505 LOGE("stream_type is null.");
2507 if (player->sound.focus_id)
2508 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2509 stream_type, stream_id, player->sound.focus_id);
2511 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2512 stream_type, stream_id);
2513 props = gst_structure_from_string(stream_props, NULL);
2514 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2515 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2516 stream_type, stream_id, player->sound.focus_id, stream_props);
2517 gst_structure_free(props);
2520 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2522 switch (latency_mode) {
2523 case AUDIO_LATENCY_MODE_LOW:
2524 latency = g_strndup("low", 3);
2526 case AUDIO_LATENCY_MODE_MID:
2527 latency = g_strndup("mid", 3);
2529 case AUDIO_LATENCY_MODE_HIGH:
2530 latency = g_strndup("high", 4);
2534 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2538 LOGD("audiosink property - latency=%s", latency);
2540 MMPLAYER_FREEIF(latency);
2546 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2548 MMPlayerGstElement *audiobin = NULL;
2551 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2553 audiobin = player->pipeline->audiobin;
2555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2556 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2559 if (player->video360_yaw_radians <= M_PI &&
2560 player->video360_yaw_radians >= -M_PI &&
2561 player->video360_pitch_radians <= M_PI_2 &&
2562 player->video360_pitch_radians >= -M_PI_2) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2565 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2566 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2567 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2568 "source-orientation-y", player->video360_metadata.init_view_heading,
2569 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2576 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2578 MMPlayerGstElement *audiobin = NULL;
2579 MMHandleType attrs = 0;
2580 GList *element_bucket = NULL;
2581 GstCaps *acaps = NULL;
2582 GstPad *sink_pad = NULL;
2583 int pitch_control = 0;
2584 double pitch_value = 1.0;
2587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2588 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2590 audiobin = player->pipeline->audiobin;
2591 attrs = MMPLAYER_GET_ATTRS(player);
2593 if (player->build_audio_offload) { /* skip all the audio filters */
2594 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2596 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2597 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2602 mm_attrs_multiple_get(player->attrs, NULL,
2603 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2604 MM_PLAYER_PITCH_VALUE, &pitch_value,
2607 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2608 if (pitch_control && (player->videodec_linked == 0)) {
2609 GstElementFactory *factory;
2611 factory = gst_element_factory_find("pitch");
2613 gst_object_unref(factory);
2616 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2619 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2620 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2622 LOGW("there is no pitch element");
2627 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2629 /* replaygain volume */
2630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2631 if (player->sound.rg_enable)
2632 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2637 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2639 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2640 gchar *dst_format = NULL;
2642 int dst_samplerate = 0;
2643 int dst_channels = 0;
2644 GstCaps *caps = NULL;
2645 char *caps_str = NULL;
2647 /* get conf. values */
2648 mm_attrs_multiple_get(player->attrs, NULL,
2649 "pcm_audioformat", &dst_format, &dst_len,
2650 "pcm_extraction_samplerate", &dst_samplerate,
2651 "pcm_extraction_channels", &dst_channels,
2654 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2657 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2658 caps = gst_caps_new_simple("audio/x-raw",
2659 "format", G_TYPE_STRING, dst_format,
2660 "rate", G_TYPE_INT, dst_samplerate,
2661 "channels", G_TYPE_INT, dst_channels,
2664 caps_str = gst_caps_to_string(caps);
2665 LOGD("new caps : %s", caps_str);
2667 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2670 gst_caps_unref(caps);
2671 MMPLAYER_FREEIF(caps_str);
2673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2677 /* raw pad handling signal, audiosink will be added after getting signal */
2678 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2679 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2683 /* normal playback */
2686 /* for logical volume control */
2687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2690 if (player->sound.mute) {
2691 LOGD("mute enabled");
2692 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2695 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2697 /* audio effect element. if audio effect is enabled */
2698 if ((strcmp(player->ini.audioeffect_element, ""))
2700 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2701 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2703 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2705 if ((!player->bypass_audio_effect)
2706 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2707 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2708 if (!_mmplayer_audio_effect_custom_apply(player))
2709 LOGI("apply audio effect(custom) setting success");
2713 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2714 && (player->set_mode.rich_audio))
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2718 /* create audio sink */
2719 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2720 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2721 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2723 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2724 if (player->is_360_feature_enabled &&
2725 player->is_content_spherical &&
2727 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2728 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2729 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2731 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2735 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2736 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2738 gst_caps_unref(acaps);
2740 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2742 player->is_openal_plugin_used = TRUE;
2744 if (player->is_360_feature_enabled && player->is_content_spherical)
2745 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2749 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2750 (player->videodec_linked && player->ini.use_system_clock)) {
2751 LOGD("system clock will be used.");
2752 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2755 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2756 __mmplayer_gst_set_pulsesink_property(player, attrs);
2757 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2758 __mmplayer_gst_set_openalsink_property(player);
2761 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2762 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2764 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2765 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2766 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2767 gst_object_unref(GST_OBJECT(sink_pad));
2769 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2773 *bucket = element_bucket;
2776 return MM_ERROR_NONE;
2779 g_list_free(element_bucket);
2783 return MM_ERROR_PLAYER_INTERNAL;
2787 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2789 MMPlayerGstElement *first_element = NULL;
2790 MMPlayerGstElement *audiobin = NULL;
2792 GstPad *ghostpad = NULL;
2793 GList *element_bucket = NULL;
2797 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2800 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2802 LOGE("failed to allocate memory for audiobin");
2803 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2807 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2808 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2809 if (!audiobin[MMPLAYER_A_BIN].gst) {
2810 LOGE("failed to create audiobin");
2815 player->pipeline->audiobin = audiobin;
2817 /* create audio filters and audiosink */
2818 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2821 /* adding created elements to bin */
2822 LOGD("adding created elements to bin");
2823 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2826 /* linking elements in the bucket by added order. */
2827 LOGD("Linking elements in the bucket by added order.");
2828 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2831 /* get first element's sinkpad for creating ghostpad */
2832 first_element = (MMPlayerGstElement *)element_bucket->data;
2833 if (!first_element) {
2834 LOGE("failed to get first elem");
2838 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2840 LOGE("failed to get pad from first element of audiobin");
2844 ghostpad = gst_ghost_pad_new("sink", pad);
2846 LOGE("failed to create ghostpad");
2850 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2851 LOGE("failed to add ghostpad to audiobin");
2855 gst_object_unref(pad);
2857 g_list_free(element_bucket);
2860 return MM_ERROR_NONE;
2863 LOGD("ERROR : releasing audiobin");
2866 gst_object_unref(GST_OBJECT(pad));
2869 gst_object_unref(GST_OBJECT(ghostpad));
2872 g_list_free(element_bucket);
2874 /* release element which are not added to bin */
2875 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2876 /* NOTE : skip bin */
2877 if (audiobin[i].gst) {
2878 GstObject *parent = NULL;
2879 parent = gst_element_get_parent(audiobin[i].gst);
2882 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2883 audiobin[i].gst = NULL;
2885 gst_object_unref(GST_OBJECT(parent));
2889 /* release audiobin with it's childs */
2890 if (audiobin[MMPLAYER_A_BIN].gst)
2891 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2893 MMPLAYER_FREEIF(audiobin);
2895 player->pipeline->audiobin = NULL;
2897 return MM_ERROR_PLAYER_INTERNAL;
2901 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2903 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2907 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2909 int ret = MM_ERROR_NONE;
2911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2912 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2914 MMPLAYER_VIDEO_BO_LOCK(player);
2916 if (player->video_bo_list) {
2917 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2918 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2919 if (tmp && tmp->bo == bo) {
2921 LOGD("release bo %p", bo);
2922 tbm_bo_unref(tmp->bo);
2923 MMPLAYER_VIDEO_BO_UNLOCK(player);
2924 MMPLAYER_VIDEO_BO_SIGNAL(player);
2929 /* hw codec is running or the list was reset for DRC. */
2930 LOGW("there is no bo list.");
2932 MMPLAYER_VIDEO_BO_UNLOCK(player);
2934 LOGW("failed to find bo %p", bo);
2939 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2944 MMPLAYER_RETURN_IF_FAIL(player);
2946 MMPLAYER_VIDEO_BO_LOCK(player);
2947 if (player->video_bo_list) {
2948 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2949 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2950 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2953 tbm_bo_unref(tmp->bo);
2957 g_list_free(player->video_bo_list);
2958 player->video_bo_list = NULL;
2960 player->video_bo_size = 0;
2961 MMPLAYER_VIDEO_BO_UNLOCK(player);
2968 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2971 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2972 gboolean ret = TRUE;
2974 /* check DRC, if it is, destroy the prev bo list to create again */
2975 if (player->video_bo_size != size) {
2976 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2977 __mmplayer_video_stream_destroy_bo_list(player);
2978 player->video_bo_size = size;
2981 MMPLAYER_VIDEO_BO_LOCK(player);
2983 if ((!player->video_bo_list) ||
2984 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2986 /* create bo list */
2988 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2990 if (player->video_bo_list) {
2991 /* if bo list did not created all, try it again. */
2992 idx = g_list_length(player->video_bo_list);
2993 LOGD("bo list exist(len: %d)", idx);
2996 for (; idx < player->ini.num_of_video_bo; idx++) {
2997 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2999 LOGE("Fail to alloc bo_info.");
3002 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3004 LOGE("Fail to tbm_bo_alloc.");
3005 MMPLAYER_FREEIF(bo_info);
3008 bo_info->used = FALSE;
3009 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3012 /* update video num buffers */
3013 player->video_num_buffers = idx;
3014 if (idx == player->ini.num_of_video_bo)
3015 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3018 MMPLAYER_VIDEO_BO_UNLOCK(player);
3022 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3026 /* get bo from list*/
3027 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3028 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3029 if (tmp && (tmp->used == FALSE)) {
3030 LOGD("found bo %p to use", tmp->bo);
3032 MMPLAYER_VIDEO_BO_UNLOCK(player);
3033 return tbm_bo_ref(tmp->bo);
3037 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3038 MMPLAYER_VIDEO_BO_UNLOCK(player);
3042 if (player->ini.video_bo_timeout <= 0) {
3043 MMPLAYER_VIDEO_BO_WAIT(player);
3045 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3046 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3053 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3055 mm_player_t *player = (mm_player_t *)data;
3057 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3059 /* send prerolled pkt */
3060 player->video_stream_prerolled = false;
3062 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3064 /* not to send prerolled pkt again */
3065 player->video_stream_prerolled = true;
3069 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3071 mm_player_t *player = (mm_player_t *)data;
3072 MMPlayerVideoStreamDataType *stream = NULL;
3073 GstMemory *mem = NULL;
3076 MMPLAYER_RETURN_IF_FAIL(player);
3077 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3079 if (player->video_stream_prerolled) {
3080 player->video_stream_prerolled = false;
3081 LOGD("skip the prerolled pkt not to send it again");
3085 /* clear stream data structure */
3086 stream = __mmplayer_create_stream_from_pad(pad);
3088 LOGE("failed to alloc stream");
3092 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3094 /* set size and timestamp */
3095 mem = gst_buffer_peek_memory(buffer, 0);
3096 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3097 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3099 /* check zero-copy */
3100 if (player->set_mode.video_zc &&
3101 player->set_mode.media_packet_video_stream &&
3102 gst_is_tizen_memory(mem)) {
3103 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3104 stream->internal_buffer = gst_buffer_ref(buffer);
3105 } else { /* sw codec */
3106 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3109 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3113 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3114 LOGE("failed to send video stream data.");
3121 LOGE("release video stream resource.");
3122 if (gst_is_tizen_memory(mem)) {
3124 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3126 tbm_bo_unref(stream->bo[i]);
3129 /* unref gst buffer */
3130 if (stream->internal_buffer)
3131 gst_buffer_unref(stream->internal_buffer);
3134 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3136 MMPLAYER_FREEIF(stream);
3141 __mmplayer_gst_set_video360_property(mm_player_t *player)
3143 MMPlayerGstElement *videobin = NULL;
3146 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3148 videobin = player->pipeline->videobin;
3150 /* Set spatial media metadata and/or user settings to the element.
3152 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3153 "projection-type", player->video360_metadata.projection_type, NULL);
3155 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3156 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3158 if (player->video360_metadata.full_pano_width_pixels &&
3159 player->video360_metadata.full_pano_height_pixels &&
3160 player->video360_metadata.cropped_area_image_width &&
3161 player->video360_metadata.cropped_area_image_height) {
3162 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3163 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3164 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3165 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3166 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3167 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3168 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3172 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3173 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3174 "horizontal-fov", player->video360_horizontal_fov,
3175 "vertical-fov", player->video360_vertical_fov, NULL);
3178 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3179 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3180 "zoom", 1.0f / player->video360_zoom, NULL);
3183 if (player->video360_yaw_radians <= M_PI &&
3184 player->video360_yaw_radians >= -M_PI &&
3185 player->video360_pitch_radians <= M_PI_2 &&
3186 player->video360_pitch_radians >= -M_PI_2) {
3187 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3189 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3190 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3191 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3192 "pose-yaw", player->video360_metadata.init_view_heading,
3193 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3196 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3197 "passthrough", !player->is_video360_enabled, NULL);
3204 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3206 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3207 GList *element_bucket = NULL;
3210 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3212 /* create video360 filter */
3213 if (player->is_360_feature_enabled && player->is_content_spherical) {
3214 LOGD("create video360 element");
3215 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3216 __mmplayer_gst_set_video360_property(player);
3220 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3221 LOGD("skip creating the videoconv and rotator");
3222 return MM_ERROR_NONE;
3225 /* in case of sw codec & overlay surface type, except 360 playback.
3226 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3227 LOGD("create video converter: %s", video_csc);
3228 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3231 *bucket = element_bucket;
3233 return MM_ERROR_NONE;
3235 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3236 g_list_free(element_bucket);
3240 return MM_ERROR_PLAYER_INTERNAL;
3244 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3246 gchar *factory_name = NULL;
3248 switch (surface_type) {
3249 case MM_DISPLAY_SURFACE_OVERLAY:
3250 if (strlen(player->ini.videosink_element_overlay) > 0)
3251 factory_name = player->ini.videosink_element_overlay;
3253 case MM_DISPLAY_SURFACE_REMOTE:
3254 case MM_DISPLAY_SURFACE_NULL:
3255 if (strlen(player->ini.videosink_element_fake) > 0)
3256 factory_name = player->ini.videosink_element_fake;
3259 LOGE("unidentified surface type");
3263 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3264 return factory_name;
3268 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3270 gchar *factory_name = NULL;
3271 MMPlayerGstElement *videobin = NULL;
3276 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3278 videobin = player->pipeline->videobin;
3279 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3281 attrs = MMPLAYER_GET_ATTRS(player);
3283 LOGE("cannot get content attribute");
3284 return MM_ERROR_PLAYER_INTERNAL;
3287 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3288 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3289 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3291 /* support shard memory with S/W codec on HawkP */
3292 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3293 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3294 "use-tbm", use_tbm, NULL);
3298 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3299 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3302 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3304 LOGD("disable last-sample");
3305 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3308 if (player->set_mode.media_packet_video_stream) {
3310 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3311 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3312 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3314 __mmplayer_add_signal_connection(player,
3315 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3316 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3318 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3321 __mmplayer_add_signal_connection(player,
3322 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3323 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3325 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3329 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3330 return MM_ERROR_PLAYER_INTERNAL;
3332 if (videobin[MMPLAYER_V_SINK].gst) {
3333 GstPad *sink_pad = NULL;
3334 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3336 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3337 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3338 gst_object_unref(GST_OBJECT(sink_pad));
3340 LOGE("failed to get sink pad from videosink");
3344 return MM_ERROR_NONE;
3349 * - video overlay surface(arm/x86) : tizenwlsink
3352 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3355 GList *element_bucket = NULL;
3356 MMPlayerGstElement *first_element = NULL;
3357 MMPlayerGstElement *videobin = NULL;
3358 gchar *videosink_factory_name = NULL;
3361 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3364 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3366 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3368 player->pipeline->videobin = videobin;
3371 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3372 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3373 if (!videobin[MMPLAYER_V_BIN].gst) {
3374 LOGE("failed to create videobin");
3378 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3381 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3382 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3384 /* additional setting for sink plug-in */
3385 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3386 LOGE("failed to set video property");
3390 /* store it as it's sink element */
3391 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3393 /* adding created elements to bin */
3394 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3395 LOGE("failed to add elements");
3399 /* Linking elements in the bucket by added order */
3400 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3401 LOGE("failed to link elements");
3405 /* get first element's sinkpad for creating ghostpad */
3406 first_element = (MMPlayerGstElement *)element_bucket->data;
3407 if (!first_element) {
3408 LOGE("failed to get first element from bucket");
3412 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3414 LOGE("failed to get pad from first element");
3418 /* create ghostpad */
3419 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3420 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3421 LOGE("failed to add ghostpad to videobin");
3424 gst_object_unref(pad);
3426 /* done. free allocated variables */
3427 g_list_free(element_bucket);
3431 return MM_ERROR_NONE;
3434 LOGE("ERROR : releasing videobin");
3435 g_list_free(element_bucket);
3438 gst_object_unref(GST_OBJECT(pad));
3440 /* release videobin with it's childs */
3441 if (videobin[MMPLAYER_V_BIN].gst)
3442 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3444 MMPLAYER_FREEIF(videobin);
3445 player->pipeline->videobin = NULL;
3447 return MM_ERROR_PLAYER_INTERNAL;
3451 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3453 GList *element_bucket = NULL;
3454 MMPlayerGstElement *textbin = player->pipeline->textbin;
3456 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3457 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3458 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3459 "signal-handoffs", FALSE,
3462 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3463 __mmplayer_add_signal_connection(player,
3464 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3465 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3467 G_CALLBACK(__mmplayer_update_subtitle),
3470 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3471 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3473 if (!player->play_subtitle) {
3474 LOGD("add textbin sink as sink element of whole pipeline.");
3475 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3478 /* adding created elements to bin */
3479 LOGD("adding created elements to bin");
3480 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3481 LOGE("failed to add elements");
3485 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3486 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3487 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3489 /* linking elements in the bucket by added order. */
3490 LOGD("Linking elements in the bucket by added order.");
3491 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3492 LOGE("failed to link elements");
3496 /* done. free allocated variables */
3497 g_list_free(element_bucket);
3499 if (textbin[MMPLAYER_T_QUEUE].gst) {
3501 GstPad *ghostpad = NULL;
3503 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3505 LOGE("failed to get sink pad of text queue");
3509 ghostpad = gst_ghost_pad_new("text_sink", pad);
3510 gst_object_unref(pad);
3513 LOGE("failed to create ghostpad of textbin");
3517 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3518 LOGE("failed to add ghostpad to textbin");
3519 gst_object_unref(ghostpad);
3524 return MM_ERROR_NONE;
3527 g_list_free(element_bucket);
3529 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3530 LOGE("remove textbin sink from sink list");
3531 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3534 /* release element at __mmplayer_gst_create_text_sink_bin */
3535 return MM_ERROR_PLAYER_INTERNAL;
3539 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3541 MMPlayerGstElement *textbin = NULL;
3542 GList *element_bucket = NULL;
3543 int surface_type = 0;
3548 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3551 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3553 LOGE("failed to allocate memory for textbin");
3554 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3558 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3559 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3560 if (!textbin[MMPLAYER_T_BIN].gst) {
3561 LOGE("failed to create textbin");
3566 player->pipeline->textbin = textbin;
3569 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3570 LOGD("surface type for subtitle : %d", surface_type);
3571 switch (surface_type) {
3572 case MM_DISPLAY_SURFACE_OVERLAY:
3573 case MM_DISPLAY_SURFACE_NULL:
3574 case MM_DISPLAY_SURFACE_REMOTE:
3575 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3576 LOGE("failed to make plain text elements");
3587 return MM_ERROR_NONE;
3591 LOGD("ERROR : releasing textbin");
3593 g_list_free(element_bucket);
3595 /* release signal */
3596 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3598 /* release element which are not added to bin */
3599 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3600 /* NOTE : skip bin */
3601 if (textbin[i].gst) {
3602 GstObject *parent = NULL;
3603 parent = gst_element_get_parent(textbin[i].gst);
3606 gst_object_unref(GST_OBJECT(textbin[i].gst));
3607 textbin[i].gst = NULL;
3609 gst_object_unref(GST_OBJECT(parent));
3614 /* release textbin with it's childs */
3615 if (textbin[MMPLAYER_T_BIN].gst)
3616 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3618 MMPLAYER_FREEIF(player->pipeline->textbin);
3619 player->pipeline->textbin = NULL;
3622 return MM_ERROR_PLAYER_INTERNAL;
3626 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3628 MMPlayerGstElement *mainbin = NULL;
3629 MMPlayerGstElement *textbin = NULL;
3630 MMHandleType attrs = 0;
3631 GstElement *subsrc = NULL;
3632 GstElement *subparse = NULL;
3633 gchar *subtitle_uri = NULL;
3634 const gchar *charset = NULL;
3640 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3642 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3644 mainbin = player->pipeline->mainbin;
3646 attrs = MMPLAYER_GET_ATTRS(player);
3648 LOGE("cannot get content attribute");
3649 return MM_ERROR_PLAYER_INTERNAL;
3652 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3653 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3654 LOGE("subtitle uri is not proper filepath.");
3655 return MM_ERROR_PLAYER_INVALID_URI;
3658 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3659 LOGE("failed to get storage info of subtitle path");
3660 return MM_ERROR_PLAYER_INVALID_URI;
3663 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3665 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3666 player->subtitle_language_list = NULL;
3667 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3669 /* create the subtitle source */
3670 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3672 LOGE("failed to create filesrc element");
3675 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3677 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3678 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3680 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3681 LOGW("failed to add queue");
3682 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3683 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3684 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3689 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3691 LOGE("failed to create subparse element");
3695 charset = util_get_charset(subtitle_uri);
3697 LOGD("detected charset is %s", charset);
3698 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3701 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3702 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3704 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3705 LOGW("failed to add subparse");
3706 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3707 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3708 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3712 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3713 LOGW("failed to link subsrc and subparse");
3717 player->play_subtitle = TRUE;
3718 player->adjust_subtitle_pos = 0;
3720 LOGD("play subtitle using subtitle file");
3722 if (player->pipeline->textbin == NULL) {
3723 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3724 LOGE("failed to create text sink bin. continuing without text");
3728 textbin = player->pipeline->textbin;
3730 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3731 LOGW("failed to add textbin");
3733 /* release signal */
3734 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3736 /* release textbin with it's childs */
3737 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3738 MMPLAYER_FREEIF(player->pipeline->textbin);
3739 player->pipeline->textbin = textbin = NULL;
3743 LOGD("link text input selector and textbin ghost pad");
3745 player->textsink_linked = 1;
3746 player->external_text_idx = 0;
3747 LOGI("textsink is linked");
3749 textbin = player->pipeline->textbin;
3750 LOGD("text bin has been created. reuse it.");
3751 player->external_text_idx = 1;
3754 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3755 LOGW("failed to link subparse and textbin");
3759 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3761 LOGE("failed to get sink pad from textsink to probe data");
3765 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3766 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3768 gst_object_unref(pad);
3771 /* create dot. for debugging */
3772 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3775 return MM_ERROR_NONE;
3778 /* release text pipeline resource */
3779 player->textsink_linked = 0;
3781 /* release signal */
3782 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3784 if (player->pipeline->textbin) {
3785 LOGE("remove textbin");
3787 /* release textbin with it's childs */
3788 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3789 MMPLAYER_FREEIF(player->pipeline->textbin);
3790 player->pipeline->textbin = NULL;
3794 /* release subtitle elem */
3795 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3796 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3798 return MM_ERROR_PLAYER_INTERNAL;
3802 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3804 mm_player_t *player = (mm_player_t *)data;
3805 MMMessageParamType msg = {0, };
3806 GstClockTime duration = 0;
3807 gpointer text = NULL;
3808 guint text_size = 0;
3809 gboolean ret = TRUE;
3810 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3814 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3815 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3817 if (player->is_subtitle_force_drop) {
3818 LOGW("subtitle is dropped forcedly.");
3822 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3823 text = mapinfo.data;
3824 text_size = mapinfo.size;
3826 if (player->set_mode.subtitle_off) {
3827 LOGD("subtitle is OFF.");
3831 if (!text || (text_size == 0)) {
3832 LOGD("There is no subtitle to be displayed.");
3836 msg.data = (void *)text;
3838 duration = GST_BUFFER_DURATION(buffer);
3840 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3841 if (player->duration > GST_BUFFER_PTS(buffer))
3842 duration = player->duration - GST_BUFFER_PTS(buffer);
3845 LOGI("subtitle duration is invalid, subtitle duration change "
3846 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3848 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3850 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3852 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3853 gst_buffer_unmap(buffer, &mapinfo);
3860 static GstPadProbeReturn
3861 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3863 mm_player_t *player = (mm_player_t *)u_data;
3864 GstClockTime cur_timestamp = 0;
3865 gint64 adjusted_timestamp = 0;
3866 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3868 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3870 if (player->set_mode.subtitle_off) {
3871 LOGD("subtitle is OFF.");
3875 if (player->adjust_subtitle_pos == 0) {
3876 LOGD("nothing to do");
3880 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3881 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3883 if (adjusted_timestamp < 0) {
3884 LOGD("adjusted_timestamp under zero");
3889 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3890 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3891 GST_TIME_ARGS(cur_timestamp),
3892 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3894 return GST_PAD_PROBE_OK;
3898 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3902 /* check player and subtitlebin are created */
3903 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3904 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3906 if (position == 0) {
3907 LOGD("nothing to do");
3909 return MM_ERROR_NONE;
3913 case MM_PLAYER_POS_FORMAT_TIME:
3915 /* check current postion */
3916 player->adjust_subtitle_pos = position;
3918 LOGD("save adjust_subtitle_pos in player") ;
3924 LOGW("invalid format.");
3926 return MM_ERROR_INVALID_ARGUMENT;
3932 return MM_ERROR_NONE;
3936 * This function is to create audio or video pipeline for playing.
3938 * @param player [in] handle of player
3940 * @return This function returns zero on success.
3945 __mmplayer_gst_create_pipeline(mm_player_t *player)
3947 int ret = MM_ERROR_NONE;
3948 MMPlayerGstElement *mainbin = NULL;
3949 MMHandleType attrs = 0;
3952 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3954 /* get profile attribute */
3955 attrs = MMPLAYER_GET_ATTRS(player);
3957 LOGE("failed to get content attribute");
3961 /* create pipeline handles */
3962 if (player->pipeline) {
3963 LOGE("pipeline should be released before create new one");
3967 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3968 if (player->pipeline == NULL)
3971 /* create mainbin */
3972 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3973 if (mainbin == NULL)
3976 /* create pipeline */
3977 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3978 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3979 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3980 LOGE("failed to create pipeline");
3985 player->pipeline->mainbin = mainbin;
3987 /* create the source and decoder elements */
3988 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3989 ret = __mmplayer_gst_build_es_pipeline(player);
3991 ret = __mmplayer_gst_build_pipeline(player);
3993 if (ret != MM_ERROR_NONE) {
3994 LOGE("failed to create some elements");
3998 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3999 if (__mmplayer_check_subtitle(player)
4000 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4001 LOGE("failed to create text pipeline");
4004 ret = __mmplayer_gst_add_bus_watch(player);
4005 if (ret != MM_ERROR_NONE) {
4006 LOGE("failed to add bus watch");
4011 return MM_ERROR_NONE;
4014 __mmplayer_gst_destroy_pipeline(player);
4015 return MM_ERROR_PLAYER_INTERNAL;
4019 __mmplayer_reset_gapless_state(mm_player_t *player)
4022 MMPLAYER_RETURN_IF_FAIL(player
4024 && player->pipeline->audiobin
4025 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4027 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4034 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4037 int ret = MM_ERROR_NONE;
4041 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4043 /* cleanup stuffs */
4044 MMPLAYER_FREEIF(player->type);
4045 player->no_more_pad = FALSE;
4046 player->num_dynamic_pad = 0;
4047 player->demux_pad_index = 0;
4049 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4050 player->subtitle_language_list = NULL;
4051 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4053 __mmplayer_reset_gapless_state(player);
4055 if (player->streamer) {
4056 __mm_player_streaming_initialize(player->streamer, FALSE);
4057 __mm_player_streaming_destroy(player->streamer);
4058 player->streamer = NULL;
4061 /* cleanup unlinked mime type */
4062 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4063 MMPLAYER_FREEIF(player->unlinked_video_mime);
4064 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4066 /* cleanup running stuffs */
4067 __mmplayer_cancel_eos_timer(player);
4069 /* cleanup gst stuffs */
4070 if (player->pipeline) {
4071 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4072 GstTagList *tag_list = player->pipeline->tag_list;
4074 /* first we need to disconnect all signal hander */
4075 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4078 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4079 MMPlayerGstElement *videobin = player->pipeline->videobin;
4080 MMPlayerGstElement *textbin = player->pipeline->textbin;
4081 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4082 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4083 gst_object_unref(bus);
4085 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4086 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4087 if (ret != MM_ERROR_NONE) {
4088 LOGE("fail to change state to NULL");
4089 return MM_ERROR_PLAYER_INTERNAL;
4092 LOGW("succeeded in changing state to NULL");
4094 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4097 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4098 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4100 /* free avsysaudiosink
4101 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4102 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4104 MMPLAYER_FREEIF(audiobin);
4105 MMPLAYER_FREEIF(videobin);
4106 MMPLAYER_FREEIF(textbin);
4107 MMPLAYER_FREEIF(mainbin);
4111 gst_tag_list_unref(tag_list);
4113 MMPLAYER_FREEIF(player->pipeline);
4115 MMPLAYER_FREEIF(player->album_art);
4117 if (player->v_stream_caps) {
4118 gst_caps_unref(player->v_stream_caps);
4119 player->v_stream_caps = NULL;
4122 if (player->a_stream_caps) {
4123 gst_caps_unref(player->a_stream_caps);
4124 player->a_stream_caps = NULL;
4127 if (player->s_stream_caps) {
4128 gst_caps_unref(player->s_stream_caps);
4129 player->s_stream_caps = NULL;
4131 __mmplayer_track_destroy(player);
4133 if (player->sink_elements)
4134 g_list_free(player->sink_elements);
4135 player->sink_elements = NULL;
4137 if (player->bufmgr) {
4138 tbm_bufmgr_deinit(player->bufmgr);
4139 player->bufmgr = NULL;
4142 LOGW("finished destroy pipeline");
4150 __mmplayer_gst_realize(mm_player_t *player)
4153 int ret = MM_ERROR_NONE;
4157 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4159 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4161 ret = __mmplayer_gst_create_pipeline(player);
4163 LOGE("failed to create pipeline");
4167 /* set pipeline state to READY */
4168 /* NOTE : state change to READY must be performed sync. */
4169 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4170 ret = __mmplayer_gst_set_state(player,
4171 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4173 if (ret != MM_ERROR_NONE) {
4174 /* return error if failed to set state */
4175 LOGE("failed to set READY state");
4179 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4181 /* create dot before error-return. for debugging */
4182 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4190 __mmplayer_gst_unrealize(mm_player_t *player)
4192 int ret = MM_ERROR_NONE;
4196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4198 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4199 MMPLAYER_PRINT_STATE(player);
4201 /* release miscellaneous information */
4202 __mmplayer_release_misc(player);
4204 /* destroy pipeline */
4205 ret = __mmplayer_gst_destroy_pipeline(player);
4206 if (ret != MM_ERROR_NONE) {
4207 LOGE("failed to destory pipeline");
4211 /* release miscellaneous information.
4212 these info needs to be released after pipeline is destroyed. */
4213 __mmplayer_release_misc_post(player);
4215 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4223 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4228 LOGW("set_message_callback is called with invalid player handle");
4229 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4232 player->msg_cb = callback;
4233 player->msg_cb_param = user_param;
4235 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4239 return MM_ERROR_NONE;
4243 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4245 int ret = MM_ERROR_NONE;
4250 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4251 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4252 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4254 memset(data, 0, sizeof(MMPlayerParseProfile));
4256 if (strstr(uri, "es_buff://")) {
4257 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4258 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4259 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4260 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4262 tmp = g_ascii_strdown(uri, strlen(uri));
4263 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4264 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4266 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4268 } else if (strstr(uri, "mms://")) {
4269 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4270 } else if ((path = strstr(uri, "mem://"))) {
4271 ret = __mmplayer_set_mem_uri(data, path, param);
4273 ret = __mmplayer_set_file_uri(data, uri);
4276 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4277 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4278 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4279 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4281 /* dump parse result */
4282 SECURE_LOGW("incoming uri : %s", uri);
4283 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4284 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4292 __mmplayer_can_do_interrupt(mm_player_t *player)
4294 if (!player || !player->pipeline || !player->attrs) {
4295 LOGW("not initialized");
4299 if (player->audio_stream_render_cb) {
4300 LOGW("not support in pcm extraction mode");
4304 /* check if seeking */
4305 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4306 MMMessageParamType msg_param;
4307 memset(&msg_param, 0, sizeof(MMMessageParamType));
4308 msg_param.code = MM_ERROR_PLAYER_SEEK;
4309 player->seek_state = MMPLAYER_SEEK_NONE;
4310 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4314 /* check other thread */
4315 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4316 LOGW("locked already, cmd state : %d", player->cmd);
4318 /* check application command */
4319 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4320 LOGW("playing.. should wait cmd lock then, will be interrupted");
4322 /* lock will be released at mrp_resource_release_cb() */
4323 MMPLAYER_CMD_LOCK(player);
4326 LOGW("nothing to do");
4329 LOGW("can interrupt immediately");
4333 FAILED: /* with CMD UNLOCKED */
4336 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4341 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4344 mm_player_t *player = NULL;
4348 if (user_data == NULL) {
4349 LOGE("- user_data is null");
4352 player = (mm_player_t *)user_data;
4354 /* do something to release resource here.
4355 * player stop and interrupt forwarding */
4356 if (!__mmplayer_can_do_interrupt(player)) {
4357 LOGW("no need to interrupt, so leave");
4359 MMMessageParamType msg = {0, };
4362 player->interrupted_by_resource = TRUE;
4364 /* get last play position */
4365 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4366 LOGW("failed to get play position.");
4368 msg.union_type = MM_MSG_UNION_TIME;
4369 msg.time.elapsed = pos;
4370 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4372 LOGD("video resource conflict so, resource will be freed by unrealizing");
4373 if (_mmplayer_unrealize((MMHandleType)player))
4374 LOGW("failed to unrealize");
4376 /* lock is called in __mmplayer_can_do_interrupt() */
4377 MMPLAYER_CMD_UNLOCK(player);
4380 if (res == player->video_overlay_resource)
4381 player->video_overlay_resource = FALSE;
4383 player->video_decoder_resource = FALSE;
4391 __mmplayer_initialize_video_roi(mm_player_t *player)
4393 player->video_roi.scale_x = 0.0;
4394 player->video_roi.scale_y = 0.0;
4395 player->video_roi.scale_width = 1.0;
4396 player->video_roi.scale_height = 1.0;
4400 _mmplayer_create_player(MMHandleType handle)
4402 int ret = MM_ERROR_PLAYER_INTERNAL;
4403 bool enabled = false;
4405 mm_player_t *player = MM_PLAYER_CAST(handle);
4409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4411 /* initialize player state */
4412 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4413 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4414 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4415 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4417 /* check current state */
4418 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4420 /* construct attributes */
4421 player->attrs = _mmplayer_construct_attribute(handle);
4423 if (!player->attrs) {
4424 LOGE("Failed to construct attributes");
4428 /* initialize gstreamer with configured parameter */
4429 if (!__mmplayer_init_gstreamer(player)) {
4430 LOGE("Initializing gstreamer failed");
4431 _mmplayer_deconstruct_attribute(handle);
4435 /* create lock. note that g_tread_init() has already called in gst_init() */
4436 g_mutex_init(&player->fsink_lock);
4438 /* create update tag lock */
4439 g_mutex_init(&player->update_tag_lock);
4441 /* create gapless play mutex */
4442 g_mutex_init(&player->gapless_play_thread_mutex);
4444 /* create gapless play cond */
4445 g_cond_init(&player->gapless_play_thread_cond);
4447 /* create gapless play thread */
4448 player->gapless_play_thread =
4449 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4450 if (!player->gapless_play_thread) {
4451 LOGE("failed to create gapless play thread");
4452 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4453 g_mutex_clear(&player->gapless_play_thread_mutex);
4454 g_cond_clear(&player->gapless_play_thread_cond);
4458 player->bus_msg_q = g_queue_new();
4459 if (!player->bus_msg_q) {
4460 LOGE("failed to create queue for bus_msg");
4461 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4465 ret = _mmplayer_initialize_video_capture(player);
4466 if (ret != MM_ERROR_NONE) {
4467 LOGE("failed to initialize video capture");
4471 /* initialize resource manager */
4472 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4473 __resource_release_cb, player, &player->resource_manager)
4474 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4475 LOGE("failed to initialize resource manager");
4476 ret = MM_ERROR_PLAYER_INTERNAL;
4480 /* create video bo lock and cond */
4481 g_mutex_init(&player->video_bo_mutex);
4482 g_cond_init(&player->video_bo_cond);
4484 /* create media stream callback mutex */
4485 g_mutex_init(&player->media_stream_cb_lock);
4487 /* create subtitle info lock and cond */
4488 g_mutex_init(&player->subtitle_info_mutex);
4489 g_cond_init(&player->subtitle_info_cond);
4491 player->streaming_type = STREAMING_SERVICE_NONE;
4493 /* give default value of audio effect setting */
4494 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4495 player->sound.rg_enable = false;
4496 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4498 player->play_subtitle = FALSE;
4499 player->has_closed_caption = FALSE;
4500 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4501 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4502 player->pending_resume = FALSE;
4503 if (player->ini.dump_element_keyword[0][0] == '\0')
4504 player->ini.set_dump_element_flag = FALSE;
4506 player->ini.set_dump_element_flag = TRUE;
4508 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4509 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4510 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4512 /* Set video360 settings to their defaults for just-created player.
4515 player->is_360_feature_enabled = FALSE;
4516 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4517 LOGI("spherical feature info: %d", enabled);
4519 player->is_360_feature_enabled = TRUE;
4521 LOGE("failed to get spherical feature info");
4524 player->is_content_spherical = FALSE;
4525 player->is_video360_enabled = TRUE;
4526 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4527 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4528 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4529 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4530 player->video360_zoom = 1.0f;
4531 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4532 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4534 __mmplayer_initialize_video_roi(player);
4536 /* set player state to null */
4537 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4538 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4542 return MM_ERROR_NONE;
4546 g_mutex_clear(&player->fsink_lock);
4547 /* free update tag lock */
4548 g_mutex_clear(&player->update_tag_lock);
4549 g_queue_free(player->bus_msg_q);
4550 /* free gapless play thread */
4551 if (player->gapless_play_thread) {
4552 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4553 player->gapless_play_thread_exit = TRUE;
4554 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4555 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4557 g_thread_join(player->gapless_play_thread);
4558 player->gapless_play_thread = NULL;
4560 g_mutex_clear(&player->gapless_play_thread_mutex);
4561 g_cond_clear(&player->gapless_play_thread_cond);
4564 /* release attributes */
4565 _mmplayer_deconstruct_attribute(handle);
4573 __mmplayer_init_gstreamer(mm_player_t *player)
4575 static gboolean initialized = FALSE;
4576 static const int max_argc = 50;
4578 gchar **argv = NULL;
4579 gchar **argv2 = NULL;
4585 LOGD("gstreamer already initialized.");
4590 argc = malloc(sizeof(int));
4591 argv = malloc(sizeof(gchar *) * max_argc);
4592 argv2 = malloc(sizeof(gchar *) * max_argc);
4594 if (!argc || !argv || !argv2)
4597 memset(argv, 0, sizeof(gchar *) * max_argc);
4598 memset(argv2, 0, sizeof(gchar *) * max_argc);
4602 argv[0] = g_strdup("mmplayer");
4605 for (i = 0; i < 5; i++) {
4606 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4607 if (strlen(player->ini.gst_param[i]) > 0) {
4608 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4613 /* we would not do fork for scanning plugins */
4614 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4617 /* check disable registry scan */
4618 if (player->ini.skip_rescan) {
4619 argv[*argc] = g_strdup("--gst-disable-registry-update");
4623 /* check disable segtrap */
4624 if (player->ini.disable_segtrap) {
4625 argv[*argc] = g_strdup("--gst-disable-segtrap");
4629 LOGD("initializing gstreamer with following parameter");
4630 LOGD("argc : %d", *argc);
4633 for (i = 0; i < arg_count; i++) {
4635 LOGD("argv[%d] : %s", i, argv2[i]);
4638 /* initializing gstreamer */
4639 if (!gst_init_check(argc, &argv, &err)) {
4640 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4647 for (i = 0; i < arg_count; i++) {
4648 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4649 MMPLAYER_FREEIF(argv2[i]);
4652 MMPLAYER_FREEIF(argv);
4653 MMPLAYER_FREEIF(argv2);
4654 MMPLAYER_FREEIF(argc);
4664 for (i = 0; i < arg_count; i++) {
4665 LOGD("free[%d] : %s", i, argv2[i]);
4666 MMPLAYER_FREEIF(argv2[i]);
4669 MMPLAYER_FREEIF(argv);
4670 MMPLAYER_FREEIF(argv2);
4671 MMPLAYER_FREEIF(argc);
4677 __mmplayer_check_async_state_transition(mm_player_t *player)
4679 GstState element_state = GST_STATE_VOID_PENDING;
4680 GstState element_pending_state = GST_STATE_VOID_PENDING;
4681 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4682 GstElement *element = NULL;
4683 gboolean async = FALSE;
4685 /* check player handle */
4686 MMPLAYER_RETURN_IF_FAIL(player &&
4688 player->pipeline->mainbin &&
4689 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4692 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4694 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4695 LOGD("don't need to check the pipeline state");
4699 MMPLAYER_PRINT_STATE(player);
4701 /* wait for state transition */
4702 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4703 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4705 if (ret == GST_STATE_CHANGE_FAILURE) {
4706 LOGE(" [%s] state : %s pending : %s",
4707 GST_ELEMENT_NAME(element),
4708 gst_element_state_get_name(element_state),
4709 gst_element_state_get_name(element_pending_state));
4711 /* dump state of all element */
4712 __mmplayer_dump_pipeline_state(player);
4717 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4722 _mmplayer_destroy(MMHandleType handle)
4724 mm_player_t *player = MM_PLAYER_CAST(handle);
4728 /* check player handle */
4729 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4731 /* destroy can called at anytime */
4732 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4734 /* check async state transition */
4735 __mmplayer_check_async_state_transition(player);
4737 /* release gapless play thread */
4738 if (player->gapless_play_thread) {
4739 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4740 player->gapless_play_thread_exit = TRUE;
4741 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4742 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4744 LOGD("waitting for gapless play thread exit");
4745 g_thread_join(player->gapless_play_thread);
4746 g_mutex_clear(&player->gapless_play_thread_mutex);
4747 g_cond_clear(&player->gapless_play_thread_cond);
4748 LOGD("gapless play thread released");
4751 _mmplayer_release_video_capture(player);
4753 /* de-initialize resource manager */
4754 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4755 player->resource_manager))
4756 LOGE("failed to deinitialize resource manager");
4758 /* release pipeline */
4759 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4760 LOGE("failed to destory pipeline");
4761 return MM_ERROR_PLAYER_INTERNAL;
4764 g_queue_free(player->bus_msg_q);
4766 /* release subtitle info lock and cond */
4767 g_mutex_clear(&player->subtitle_info_mutex);
4768 g_cond_clear(&player->subtitle_info_cond);
4770 __mmplayer_release_dump_list(player->dump_list);
4772 /* release miscellaneous information */
4773 __mmplayer_release_misc(player);
4775 /* release miscellaneous information.
4776 these info needs to be released after pipeline is destroyed. */
4777 __mmplayer_release_misc_post(player);
4779 /* release attributes */
4780 _mmplayer_deconstruct_attribute(handle);
4783 g_mutex_clear(&player->fsink_lock);
4786 g_mutex_clear(&player->update_tag_lock);
4788 /* release video bo lock and cond */
4789 g_mutex_clear(&player->video_bo_mutex);
4790 g_cond_clear(&player->video_bo_cond);
4792 /* release media stream callback lock */
4793 g_mutex_clear(&player->media_stream_cb_lock);
4797 return MM_ERROR_NONE;
4801 _mmplayer_realize(MMHandleType hplayer)
4803 mm_player_t *player = (mm_player_t *)hplayer;
4806 MMHandleType attrs = 0;
4807 int ret = MM_ERROR_NONE;
4811 /* check player handle */
4812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4814 /* check current state */
4815 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4817 attrs = MMPLAYER_GET_ATTRS(player);
4819 LOGE("fail to get attributes.");
4820 return MM_ERROR_PLAYER_INTERNAL;
4822 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4823 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4825 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4826 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4828 if (ret != MM_ERROR_NONE) {
4829 LOGE("failed to parse profile");
4834 if (uri && (strstr(uri, "es_buff://"))) {
4835 if (strstr(uri, "es_buff://push_mode"))
4836 player->es_player_push_mode = TRUE;
4838 player->es_player_push_mode = FALSE;
4841 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4842 LOGW("mms protocol is not supported format.");
4843 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4846 if (MMPLAYER_IS_STREAMING(player))
4847 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4849 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4851 player->smooth_streaming = FALSE;
4852 player->videodec_linked = 0;
4853 player->audiodec_linked = 0;
4854 player->textsink_linked = 0;
4855 player->is_external_subtitle_present = FALSE;
4856 player->is_external_subtitle_added_now = FALSE;
4857 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4858 player->video360_metadata.is_spherical = -1;
4859 player->is_openal_plugin_used = FALSE;
4860 player->demux_pad_index = 0;
4861 player->subtitle_language_list = NULL;
4862 player->is_subtitle_force_drop = FALSE;
4864 __mmplayer_track_initialize(player);
4865 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4867 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4868 gint prebuffer_ms = 0, rebuffer_ms = 0;
4870 player->streamer = __mm_player_streaming_create();
4871 __mm_player_streaming_initialize(player->streamer, TRUE);
4873 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4874 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4876 if (prebuffer_ms > 0) {
4877 prebuffer_ms = MAX(prebuffer_ms, 1000);
4878 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4881 if (rebuffer_ms > 0) {
4882 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4883 rebuffer_ms = MAX(rebuffer_ms, 1000);
4884 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4887 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4888 player->streamer->buffering_req.rebuffer_time);
4891 /* realize pipeline */
4892 ret = __mmplayer_gst_realize(player);
4893 if (ret != MM_ERROR_NONE)
4894 LOGE("fail to realize the player.");
4896 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4904 _mmplayer_unrealize(MMHandleType hplayer)
4906 mm_player_t *player = (mm_player_t *)hplayer;
4907 int ret = MM_ERROR_NONE;
4911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4913 MMPLAYER_CMD_UNLOCK(player);
4914 /* destroy the gst bus msg thread which is created during realize.
4915 this funct have to be called before getting cmd lock. */
4916 __mmplayer_bus_msg_thread_destroy(player);
4917 MMPLAYER_CMD_LOCK(player);
4919 /* check current state */
4920 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4922 /* check async state transition */
4923 __mmplayer_check_async_state_transition(player);
4925 /* unrealize pipeline */
4926 ret = __mmplayer_gst_unrealize(player);
4928 /* set asm stop if success */
4929 if (MM_ERROR_NONE == ret) {
4930 if (!player->interrupted_by_resource) {
4931 if (player->video_decoder_resource != NULL) {
4932 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4933 player->video_decoder_resource);
4934 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4935 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4937 player->video_decoder_resource = NULL;
4940 if (player->video_overlay_resource != NULL) {
4941 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4942 player->video_overlay_resource);
4943 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4944 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4946 player->video_overlay_resource = NULL;
4949 ret = mm_resource_manager_commit(player->resource_manager);
4950 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4951 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4954 LOGE("failed and don't change asm state to stop");
4962 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4964 mm_player_t *player = (mm_player_t *)hplayer;
4966 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4968 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4972 _mmplayer_get_state(MMHandleType hplayer, int *state)
4974 mm_player_t *player = (mm_player_t *)hplayer;
4976 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4978 *state = MMPLAYER_CURRENT_STATE(player);
4980 return MM_ERROR_NONE;
4985 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4987 mm_player_t *player = (mm_player_t *)hplayer;
4988 GstElement *vol_element = NULL;
4993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4995 LOGD("volume [L]=%f:[R]=%f",
4996 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4998 /* invalid factor range or not */
4999 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5000 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5001 LOGE("Invalid factor!(valid factor:0~1.0)");
5002 return MM_ERROR_INVALID_ARGUMENT;
5006 /* not support to set other value into each channel */
5007 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5008 return MM_ERROR_INVALID_ARGUMENT;
5010 /* Save volume to handle. Currently the first array element will be saved. */
5011 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5013 /* check pipeline handle */
5014 if (!player->pipeline || !player->pipeline->audiobin) {
5015 LOGD("audiobin is not created yet");
5016 LOGD("but, current stored volume will be set when it's created.");
5018 /* NOTE : stored volume will be used in create_audiobin
5019 * returning MM_ERROR_NONE here makes application to able to
5020 * set volume at anytime.
5022 return MM_ERROR_NONE;
5025 /* setting volume to volume element */
5026 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5029 LOGD("volume is set [%f]", player->sound.volume);
5030 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5035 return MM_ERROR_NONE;
5039 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5041 mm_player_t *player = (mm_player_t *)hplayer;
5046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5047 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5049 /* returning stored volume */
5050 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5051 volume->level[i] = player->sound.volume;
5055 return MM_ERROR_NONE;
5059 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5061 mm_player_t *player = (mm_player_t *)hplayer;
5062 GstElement *vol_element = NULL;
5066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5068 /* mute value shoud 0 or 1 */
5069 if (mute != 0 && mute != 1) {
5070 LOGE("bad mute value");
5072 /* FIXIT : definitly, we need _BAD_PARAM error code */
5073 return MM_ERROR_INVALID_ARGUMENT;
5076 player->sound.mute = mute;
5078 /* just hold mute value if pipeline is not ready */
5079 if (!player->pipeline || !player->pipeline->audiobin) {
5080 LOGD("pipeline is not ready. holding mute value");
5081 return MM_ERROR_NONE;
5084 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5086 /* NOTE : volume will only created when the bt is enabled */
5088 LOGD("mute : %d", mute);
5089 g_object_set(vol_element, "mute", mute, NULL);
5091 LOGD("volume elemnet is not created. using volume in audiosink");
5095 return MM_ERROR_NONE;
5099 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5101 mm_player_t *player = (mm_player_t *)hplayer;
5105 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5108 /* just hold mute value if pipeline is not ready */
5109 if (!player->pipeline || !player->pipeline->audiobin) {
5110 LOGD("pipeline is not ready. returning stored value");
5111 *pmute = player->sound.mute;
5112 return MM_ERROR_NONE;
5115 *pmute = player->sound.mute;
5119 return MM_ERROR_NONE;
5123 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5125 mm_player_t *player = (mm_player_t *)hplayer;
5129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5131 player->video_stream_changed_cb = callback;
5132 player->video_stream_changed_cb_user_param = user_param;
5133 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5137 return MM_ERROR_NONE;
5141 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5143 mm_player_t *player = (mm_player_t *)hplayer;
5147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 player->audio_stream_changed_cb = callback;
5150 player->audio_stream_changed_cb_user_param = user_param;
5151 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5155 return MM_ERROR_NONE;
5159 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5161 mm_player_t *player = (mm_player_t *)hplayer;
5165 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5167 player->audio_stream_render_cb = callback;
5168 player->audio_stream_cb_user_param = user_param;
5169 player->audio_stream_sink_sync = sync;
5170 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5174 return MM_ERROR_NONE;
5178 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5180 mm_player_t *player = (mm_player_t *)hplayer;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186 if (callback && !player->bufmgr)
5187 player->bufmgr = tbm_bufmgr_init(-1);
5189 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5190 player->video_stream_cb = callback;
5191 player->video_stream_cb_user_param = user_param;
5193 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5197 return MM_ERROR_NONE;
5201 _mmplayer_start(MMHandleType hplayer)
5203 mm_player_t *player = (mm_player_t *)hplayer;
5204 gint ret = MM_ERROR_NONE;
5208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5210 /* check current state */
5211 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5213 /* start pipeline */
5214 ret = __mmplayer_gst_start(player);
5215 if (ret != MM_ERROR_NONE)
5216 LOGE("failed to start player.");
5218 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5219 LOGD("force playing start even during buffering");
5220 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5228 /* NOTE: post "not supported codec message" to application
5229 * when one codec is not found during AUTOPLUGGING in MSL.
5230 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5231 * And, if any codec is not found, don't send message here.
5232 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5235 __mmplayer_handle_missed_plugin(mm_player_t *player)
5237 MMMessageParamType msg_param;
5238 memset(&msg_param, 0, sizeof(MMMessageParamType));
5239 gboolean post_msg_direct = FALSE;
5243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5246 player->not_supported_codec, player->can_support_codec);
5248 if (player->not_found_demuxer) {
5249 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5250 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5252 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5253 MMPLAYER_FREEIF(msg_param.data);
5255 return MM_ERROR_NONE;
5258 if (player->not_supported_codec) {
5259 if (player->can_support_codec) {
5260 // There is one codec to play
5261 post_msg_direct = TRUE;
5263 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5264 post_msg_direct = TRUE;
5267 if (post_msg_direct) {
5268 MMMessageParamType msg_param;
5269 memset(&msg_param, 0, sizeof(MMMessageParamType));
5271 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5272 LOGW("not found AUDIO codec, posting error code to application.");
5274 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5275 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5276 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5277 LOGW("not found VIDEO codec, posting error code to application.");
5279 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5280 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5283 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5285 MMPLAYER_FREEIF(msg_param.data);
5287 return MM_ERROR_NONE;
5289 // no any supported codec case
5290 LOGW("not found any codec, posting error code to application.");
5292 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5293 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5294 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5296 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5297 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5300 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5302 MMPLAYER_FREEIF(msg_param.data);
5308 return MM_ERROR_NONE;
5312 __mmplayer_check_pipeline(mm_player_t *player)
5314 GstState element_state = GST_STATE_VOID_PENDING;
5315 GstState element_pending_state = GST_STATE_VOID_PENDING;
5317 int ret = MM_ERROR_NONE;
5319 if (!player->gapless.reconfigure)
5322 LOGW("pipeline is under construction.");
5324 MMPLAYER_PLAYBACK_LOCK(player);
5325 MMPLAYER_PLAYBACK_UNLOCK(player);
5327 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5329 /* wait for state transition */
5330 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5331 if (ret == GST_STATE_CHANGE_FAILURE)
5332 LOGE("failed to change pipeline state within %d sec", timeout);
5335 /* NOTE : it should be able to call 'stop' anytime*/
5337 _mmplayer_stop(MMHandleType hplayer)
5339 mm_player_t *player = (mm_player_t *)hplayer;
5340 int ret = MM_ERROR_NONE;
5344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346 /* check current state */
5347 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5349 /* check pipline building state */
5350 __mmplayer_check_pipeline(player);
5351 __mmplayer_reset_gapless_state(player);
5353 /* NOTE : application should not wait for EOS after calling STOP */
5354 __mmplayer_cancel_eos_timer(player);
5357 player->seek_state = MMPLAYER_SEEK_NONE;
5360 ret = __mmplayer_gst_stop(player);
5362 if (ret != MM_ERROR_NONE)
5363 LOGE("failed to stop player.");
5371 _mmplayer_pause(MMHandleType hplayer)
5373 mm_player_t *player = (mm_player_t *)hplayer;
5374 gint64 pos_nsec = 0;
5375 gboolean async = FALSE;
5376 gint ret = MM_ERROR_NONE;
5380 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5382 /* check current state */
5383 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5385 /* check pipline building state */
5386 __mmplayer_check_pipeline(player);
5388 switch (MMPLAYER_CURRENT_STATE(player)) {
5389 case MM_PLAYER_STATE_READY:
5391 /* check prepare async or not.
5392 * In the case of streaming playback, it's recommned to avoid blocking wait.
5394 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5395 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5397 /* Changing back sync of rtspsrc to async */
5398 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5399 LOGD("async prepare working mode for rtsp");
5405 case MM_PLAYER_STATE_PLAYING:
5407 /* NOTE : store current point to overcome some bad operation
5408 *(returning zero when getting current position in paused state) of some
5411 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5412 LOGW("getting current position failed in paused");
5414 player->last_position = pos_nsec;
5416 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5417 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5418 This causes problem is position calculation during normal pause resume scenarios also.
5419 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5420 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5421 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5422 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5428 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5429 LOGD("doing async pause in case of ms buff src");
5433 /* pause pipeline */
5434 ret = __mmplayer_gst_pause(player, async);
5436 if (ret != MM_ERROR_NONE)
5437 LOGE("failed to pause player. ret : 0x%x", ret);
5439 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5440 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5441 LOGE("failed to update display_rotation");
5449 /* in case of streaming, pause could take long time.*/
5451 _mmplayer_abort_pause(MMHandleType hplayer)
5453 mm_player_t *player = (mm_player_t *)hplayer;
5454 int ret = MM_ERROR_NONE;
5458 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5460 player->pipeline->mainbin,
5461 MM_ERROR_PLAYER_NOT_INITIALIZED);
5463 LOGD("set the pipeline state to READY");
5465 /* set state to READY */
5466 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5467 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5468 if (ret != MM_ERROR_NONE) {
5469 LOGE("fail to change state to READY");
5470 return MM_ERROR_PLAYER_INTERNAL;
5473 LOGD("succeeded in changing state to READY");
5478 _mmplayer_resume(MMHandleType hplayer)
5480 mm_player_t *player = (mm_player_t *)hplayer;
5481 int ret = MM_ERROR_NONE;
5482 gboolean async = FALSE;
5486 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5488 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5489 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5490 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5494 /* Changing back sync mode rtspsrc to async */
5495 LOGD("async resume for rtsp case");
5499 /* check current state */
5500 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5502 ret = __mmplayer_gst_resume(player, async);
5503 if (ret != MM_ERROR_NONE)
5504 LOGE("failed to resume player.");
5506 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5507 LOGD("force resume even during buffering");
5508 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5517 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5519 mm_player_t *player = (mm_player_t *)hplayer;
5520 gint64 pos_nsec = 0;
5521 int ret = MM_ERROR_NONE;
5523 signed long long start = 0, stop = 0;
5524 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5528 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5530 /* The sound of video is not supported under 0.0 and over 2.0. */
5531 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5532 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5535 _mmplayer_set_mute(hplayer, mute);
5537 if (player->playback_rate == rate)
5538 return MM_ERROR_NONE;
5540 /* If the position is reached at start potion during fast backward, EOS is posted.
5541 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5543 player->playback_rate = rate;
5545 current_state = MMPLAYER_CURRENT_STATE(player);
5547 if (current_state != MM_PLAYER_STATE_PAUSED)
5548 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5550 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5552 if ((current_state == MM_PLAYER_STATE_PAUSED)
5553 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5554 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5555 pos_nsec = player->last_position;
5560 stop = GST_CLOCK_TIME_NONE;
5562 start = GST_CLOCK_TIME_NONE;
5566 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5567 player->playback_rate,
5569 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5570 GST_SEEK_TYPE_SET, start,
5571 GST_SEEK_TYPE_SET, stop)) {
5572 LOGE("failed to set speed playback");
5573 return MM_ERROR_PLAYER_SEEK;
5576 LOGD("succeeded to set speed playback as %0.1f", rate);
5580 return MM_ERROR_NONE;;
5584 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5586 mm_player_t *player = (mm_player_t *)hplayer;
5587 int ret = MM_ERROR_NONE;
5591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5593 /* check pipline building state */
5594 __mmplayer_check_pipeline(player);
5596 ret = __mmplayer_gst_set_position(player, position, FALSE);
5604 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5606 mm_player_t *player = (mm_player_t *)hplayer;
5607 int ret = MM_ERROR_NONE;
5609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5611 ret = __mmplayer_gst_get_position(player, position);
5617 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5619 mm_player_t *player = (mm_player_t *)hplayer;
5620 int ret = MM_ERROR_NONE;
5622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5623 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5625 if (g_strrstr(player->type, "video/mpegts"))
5626 __mmplayer_update_duration_value(player);
5628 *duration = player->duration;
5633 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5635 mm_player_t *player = (mm_player_t *)hplayer;
5636 int ret = MM_ERROR_NONE;
5638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5640 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5646 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5648 mm_player_t *player = (mm_player_t *)hplayer;
5649 int ret = MM_ERROR_NONE;
5653 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5655 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5663 __mmplayer_is_midi_type(gchar *str_caps)
5665 if ((g_strrstr(str_caps, "audio/midi")) ||
5666 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5667 (g_strrstr(str_caps, "application/x-smaf")) ||
5668 (g_strrstr(str_caps, "audio/x-imelody")) ||
5669 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5670 (g_strrstr(str_caps, "audio/xmf")) ||
5671 (g_strrstr(str_caps, "audio/mxmf"))) {
5680 __mmplayer_is_only_mp3_type(gchar *str_caps)
5682 if (g_strrstr(str_caps, "application/x-id3") ||
5683 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5689 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5691 GstStructure *caps_structure = NULL;
5692 gint samplerate = 0;
5696 MMPLAYER_RETURN_IF_FAIL(player && caps);
5698 caps_structure = gst_caps_get_structure(caps, 0);
5700 /* set stream information */
5701 gst_structure_get_int(caps_structure, "rate", &samplerate);
5702 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5704 gst_structure_get_int(caps_structure, "channels", &channels);
5705 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5707 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5711 __mmplayer_update_content_type_info(mm_player_t *player)
5714 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5716 if (__mmplayer_is_midi_type(player->type)) {
5717 player->bypass_audio_effect = TRUE;
5721 if (!player->streamer) {
5722 LOGD("no need to check streaming type");
5726 if (g_strrstr(player->type, "application/x-hls")) {
5727 /* If it can't know exact type when it parses uri because of redirection case,
5728 * it will be fixed by typefinder or when doing autoplugging.
5730 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5731 player->streamer->is_adaptive_streaming = TRUE;
5732 } else if (g_strrstr(player->type, "application/dash+xml")) {
5733 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5734 player->streamer->is_adaptive_streaming = TRUE;
5737 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5738 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5739 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5741 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5742 if (player->streamer->is_adaptive_streaming)
5743 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5745 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5749 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5754 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5755 GstCaps *caps, gpointer data)
5757 mm_player_t *player = (mm_player_t *)data;
5762 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5764 /* store type string */
5765 MMPLAYER_FREEIF(player->type);
5766 player->type = gst_caps_to_string(caps);
5768 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5769 player, player->type, probability, gst_caps_get_size(caps));
5771 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5772 (g_strrstr(player->type, "audio/x-raw-int"))) {
5773 LOGE("not support media format");
5775 if (player->msg_posted == FALSE) {
5776 MMMessageParamType msg_param;
5777 memset(&msg_param, 0, sizeof(MMMessageParamType));
5779 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5780 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5782 /* don't post more if one was sent already */
5783 player->msg_posted = TRUE;
5788 __mmplayer_update_content_type_info(player);
5790 pad = gst_element_get_static_pad(tf, "src");
5792 LOGE("fail to get typefind src pad.");
5796 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5797 gboolean async = FALSE;
5798 LOGE("failed to autoplug %s", player->type);
5800 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5802 if (async && player->msg_posted == FALSE)
5803 __mmplayer_handle_missed_plugin(player);
5807 gst_object_unref(GST_OBJECT(pad));
5815 __mmplayer_gst_make_decodebin(mm_player_t *player)
5817 GstElement *decodebin = NULL;
5821 /* create decodebin */
5822 decodebin = gst_element_factory_make("decodebin", NULL);
5825 LOGE("fail to create decodebin");
5829 /* raw pad handling signal */
5830 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5831 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5833 /* no-more-pad pad handling signal */
5834 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5835 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5837 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5838 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5840 /* This signal is emitted when a pad for which there is no further possible
5841 decoding is added to the decodebin.*/
5842 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5843 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5845 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5846 before looking for any elements that can handle that stream.*/
5847 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5848 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5850 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5851 before looking for any elements that can handle that stream.*/
5852 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5853 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5855 /* This signal is emitted once decodebin has finished decoding all the data.*/
5856 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5857 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5859 /* This signal is emitted when a element is added to the bin.*/
5860 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5861 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5868 __mmplayer_gst_make_queue2(mm_player_t *player)
5870 GstElement *queue2 = NULL;
5871 gint64 dur_bytes = 0L;
5872 MMPlayerGstElement *mainbin = NULL;
5873 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5876 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5878 mainbin = player->pipeline->mainbin;
5880 queue2 = gst_element_factory_make("queue2", "queue2");
5882 LOGE("failed to create buffering queue element");
5886 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5887 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5889 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5891 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5892 * skip the pull mode(file or ring buffering) setting. */
5893 if (dur_bytes > 0) {
5894 if (!g_strrstr(player->type, "video/mpegts")) {
5895 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5896 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5902 __mm_player_streaming_set_queue2(player->streamer,
5906 (guint64)dur_bytes); /* no meaning at the moment */
5912 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5914 MMPlayerGstElement *mainbin = NULL;
5915 GstElement *decodebin = NULL;
5916 GstElement *queue2 = NULL;
5917 GstPad *sinkpad = NULL;
5918 GstPad *qsrcpad = NULL;
5921 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5923 mainbin = player->pipeline->mainbin;
5925 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5927 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5928 LOGW("need to check: muxed buffer is not null");
5931 queue2 = __mmplayer_gst_make_queue2(player);
5933 LOGE("failed to make queue2");
5937 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5938 LOGE("failed to add buffering queue");
5942 sinkpad = gst_element_get_static_pad(queue2, "sink");
5943 qsrcpad = gst_element_get_static_pad(queue2, "src");
5945 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5946 LOGE("failed to link [%s:%s]-[%s:%s]",
5947 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5951 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5952 LOGE("failed to sync queue2 state with parent");
5956 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5957 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5961 gst_object_unref(GST_OBJECT(sinkpad));
5965 /* create decodebin */
5966 decodebin = __mmplayer_gst_make_decodebin(player);
5968 LOGE("failed to make decodebin");
5972 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5973 LOGE("failed to add decodebin");
5977 /* to force caps on the decodebin element and avoid reparsing stuff by
5978 * typefind. It also avoids a deadlock in the way typefind activates pads in
5979 * the state change */
5980 g_object_set(decodebin, "sink-caps", caps, NULL);
5982 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5984 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5985 LOGE("failed to link [%s:%s]-[%s:%s]",
5986 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5990 gst_object_unref(GST_OBJECT(sinkpad));
5992 gst_object_unref(GST_OBJECT(qsrcpad));
5995 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5996 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5998 /* set decodebin property about buffer in streaming playback. *
5999 * in case of HLS/DASH, it does not need to have big buffer *
6000 * because it is kind of adaptive streaming. */
6001 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6002 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6003 gint high_percent = 0;
6005 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6006 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6008 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6010 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6012 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6013 "high-percent", high_percent,
6014 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6015 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6016 "max-size-buffers", 0, NULL); // disable or automatic
6019 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6020 LOGE("failed to sync decodebin state with parent");
6031 gst_object_unref(GST_OBJECT(sinkpad));
6034 gst_object_unref(GST_OBJECT(qsrcpad));
6037 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6038 * You need to explicitly set elements to the NULL state before
6039 * dropping the final reference, to allow them to clean up.
6041 gst_element_set_state(queue2, GST_STATE_NULL);
6043 /* And, it still has a parent "player".
6044 * You need to let the parent manage the object instead of unreffing the object directly.
6046 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6047 gst_object_unref(queue2);
6052 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6053 * You need to explicitly set elements to the NULL state before
6054 * dropping the final reference, to allow them to clean up.
6056 gst_element_set_state(decodebin, GST_STATE_NULL);
6058 /* And, it still has a parent "player".
6059 * You need to let the parent manage the object instead of unreffing the object directly.
6062 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6063 gst_object_unref(decodebin);
6071 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6075 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6076 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6078 LOGD("class : %s, mime : %s", factory_class, mime);
6080 /* add missing plugin */
6081 /* NOTE : msl should check missing plugin for image mime type.
6082 * Some motion jpeg clips can have playable audio track.
6083 * So, msl have to play audio after displaying popup written video format not supported.
6085 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6086 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6087 LOGD("not found demuxer");
6088 player->not_found_demuxer = TRUE;
6089 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6095 if (!g_strrstr(factory_class, "Demuxer")) {
6096 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6097 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6098 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6100 /* check that clip have multi tracks or not */
6101 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6102 LOGD("video plugin is already linked");
6104 LOGW("add VIDEO to missing plugin");
6105 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6106 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6108 } else if (g_str_has_prefix(mime, "audio")) {
6109 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6110 LOGD("audio plugin is already linked");
6112 LOGW("add AUDIO to missing plugin");
6113 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6114 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6122 return MM_ERROR_NONE;
6126 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6128 mm_player_t *player = (mm_player_t *)data;
6132 MMPLAYER_RETURN_IF_FAIL(player);
6134 /* remove fakesink. */
6135 if (!__mmplayer_gst_remove_fakesink(player,
6136 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6137 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6138 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6139 * source element are not same. To overcome this situation, this function will called
6140 * several places and several times. Therefore, this is not an error case.
6145 LOGD("[handle: %p] pipeline has completely constructed", player);
6147 if ((player->ini.async_start) &&
6148 (player->msg_posted == FALSE) &&
6149 (player->cmd >= MMPLAYER_COMMAND_START))
6150 __mmplayer_handle_missed_plugin(player);
6152 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6156 __mmplayer_check_profile(void)
6159 static int profile_tv = -1;
6161 if (__builtin_expect(profile_tv != -1, 1))
6164 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6165 switch (*profileName) {
6180 __mmplayer_get_next_uri(mm_player_t *player)
6182 MMPlayerParseProfile profile;
6184 guint num_of_list = 0;
6187 num_of_list = g_list_length(player->uri_info.uri_list);
6188 uri_idx = player->uri_info.uri_idx;
6190 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6191 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6192 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6194 LOGW("next uri does not exist");
6198 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6199 LOGE("failed to parse profile");
6203 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6204 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6205 LOGW("uri type is not supported(%d)", profile.uri_type);
6209 LOGD("success to find next uri %d", uri_idx);
6213 if (uri_idx == num_of_list) {
6214 LOGE("failed to find next uri");
6218 player->uri_info.uri_idx = uri_idx;
6219 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6221 if (mm_attrs_commit_all(player->attrs)) {
6222 LOGE("failed to commit");
6226 SECURE_LOGD("next playback uri: %s", uri);
6231 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6233 #define REPEAT_COUNT_INFINITELY -1
6234 #define REPEAT_COUNT_MIN 2
6236 MMHandleType attrs = 0;
6240 guint num_of_list = 0;
6241 int profile_tv = -1;
6245 LOGD("checking for gapless play option");
6247 if (player->pipeline->textbin) {
6248 LOGE("subtitle path is enabled. gapless play is not supported.");
6252 attrs = MMPLAYER_GET_ATTRS(player);
6254 LOGE("fail to get attributes.");
6258 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6260 /* gapless playback is not supported in case of video at TV profile. */
6261 profile_tv = __mmplayer_check_profile();
6262 if (profile_tv && video) {
6263 LOGW("not support video gapless playback");
6267 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6268 LOGE("failed to get play count");
6270 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6271 LOGE("failed to get gapless mode");
6273 /* check repeat count in case of audio */
6275 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6276 LOGW("gapless is disabled");
6280 num_of_list = g_list_length(player->uri_info.uri_list);
6282 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6284 if (num_of_list == 0) {
6285 /* audio looping path */
6286 if (count >= REPEAT_COUNT_MIN) {
6287 /* decrease play count */
6288 /* we succeeded to rewind. update play count and then wait for next EOS */
6290 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6291 /* commit attribute */
6292 if (mm_attrs_commit_all(attrs))
6293 LOGE("failed to commit attribute");
6295 } else if (count != REPEAT_COUNT_INFINITELY) {
6296 LOGD("there is no next uri and no repeat");
6299 LOGD("looping cnt %d", count);
6301 /* gapless playback path */
6302 if (!__mmplayer_get_next_uri(player)) {
6303 LOGE("failed to get next uri");
6310 LOGE("unable to play gapless path. EOS will be posted soon");
6315 __mmplayer_initialize_gapless_play(mm_player_t *player)
6321 player->smooth_streaming = FALSE;
6322 player->videodec_linked = 0;
6323 player->audiodec_linked = 0;
6324 player->textsink_linked = 0;
6325 player->is_external_subtitle_present = FALSE;
6326 player->is_external_subtitle_added_now = FALSE;
6327 player->not_supported_codec = MISSING_PLUGIN_NONE;
6328 player->can_support_codec = FOUND_PLUGIN_NONE;
6329 player->pending_seek.is_pending = false;
6330 player->pending_seek.pos = 0;
6331 player->msg_posted = FALSE;
6332 player->has_many_types = FALSE;
6333 player->no_more_pad = FALSE;
6334 player->not_found_demuxer = 0;
6335 player->seek_state = MMPLAYER_SEEK_NONE;
6336 player->is_subtitle_force_drop = FALSE;
6337 player->play_subtitle = FALSE;
6338 player->adjust_subtitle_pos = 0;
6340 player->total_bitrate = 0;
6341 player->total_maximum_bitrate = 0;
6343 __mmplayer_track_initialize(player);
6344 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6346 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6347 player->bitrate[i] = 0;
6348 player->maximum_bitrate[i] = 0;
6351 if (player->v_stream_caps) {
6352 gst_caps_unref(player->v_stream_caps);
6353 player->v_stream_caps = NULL;
6356 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6358 /* clean found audio decoders */
6359 if (player->audio_decoders) {
6360 GList *a_dec = player->audio_decoders;
6361 for (; a_dec; a_dec = g_list_next(a_dec)) {
6362 gchar *name = a_dec->data;
6363 MMPLAYER_FREEIF(name);
6365 g_list_free(player->audio_decoders);
6366 player->audio_decoders = NULL;
6373 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6375 MMPlayerGstElement *mainbin = NULL;
6376 MMMessageParamType msg_param = {0,};
6377 GstElement *element = NULL;
6378 MMHandleType attrs = 0;
6380 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6384 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6385 LOGE("player is not initialized");
6389 mainbin = player->pipeline->mainbin;
6390 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6392 attrs = MMPLAYER_GET_ATTRS(player);
6394 LOGE("fail to get attributes");
6398 /* Initialize Player values */
6399 __mmplayer_initialize_gapless_play(player);
6401 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6403 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6404 LOGE("failed to parse profile");
6405 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6409 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6410 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6411 LOGE("dash or hls is not supportable");
6412 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6416 element = __mmplayer_gst_create_source(player);
6418 LOGE("no source element was created");
6422 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6423 LOGE("failed to add source element to pipeline");
6424 gst_object_unref(GST_OBJECT(element));
6429 /* take source element */
6430 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6431 mainbin[MMPLAYER_M_SRC].gst = element;
6435 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6436 if (player->streamer == NULL) {
6437 player->streamer = __mm_player_streaming_create();
6438 __mm_player_streaming_initialize(player->streamer, TRUE);
6441 elem_idx = MMPLAYER_M_TYPEFIND;
6442 element = gst_element_factory_make("typefind", "typefinder");
6443 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6444 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6446 elem_idx = MMPLAYER_M_AUTOPLUG;
6447 element = __mmplayer_gst_make_decodebin(player);
6450 /* check autoplug element is OK */
6452 LOGE("can not create element(%d)", elem_idx);
6456 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6457 LOGE("failed to add sinkbin to pipeline");
6458 gst_object_unref(GST_OBJECT(element));
6463 mainbin[elem_idx].id = elem_idx;
6464 mainbin[elem_idx].gst = element;
6466 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6467 LOGE("Failed to link src - autoplug(or typefind)");
6471 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6472 LOGE("Failed to change state of src element");
6476 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6477 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6478 LOGE("Failed to change state of decodebin");
6482 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6483 LOGE("Failed to change state of src element");
6488 player->gapless.stream_changed = TRUE;
6489 player->gapless.running = TRUE;
6495 MMPLAYER_PLAYBACK_UNLOCK(player);
6497 if (!player->msg_posted) {
6498 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6499 player->msg_posted = TRUE;
6506 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6508 mm_player_selector_t *selector = &player->selector[type];
6509 MMPlayerGstElement *sinkbin = NULL;
6510 enum MainElementID selectorId = MMPLAYER_M_NUM;
6511 enum MainElementID sinkId = MMPLAYER_M_NUM;
6512 GstPad *srcpad = NULL;
6513 GstPad *sinkpad = NULL;
6514 gboolean send_notice = FALSE;
6517 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6519 LOGD("type %d", type);
6522 case MM_PLAYER_TRACK_TYPE_AUDIO:
6523 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6524 sinkId = MMPLAYER_A_BIN;
6525 sinkbin = player->pipeline->audiobin;
6527 case MM_PLAYER_TRACK_TYPE_VIDEO:
6528 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6529 sinkId = MMPLAYER_V_BIN;
6530 sinkbin = player->pipeline->videobin;
6533 case MM_PLAYER_TRACK_TYPE_TEXT:
6534 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6535 sinkId = MMPLAYER_T_BIN;
6536 sinkbin = player->pipeline->textbin;
6539 LOGE("requested type is not supportable");
6544 if (player->pipeline->mainbin[selectorId].gst) {
6547 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6549 if (selector->event_probe_id != 0)
6550 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6551 selector->event_probe_id = 0;
6553 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6554 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6556 if (srcpad && sinkpad) {
6557 /* after getting drained signal there is no data flows, so no need to do pad_block */
6558 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6559 gst_pad_unlink(srcpad, sinkpad);
6561 /* send custom event to sink pad to handle it at video sink */
6563 LOGD("send custom event to sinkpad");
6564 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6565 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6566 gst_pad_send_event(sinkpad, event);
6570 gst_object_unref(sinkpad);
6573 gst_object_unref(srcpad);
6576 LOGD("selector release");
6578 /* release and unref requests pad from the selector */
6579 for (n = 0; n < selector->channels->len; n++) {
6580 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6581 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6583 g_ptr_array_set_size(selector->channels, 0);
6585 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6586 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6588 player->pipeline->mainbin[selectorId].gst = NULL;
6596 __mmplayer_deactivate_old_path(mm_player_t *player)
6599 MMPLAYER_RETURN_IF_FAIL(player);
6601 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6602 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6603 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6604 LOGE("deactivate selector error");
6608 __mmplayer_track_destroy(player);
6609 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6611 if (player->streamer) {
6612 __mm_player_streaming_initialize(player->streamer, FALSE);
6613 __mm_player_streaming_destroy(player->streamer);
6614 player->streamer = NULL;
6617 MMPLAYER_PLAYBACK_LOCK(player);
6618 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6625 if (!player->msg_posted) {
6626 MMMessageParamType msg = {0,};
6629 msg.code = MM_ERROR_PLAYER_INTERNAL;
6630 LOGE("gapless_uri_play> deactivate error");
6632 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6633 player->msg_posted = TRUE;
6639 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6641 int result = MM_ERROR_NONE;
6642 mm_player_t *player = (mm_player_t *)hplayer;
6645 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6647 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6648 if (mm_attrs_commit_all(player->attrs)) {
6649 LOGE("failed to commit the original uri.");
6650 result = MM_ERROR_PLAYER_INTERNAL;
6652 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6653 LOGE("failed to add the original uri in the uri list.");
6661 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6663 mm_player_t *player = (mm_player_t *)hplayer;
6664 guint num_of_list = 0;
6668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6669 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6671 if (player->pipeline && player->pipeline->textbin) {
6672 LOGE("subtitle path is enabled.");
6673 return MM_ERROR_PLAYER_INVALID_STATE;
6676 num_of_list = g_list_length(player->uri_info.uri_list);
6678 if (is_first_path) {
6679 if (num_of_list == 0) {
6680 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6681 SECURE_LOGD("add original path : %s", uri);
6683 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6684 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6686 SECURE_LOGD("change original path : %s", uri);
6689 MMHandleType attrs = 0;
6690 attrs = MMPLAYER_GET_ATTRS(player);
6692 if (num_of_list == 0) {
6693 char *original_uri = NULL;
6696 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6698 if (!original_uri) {
6699 LOGE("there is no original uri.");
6700 return MM_ERROR_PLAYER_INVALID_STATE;
6703 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6704 player->uri_info.uri_idx = 0;
6706 SECURE_LOGD("add original path at first : %s", original_uri);
6710 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6711 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6715 return MM_ERROR_NONE;
6719 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6721 mm_player_t *player = (mm_player_t *)hplayer;
6722 char *next_uri = NULL;
6723 guint num_of_list = 0;
6726 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6728 num_of_list = g_list_length(player->uri_info.uri_list);
6730 if (num_of_list > 0) {
6731 gint uri_idx = player->uri_info.uri_idx;
6733 if (uri_idx < num_of_list-1)
6738 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6739 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6741 *uri = g_strdup(next_uri);
6745 return MM_ERROR_NONE;
6749 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6750 GstCaps *caps, gpointer data)
6752 mm_player_t *player = (mm_player_t *)data;
6753 const gchar *klass = NULL;
6754 const gchar *mime = NULL;
6755 gchar *caps_str = NULL;
6757 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6758 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6759 caps_str = gst_caps_to_string(caps);
6761 LOGW("unknown type of caps : %s from %s",
6762 caps_str, GST_ELEMENT_NAME(elem));
6764 MMPLAYER_FREEIF(caps_str);
6766 /* There is no available codec. */
6767 __mmplayer_check_not_supported_codec(player, klass, mime);
6771 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6772 GstCaps *caps, gpointer data)
6774 mm_player_t *player = (mm_player_t *)data;
6775 const char *mime = NULL;
6776 gboolean ret = TRUE;
6778 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6779 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6781 if (g_str_has_prefix(mime, "audio")) {
6782 GstStructure *caps_structure = NULL;
6783 gint samplerate = 0;
6785 gchar *caps_str = NULL;
6787 caps_structure = gst_caps_get_structure(caps, 0);
6788 gst_structure_get_int(caps_structure, "rate", &samplerate);
6789 gst_structure_get_int(caps_structure, "channels", &channels);
6791 if ((channels > 0 && samplerate == 0)) {
6792 LOGD("exclude audio...");
6796 caps_str = gst_caps_to_string(caps);
6797 /* set it directly because not sent by TAG */
6798 if (g_strrstr(caps_str, "mobile-xmf"))
6799 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6800 MMPLAYER_FREEIF(caps_str);
6801 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6802 MMMessageParamType msg_param;
6803 memset(&msg_param, 0, sizeof(MMMessageParamType));
6804 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6805 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6806 LOGD("video file is not supported on this device");
6808 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6809 LOGD("already video linked");
6812 LOGD("found new stream");
6819 __mmplayer_is_audio_offload_device_type(mm_player_t *player)
6821 gboolean ret = TRUE;
6822 GDBusConnection *conn = NULL;
6824 GVariant *result = NULL;
6825 const gchar *dbus_device_type = NULL;
6826 const gchar *dbus_ret = NULL;
6829 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6831 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6837 result = g_dbus_connection_call_sync(conn,
6838 "org.pulseaudio.Server",
6839 "/org/pulseaudio/StreamManager",
6840 "org.pulseaudio.StreamManager",
6841 "GetCurrentMediaRoutingPath",
6842 g_variant_new("(s)", "out"),
6843 G_VARIANT_TYPE("(ss)"),
6844 G_DBUS_CALL_FLAGS_NONE,
6848 if (!result || err) {
6849 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6855 /* device type is listed in stream-map.json at mmfw-sysconf */
6856 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6858 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6859 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6864 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6865 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6866 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6867 LOGD("audio offload is supportable");
6873 LOGD("audio offload is not supportable");
6877 g_variant_unref(result);
6878 g_object_unref(conn);
6883 static void __mmplayer_rebuild_audio_pipeline(mm_player_t *player)
6885 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6886 gint64 position = 0;
6888 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6889 player->pipeline && player->pipeline->mainbin);
6891 MMPLAYER_CMD_LOCK(player);
6892 current_state = MMPLAYER_CURRENT_STATE(player);
6894 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6895 LOGW("getting current position failed in paused");
6897 _mmplayer_unrealize((MMHandleType)player);
6898 _mmplayer_realize((MMHandleType)player);
6900 _mmplayer_set_position((MMHandleType)player, position);
6902 /* async not to be blocked in streaming case */
6903 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6904 if (mm_attrs_commit_all(player->attrs))
6905 LOGE("failed to commit");
6907 _mmplayer_pause((MMHandleType)player);
6909 if (current_state == MM_PLAYER_STATE_PLAYING)
6910 _mmplayer_start((MMHandleType)player);
6911 MMPLAYER_CMD_UNLOCK(player);
6913 LOGD("rebuilding audio pipeline is completed.");
6916 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6918 mm_player_t *player = (mm_player_t *)user_data;
6919 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6920 gboolean is_supportable = FALSE;
6922 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6923 LOGW("failed to get device type");
6925 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6927 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6928 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6929 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6930 LOGD("ignore this dev connected info");
6934 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6935 if (player->build_audio_offload == is_supportable) {
6936 LOGD("keep current pipeline without re-building");
6940 /* rebuild pipeline */
6941 LOGD("re-build pipeline - offload: %d", is_supportable);
6942 player->build_audio_offload = FALSE;
6943 __mmplayer_rebuild_audio_pipeline(player);
6949 __mmplayer_add_audio_device_connected_cb(mm_player_t *player)
6951 unsigned int id = 0;
6953 if (player->audio_device_cb_id != 0) {
6954 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6958 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6959 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6960 LOGD("added device connected cb (%u)", id);
6961 player->audio_device_cb_id = id;
6963 LOGW("failed to add device connected cb");
6971 __mmplayer_can_build_audio_offload_path(mm_player_t *player)
6973 gboolean ret = FALSE;
6974 GstElementFactory *factory = NULL;
6977 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6979 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6980 if (!__mmplayer_is_only_mp3_type(player->type))
6983 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6984 LOGD("there is no audio offload sink");
6988 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6989 LOGW("there is no audio device type to support offload");
6993 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6995 LOGW("there is no installed audio offload sink element");
6998 gst_object_unref(factory);
7000 if (!__mmplayer_add_audio_device_connected_cb(player))
7003 if (!__mmplayer_is_audio_offload_device_type(player))
7006 LOGD("audio offload can be built");
7014 static GstAutoplugSelectResult
7015 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
7017 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7019 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7020 int audio_offload = 0;
7022 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7023 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7025 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7026 LOGD("expose audio path to build offload output path");
7027 player->build_audio_offload = TRUE;
7028 /* update codec info */
7029 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7030 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7031 player->audiodec_linked = 1;
7033 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7037 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7039 LOGD("audio codec type: %d", codec_type);
7040 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7041 /* sw codec will be skipped */
7042 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7043 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7044 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7045 ret = GST_AUTOPLUG_SELECT_SKIP;
7049 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7050 /* hw codec will be skipped */
7051 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7052 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7053 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7054 ret = GST_AUTOPLUG_SELECT_SKIP;
7059 /* set stream information */
7060 if (!player->audiodec_linked)
7061 __mmplayer_set_audio_attrs(player, caps);
7063 /* update codec info */
7064 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7065 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7066 player->audiodec_linked = 1;
7068 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7070 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7072 LOGD("video codec type: %d", codec_type);
7073 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7074 /* sw codec is skipped */
7075 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7076 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7077 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7078 ret = GST_AUTOPLUG_SELECT_SKIP;
7082 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7083 /* hw codec is skipped */
7084 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7085 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7086 ret = GST_AUTOPLUG_SELECT_SKIP;
7091 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7092 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7094 /* mark video decoder for acquire */
7095 if (player->video_decoder_resource == NULL) {
7096 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7097 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7098 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7099 &player->video_decoder_resource)
7100 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7101 LOGE("could not mark video_decoder resource for acquire");
7102 ret = GST_AUTOPLUG_SELECT_SKIP;
7106 LOGW("video decoder resource is already acquired, skip it.");
7107 ret = GST_AUTOPLUG_SELECT_SKIP;
7111 player->interrupted_by_resource = FALSE;
7112 /* acquire resources for video playing */
7113 if (mm_resource_manager_commit(player->resource_manager)
7114 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7115 LOGE("could not acquire resources for video decoding");
7116 ret = GST_AUTOPLUG_SELECT_SKIP;
7121 /* update codec info */
7122 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7123 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7124 player->videodec_linked = 1;
7132 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7133 GstCaps *caps, GstElementFactory *factory, gpointer data)
7135 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7136 mm_player_t *player = (mm_player_t *)data;
7138 gchar *factory_name = NULL;
7139 gchar *caps_str = NULL;
7140 const gchar *klass = NULL;
7143 factory_name = GST_OBJECT_NAME(factory);
7144 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7145 caps_str = gst_caps_to_string(caps);
7147 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7149 /* store type string */
7150 if (player->type == NULL) {
7151 player->type = gst_caps_to_string(caps);
7152 __mmplayer_update_content_type_info(player);
7155 /* filtering exclude keyword */
7156 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7157 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7158 LOGW("skipping [%s] by exculde keyword [%s]",
7159 factory_name, player->ini.exclude_element_keyword[idx]);
7161 result = GST_AUTOPLUG_SELECT_SKIP;
7166 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7167 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7168 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7169 factory_name, player->ini.unsupported_codec_keyword[idx]);
7170 result = GST_AUTOPLUG_SELECT_SKIP;
7175 /* exclude webm format */
7176 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7177 * because webm format is not supportable.
7178 * If webm is disabled in "autoplug-continue", there is no state change
7179 * failure or error because the decodebin will expose the pad directly.
7180 * It make MSL invoke _prepare_async_callback.
7181 * So, we need to disable webm format in "autoplug-select" */
7182 if (caps_str && strstr(caps_str, "webm")) {
7183 LOGW("webm is not supported");
7184 result = GST_AUTOPLUG_SELECT_SKIP;
7188 /* check factory class for filtering */
7189 /* NOTE : msl don't need to use image plugins.
7190 * So, those plugins should be skipped for error handling.
7192 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7193 LOGD("skipping [%s] by not required", factory_name);
7194 result = GST_AUTOPLUG_SELECT_SKIP;
7198 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7199 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7200 // TO CHECK : subtitle if needed, add subparse exception.
7201 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7202 result = GST_AUTOPLUG_SELECT_SKIP;
7206 if (g_strrstr(factory_name, "mpegpsdemux")) {
7207 LOGD("skipping PS container - not support");
7208 result = GST_AUTOPLUG_SELECT_SKIP;
7212 if (g_strrstr(factory_name, "mssdemux"))
7213 player->smooth_streaming = TRUE;
7215 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7216 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7219 GstStructure *str = NULL;
7220 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7222 /* don't make video because of not required */
7223 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7224 (!player->set_mode.media_packet_video_stream)) {
7225 LOGD("no need video decoding, expose pad");
7226 result = GST_AUTOPLUG_SELECT_EXPOSE;
7230 /* get w/h for omx state-tune */
7231 /* FIXME: deprecated? */
7232 str = gst_caps_get_structure(caps, 0);
7233 gst_structure_get_int(str, "width", &width);
7236 if (player->v_stream_caps) {
7237 gst_caps_unref(player->v_stream_caps);
7238 player->v_stream_caps = NULL;
7241 player->v_stream_caps = gst_caps_copy(caps);
7242 LOGD("take caps for video state tune");
7243 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7247 if (g_strrstr(klass, "Codec/Decoder")) {
7248 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7249 if (result != GST_AUTOPLUG_SELECT_TRY) {
7250 LOGW("skip add decoder");
7256 MMPLAYER_FREEIF(caps_str);
7262 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7265 //mm_player_t *player = (mm_player_t *)data;
7266 GstCaps *caps = NULL;
7268 LOGD("[Decodebin2] pad-removed signal");
7270 caps = gst_pad_query_caps(new_pad, NULL);
7272 LOGW("query caps is NULL");
7276 gchar *caps_str = NULL;
7277 caps_str = gst_caps_to_string(caps);
7279 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7281 MMPLAYER_FREEIF(caps_str);
7282 gst_caps_unref(caps);
7286 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7288 mm_player_t *player = (mm_player_t *)data;
7289 GstIterator *iter = NULL;
7290 GValue item = { 0, };
7292 gboolean done = FALSE;
7293 gboolean is_all_drained = TRUE;
7296 MMPLAYER_RETURN_IF_FAIL(player);
7298 LOGD("__mmplayer_gst_decode_drained");
7300 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7301 LOGW("Fail to get cmd lock");
7305 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7306 !__mmplayer_verify_gapless_play_path(player)) {
7307 LOGD("decoding is finished.");
7308 __mmplayer_reset_gapless_state(player);
7309 MMPLAYER_CMD_UNLOCK(player);
7313 player->gapless.reconfigure = TRUE;
7315 /* check decodebin src pads whether they received EOS or not */
7316 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7319 switch (gst_iterator_next(iter, &item)) {
7320 case GST_ITERATOR_OK:
7321 pad = g_value_get_object(&item);
7322 if (pad && !GST_PAD_IS_EOS(pad)) {
7323 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7324 is_all_drained = FALSE;
7327 g_value_reset(&item);
7329 case GST_ITERATOR_RESYNC:
7330 gst_iterator_resync(iter);
7332 case GST_ITERATOR_ERROR:
7333 case GST_ITERATOR_DONE:
7338 g_value_unset(&item);
7339 gst_iterator_free(iter);
7341 if (!is_all_drained) {
7342 LOGD("Wait util the all pads get EOS.");
7343 MMPLAYER_CMD_UNLOCK(player);
7348 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7349 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7351 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7352 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7353 __mmplayer_deactivate_old_path(player);
7354 MMPLAYER_CMD_UNLOCK(player);
7360 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7362 mm_player_t *player = (mm_player_t *)data;
7363 const gchar *klass = NULL;
7364 gchar *factory_name = NULL;
7366 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7367 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7369 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7371 if (__mmplayer_add_dump_buffer_probe(player, element))
7372 LOGD("add buffer probe");
7374 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7375 gchar *selected = NULL;
7376 selected = g_strdup(GST_ELEMENT_NAME(element));
7377 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7380 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7381 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7382 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7384 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7385 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7387 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7388 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7389 "max-video-width", player->adaptive_info.limit.width,
7390 "max-video-height", player->adaptive_info.limit.height, NULL);
7392 } else if (g_strrstr(klass, "Demuxer")) {
7393 //LOGD("plugged element is demuxer. take it");
7394 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7395 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7398 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7399 int surface_type = 0;
7401 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7404 // to support trust-zone only
7405 if (g_strrstr(factory_name, "asfdemux")) {
7406 LOGD("set file-location %s", player->profile.uri);
7407 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7408 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7409 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7410 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7411 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7412 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7413 (__mmplayer_is_only_mp3_type(player->type))) {
7414 LOGD("[mpegaudioparse] set streaming pull mode.");
7415 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7417 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7418 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7421 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7422 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7423 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7425 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7426 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7428 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7429 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7430 (MMPLAYER_IS_DASH_STREAMING(player))) {
7431 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7432 __mm_player_streaming_set_multiqueue(player->streamer, element);
7433 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7442 __mmplayer_release_misc(mm_player_t *player)
7445 bool cur_mode = player->set_mode.rich_audio;
7448 MMPLAYER_RETURN_IF_FAIL(player);
7450 player->video_stream_cb = NULL;
7451 player->video_stream_cb_user_param = NULL;
7452 player->video_stream_prerolled = false;
7454 player->audio_stream_render_cb = NULL;
7455 player->audio_stream_cb_user_param = NULL;
7456 player->audio_stream_sink_sync = false;
7458 player->video_stream_changed_cb = NULL;
7459 player->video_stream_changed_cb_user_param = NULL;
7461 player->audio_stream_changed_cb = NULL;
7462 player->audio_stream_changed_cb_user_param = NULL;
7464 player->sent_bos = FALSE;
7465 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7467 player->seek_state = MMPLAYER_SEEK_NONE;
7469 player->total_bitrate = 0;
7470 player->total_maximum_bitrate = 0;
7472 player->not_found_demuxer = 0;
7474 player->last_position = 0;
7475 player->duration = 0;
7476 player->http_content_size = 0;
7477 player->not_supported_codec = MISSING_PLUGIN_NONE;
7478 player->can_support_codec = FOUND_PLUGIN_NONE;
7479 player->pending_seek.is_pending = false;
7480 player->pending_seek.pos = 0;
7481 player->msg_posted = FALSE;
7482 player->has_many_types = FALSE;
7483 player->is_subtitle_force_drop = FALSE;
7484 player->play_subtitle = FALSE;
7485 player->adjust_subtitle_pos = 0;
7486 player->has_closed_caption = FALSE;
7487 player->set_mode.media_packet_video_stream = false;
7488 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7489 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7491 player->set_mode.rich_audio = cur_mode;
7493 if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7494 LOGW("failed to remove audio device_connected_callback");
7495 player->audio_device_cb_id = 0;
7497 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7498 player->bitrate[i] = 0;
7499 player->maximum_bitrate[i] = 0;
7502 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7504 /* remove media stream cb(appsrc cb) */
7505 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7506 player->media_stream_buffer_status_cb[i] = NULL;
7507 player->media_stream_seek_data_cb[i] = NULL;
7508 player->buffer_cb_user_param[i] = NULL;
7509 player->seek_cb_user_param[i] = NULL;
7511 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7513 /* free memory related to audio effect */
7514 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7516 if (player->adaptive_info.var_list) {
7517 g_list_free_full(player->adaptive_info.var_list, g_free);
7518 player->adaptive_info.var_list = NULL;
7521 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7522 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7523 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7525 /* Reset video360 settings to their defaults in case if the pipeline is to be
7528 player->video360_metadata.is_spherical = -1;
7529 player->is_openal_plugin_used = FALSE;
7531 player->is_content_spherical = FALSE;
7532 player->is_video360_enabled = TRUE;
7533 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7534 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7535 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7536 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7537 player->video360_zoom = 1.0f;
7538 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7539 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7541 player->sound.rg_enable = false;
7543 __mmplayer_initialize_video_roi(player);
7548 __mmplayer_release_misc_post(mm_player_t *player)
7550 char *original_uri = NULL;
7553 /* player->pipeline is already released before. */
7555 MMPLAYER_RETURN_IF_FAIL(player);
7557 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7559 /* clean found audio decoders */
7560 if (player->audio_decoders) {
7561 GList *a_dec = player->audio_decoders;
7562 for (; a_dec; a_dec = g_list_next(a_dec)) {
7563 gchar *name = a_dec->data;
7564 MMPLAYER_FREEIF(name);
7566 g_list_free(player->audio_decoders);
7567 player->audio_decoders = NULL;
7570 /* clean the uri list except original uri */
7571 if (player->uri_info.uri_list) {
7572 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7574 if (player->attrs) {
7575 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7576 LOGD("restore original uri = %s", original_uri);
7578 if (mm_attrs_commit_all(player->attrs))
7579 LOGE("failed to commit the original uri.");
7582 GList *uri_list = player->uri_info.uri_list;
7583 for (; uri_list; uri_list = g_list_next(uri_list)) {
7584 gchar *uri = uri_list->data;
7585 MMPLAYER_FREEIF(uri);
7587 g_list_free(player->uri_info.uri_list);
7588 player->uri_info.uri_list = NULL;
7591 /* clear the audio stream buffer list */
7592 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7594 /* clear the video stream bo list */
7595 __mmplayer_video_stream_destroy_bo_list(player);
7596 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7598 if (player->profile.input_mem.buf) {
7599 free(player->profile.input_mem.buf);
7600 player->profile.input_mem.buf = NULL;
7602 player->profile.input_mem.len = 0;
7603 player->profile.input_mem.offset = 0;
7605 player->uri_info.uri_idx = 0;
7610 __mmplayer_check_subtitle(mm_player_t *player)
7612 MMHandleType attrs = 0;
7613 char *subtitle_uri = NULL;
7617 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7619 /* get subtitle attribute */
7620 attrs = MMPLAYER_GET_ATTRS(player);
7624 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7625 if (!subtitle_uri || !strlen(subtitle_uri))
7628 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7629 player->is_external_subtitle_present = TRUE;
7637 __mmplayer_cancel_eos_timer(mm_player_t *player)
7639 MMPLAYER_RETURN_IF_FAIL(player);
7641 if (player->eos_timer) {
7642 LOGD("cancel eos timer");
7643 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7644 player->eos_timer = 0;
7651 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7655 MMPLAYER_RETURN_IF_FAIL(player);
7656 MMPLAYER_RETURN_IF_FAIL(sink);
7658 player->sink_elements = g_list_append(player->sink_elements, sink);
7664 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7668 MMPLAYER_RETURN_IF_FAIL(player);
7669 MMPLAYER_RETURN_IF_FAIL(sink);
7671 player->sink_elements = g_list_remove(player->sink_elements, sink);
7677 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7678 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7680 MMPlayerSignalItem *item = NULL;
7683 MMPLAYER_RETURN_IF_FAIL(player);
7685 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7686 LOGE("invalid signal type [%d]", type);
7690 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7692 LOGE("cannot connect signal [%s]", signal);
7697 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7698 player->signals[type] = g_list_append(player->signals[type], item);
7704 /* NOTE : be careful with calling this api. please refer to below glib comment
7705 * glib comment : Note that there is a bug in GObject that makes this function much
7706 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7707 * will no longer be called, but, the signal handler is not currently disconnected.
7708 * If the instance is itself being freed at the same time than this doesn't matter,
7709 * since the signal will automatically be removed, but if instance persists,
7710 * then the signal handler will leak. You should not remove the signal yourself
7711 * because in a future versions of GObject, the handler will automatically be
7714 * It's possible to work around this problem in a way that will continue to work
7715 * with future versions of GObject by checking that the signal handler is still
7716 * connected before disconnected it:
7718 * if (g_signal_handler_is_connected(instance, id))
7719 * g_signal_handler_disconnect(instance, id);
7722 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7724 GList *sig_list = NULL;
7725 MMPlayerSignalItem *item = NULL;
7729 MMPLAYER_RETURN_IF_FAIL(player);
7731 LOGD("release signals type : %d", type);
7733 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7734 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7735 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7736 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7737 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7738 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7742 sig_list = player->signals[type];
7744 for (; sig_list; sig_list = sig_list->next) {
7745 item = sig_list->data;
7747 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7748 if (g_signal_handler_is_connected(item->obj, item->sig))
7749 g_signal_handler_disconnect(item->obj, item->sig);
7752 MMPLAYER_FREEIF(item);
7755 g_list_free(player->signals[type]);
7756 player->signals[type] = NULL;
7764 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7766 mm_player_t *player = 0;
7767 int prev_display_surface_type = 0;
7768 void *prev_display_overlay = NULL;
7772 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7773 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7775 player = MM_PLAYER_CAST(handle);
7777 /* check video sinkbin is created */
7778 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7779 LOGE("Videosink is already created");
7780 return MM_ERROR_NONE;
7783 LOGD("videosink element is not yet ready");
7785 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7786 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7788 return MM_ERROR_INVALID_ARGUMENT;
7791 /* load previous attributes */
7792 if (player->attrs) {
7793 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7794 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7795 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7796 if (prev_display_surface_type == surface_type) {
7797 LOGD("incoming display surface type is same as previous one, do nothing..");
7799 return MM_ERROR_NONE;
7802 LOGE("failed to load attributes");
7804 return MM_ERROR_PLAYER_INTERNAL;
7807 /* videobin is not created yet, so we just set attributes related to display surface */
7808 LOGD("store display attribute for given surface type(%d)", surface_type);
7809 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7810 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7811 if (mm_attrs_commit_all(player->attrs)) {
7812 LOGE("failed to commit attribute");
7814 return MM_ERROR_PLAYER_INTERNAL;
7818 return MM_ERROR_NONE;
7821 /* Note : if silent is true, then subtitle would not be displayed. :*/
7823 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7825 mm_player_t *player = (mm_player_t *)hplayer;
7829 /* check player handle */
7830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7832 player->set_mode.subtitle_off = silent;
7834 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7838 return MM_ERROR_NONE;
7842 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7844 MMPlayerGstElement *mainbin = NULL;
7845 MMPlayerGstElement *textbin = NULL;
7846 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7847 GstState current_state = GST_STATE_VOID_PENDING;
7848 GstState element_state = GST_STATE_VOID_PENDING;
7849 GstState element_pending_state = GST_STATE_VOID_PENDING;
7851 GstEvent *event = NULL;
7852 int result = MM_ERROR_NONE;
7854 GstClock *curr_clock = NULL;
7855 GstClockTime base_time, start_time, curr_time;
7860 /* check player handle */
7861 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7863 player->pipeline->mainbin &&
7864 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7866 mainbin = player->pipeline->mainbin;
7867 textbin = player->pipeline->textbin;
7869 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7871 // sync clock with current pipeline
7872 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7873 curr_time = gst_clock_get_time(curr_clock);
7875 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7876 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7878 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7879 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7881 if (current_state > GST_STATE_READY) {
7882 // sync state with current pipeline
7883 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7884 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7885 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7887 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7888 if (GST_STATE_CHANGE_FAILURE == ret) {
7889 LOGE("fail to state change.");
7890 result = MM_ERROR_PLAYER_INTERNAL;
7894 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7895 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7898 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7899 gst_object_unref(curr_clock);
7902 // seek to current position
7903 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7904 result = MM_ERROR_PLAYER_INVALID_STATE;
7905 LOGE("gst_element_query_position failed, invalid state");
7909 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7910 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);
7912 __mmplayer_gst_send_event_to_sink(player, event);
7914 result = MM_ERROR_PLAYER_INTERNAL;
7915 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7919 /* sync state with current pipeline */
7920 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7921 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7922 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7924 return MM_ERROR_NONE;
7927 /* release text pipeline resource */
7928 player->textsink_linked = 0;
7930 /* release signal */
7931 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7933 /* release textbin with it's childs */
7934 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7935 MMPLAYER_FREEIF(player->pipeline->textbin);
7936 player->pipeline->textbin = NULL;
7938 /* release subtitle elem */
7939 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7940 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7946 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7948 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7949 GstState current_state = GST_STATE_VOID_PENDING;
7951 MMHandleType attrs = 0;
7952 MMPlayerGstElement *mainbin = NULL;
7953 MMPlayerGstElement *textbin = NULL;
7955 gchar *subtitle_uri = NULL;
7956 int result = MM_ERROR_NONE;
7957 const gchar *charset = NULL;
7961 /* check player handle */
7962 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7964 player->pipeline->mainbin &&
7965 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7966 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7968 mainbin = player->pipeline->mainbin;
7969 textbin = player->pipeline->textbin;
7971 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7972 if (current_state < GST_STATE_READY) {
7973 result = MM_ERROR_PLAYER_INVALID_STATE;
7974 LOGE("Pipeline is not in proper state");
7978 attrs = MMPLAYER_GET_ATTRS(player);
7980 LOGE("cannot get content attribute");
7981 result = MM_ERROR_PLAYER_INTERNAL;
7985 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7986 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7987 LOGE("subtitle uri is not proper filepath");
7988 result = MM_ERROR_PLAYER_INVALID_URI;
7992 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7993 LOGE("failed to get storage info of subtitle path");
7994 result = MM_ERROR_PLAYER_INVALID_URI;
7998 LOGD("old subtitle file path is [%s]", subtitle_uri);
7999 LOGD("new subtitle file path is [%s]", filepath);
8001 if (!strcmp(filepath, subtitle_uri)) {
8002 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8005 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8006 if (mm_attrs_commit_all(player->attrs)) {
8007 LOGE("failed to commit.");
8012 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8013 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8014 player->subtitle_language_list = NULL;
8015 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8017 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8018 if (ret != GST_STATE_CHANGE_SUCCESS) {
8019 LOGE("failed to change state of textbin to READY");
8020 result = MM_ERROR_PLAYER_INTERNAL;
8024 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8025 if (ret != GST_STATE_CHANGE_SUCCESS) {
8026 LOGE("failed to change state of subparse to READY");
8027 result = MM_ERROR_PLAYER_INTERNAL;
8031 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8032 if (ret != GST_STATE_CHANGE_SUCCESS) {
8033 LOGE("failed to change state of filesrc to READY");
8034 result = MM_ERROR_PLAYER_INTERNAL;
8038 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8040 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8042 charset = util_get_charset(filepath);
8044 LOGD("detected charset is %s", charset);
8045 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8048 result = _mmplayer_sync_subtitle_pipeline(player);
8055 /* API to switch between external subtitles */
8057 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8059 int result = MM_ERROR_NONE;
8060 mm_player_t *player = (mm_player_t *)hplayer;
8065 /* check player handle */
8066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8068 /* filepath can be null in idle state */
8070 /* check file path */
8071 if ((path = strstr(filepath, "file://")))
8072 result = util_exist_file_path(path + 7);
8074 result = util_exist_file_path(filepath);
8076 if (result != MM_ERROR_NONE) {
8077 LOGE("invalid subtitle path 0x%X", result);
8078 return result; /* file not found or permission denied */
8082 if (!player->pipeline) {
8084 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8085 if (mm_attrs_commit_all(player->attrs)) {
8086 LOGE("failed to commit"); /* subtitle path will not be created */
8087 return MM_ERROR_PLAYER_INTERNAL;
8090 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8091 /* check filepath */
8092 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8094 if (!__mmplayer_check_subtitle(player)) {
8095 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8096 if (mm_attrs_commit_all(player->attrs)) {
8097 LOGE("failed to commit");
8098 return MM_ERROR_PLAYER_INTERNAL;
8101 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8102 LOGE("fail to create text pipeline");
8103 return MM_ERROR_PLAYER_INTERNAL;
8106 result = _mmplayer_sync_subtitle_pipeline(player);
8108 result = __mmplayer_change_external_subtitle_language(player, filepath);
8111 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8112 player->is_external_subtitle_added_now = TRUE;
8114 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8115 if (!player->subtitle_language_list) {
8116 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8117 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8118 LOGW("subtitle language list is not updated yet");
8120 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8128 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
8130 int result = MM_ERROR_NONE;
8131 gchar *change_pad_name = NULL;
8132 GstPad *sinkpad = NULL;
8133 MMPlayerGstElement *mainbin = NULL;
8134 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8135 GstCaps *caps = NULL;
8136 gint total_track_num = 0;
8140 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8141 MM_ERROR_PLAYER_NOT_INITIALIZED);
8143 LOGD("Change Track(%d) to %d", type, index);
8145 mainbin = player->pipeline->mainbin;
8147 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8148 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8149 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8150 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8152 /* Changing Video Track is not supported. */
8153 LOGE("Track Type Error");
8157 if (mainbin[elem_idx].gst == NULL) {
8158 result = MM_ERROR_PLAYER_NO_OP;
8159 LOGD("Req track doesn't exist");
8163 total_track_num = player->selector[type].total_track_num;
8164 if (total_track_num <= 0) {
8165 result = MM_ERROR_PLAYER_NO_OP;
8166 LOGD("Language list is not available");
8170 if ((index < 0) || (index >= total_track_num)) {
8171 result = MM_ERROR_INVALID_ARGUMENT;
8172 LOGD("Not a proper index : %d", index);
8176 /*To get the new pad from the selector*/
8177 change_pad_name = g_strdup_printf("sink_%u", index);
8178 if (change_pad_name == NULL) {
8179 result = MM_ERROR_PLAYER_INTERNAL;
8180 LOGD("Pad does not exists");
8184 LOGD("new active pad name: %s", change_pad_name);
8186 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8187 if (sinkpad == NULL) {
8188 LOGD("sinkpad is NULL");
8189 result = MM_ERROR_PLAYER_INTERNAL;
8193 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8194 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8196 caps = gst_pad_get_current_caps(sinkpad);
8197 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8200 gst_object_unref(sinkpad);
8202 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8203 __mmplayer_set_audio_attrs(player, caps);
8206 MMPLAYER_FREEIF(change_pad_name);
8211 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8213 int result = MM_ERROR_NONE;
8214 mm_player_t *player = NULL;
8215 MMPlayerGstElement *mainbin = NULL;
8217 gint current_active_index = 0;
8219 GstState current_state = GST_STATE_VOID_PENDING;
8220 GstEvent *event = NULL;
8225 player = (mm_player_t *)hplayer;
8226 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8228 if (!player->pipeline) {
8229 LOGE("Track %d pre setting -> %d", type, index);
8231 player->selector[type].active_pad_index = index;
8235 mainbin = player->pipeline->mainbin;
8237 current_active_index = player->selector[type].active_pad_index;
8239 /*If index is same as running index no need to change the pad*/
8240 if (current_active_index == index)
8243 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8244 result = MM_ERROR_PLAYER_INVALID_STATE;
8248 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8249 if (current_state < GST_STATE_PAUSED) {
8250 result = MM_ERROR_PLAYER_INVALID_STATE;
8251 LOGW("Pipeline not in porper state");
8255 result = __mmplayer_change_selector_pad(player, type, index);
8256 if (result != MM_ERROR_NONE) {
8257 LOGE("change selector pad error");
8261 player->selector[type].active_pad_index = index;
8263 if (current_state == GST_STATE_PLAYING) {
8264 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8265 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8266 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8268 __mmplayer_gst_send_event_to_sink(player, event);
8270 result = MM_ERROR_PLAYER_INTERNAL;
8280 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8282 mm_player_t *player = (mm_player_t *)hplayer;
8286 /* check player handle */
8287 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8289 *silent = player->set_mode.subtitle_off;
8291 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8295 return MM_ERROR_NONE;
8299 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8301 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8302 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8304 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8305 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8309 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8310 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8311 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8312 mm_player_dump_t *dump_s;
8313 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8314 if (dump_s == NULL) {
8315 LOGE("malloc fail");
8319 dump_s->dump_element_file = NULL;
8320 dump_s->dump_pad = NULL;
8321 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8323 if (dump_s->dump_pad) {
8324 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8325 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]);
8326 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8327 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);
8328 /* add list for removed buffer probe and close FILE */
8329 player->dump_list = g_list_append(player->dump_list, dump_s);
8330 LOGD("%s sink pad added buffer probe for dump", factory_name);
8333 MMPLAYER_FREEIF(dump_s);
8334 LOGE("failed to get %s sink pad added", factory_name);
8341 static GstPadProbeReturn
8342 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8344 FILE *dump_data = (FILE *)u_data;
8346 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8347 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8349 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8351 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8353 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8355 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8357 return GST_PAD_PROBE_OK;
8361 __mmplayer_release_dump_list(GList *dump_list)
8363 GList *d_list = dump_list;
8368 for (; d_list; d_list = g_list_next(d_list)) {
8369 mm_player_dump_t *dump_s = d_list->data;
8370 if (dump_s->dump_pad) {
8371 if (dump_s->probe_handle_id)
8372 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8373 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8375 if (dump_s->dump_element_file) {
8376 fclose(dump_s->dump_element_file);
8377 dump_s->dump_element_file = NULL;
8379 MMPLAYER_FREEIF(dump_s);
8381 g_list_free(dump_list);
8386 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8388 mm_player_t *player = (mm_player_t *)hplayer;
8392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8393 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8395 *exist = (bool)player->has_closed_caption;
8399 return MM_ERROR_NONE;
8403 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8407 // LOGD("unref internal gst buffer %p", buffer);
8408 gst_buffer_unref((GstBuffer *)buffer);
8415 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8417 mm_player_t *player = (mm_player_t *)hplayer;
8421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8422 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8424 if (MMPLAYER_IS_STREAMING(player))
8425 *timeout = (int)player->ini.live_state_change_timeout;
8427 *timeout = (int)player->ini.localplayback_state_change_timeout;
8429 LOGD("timeout = %d", *timeout);
8432 return MM_ERROR_NONE;
8436 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8438 mm_player_t *player = (mm_player_t *)hplayer;
8442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8443 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8445 *num = player->video_num_buffers;
8446 *extra_num = player->video_extra_num_buffers;
8448 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8451 return MM_ERROR_NONE;
8455 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8459 MMPLAYER_RETURN_IF_FAIL(player);
8461 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8463 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8464 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8465 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8466 player->storage_info[i].id = -1;
8467 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8469 if (path_type != MMPLAYER_PATH_MAX)
8478 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8480 int ret = MM_ERROR_NONE;
8481 mm_player_t *player = (mm_player_t *)hplayer;
8482 MMMessageParamType msg_param = {0, };
8485 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8487 LOGW("state changed storage %d:%d", id, state);
8489 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8490 return MM_ERROR_NONE;
8492 /* FIXME: text path should be handled seperately. */
8493 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8494 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8495 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8496 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8497 LOGW("external storage is removed");
8499 if (player->msg_posted == FALSE) {
8500 memset(&msg_param, 0, sizeof(MMMessageParamType));
8501 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8502 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8503 player->msg_posted = TRUE;
8506 /* unrealize the player */
8507 ret = _mmplayer_unrealize(hplayer);
8508 if (ret != MM_ERROR_NONE)
8509 LOGE("failed to unrealize");
8517 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8519 int ret = MM_ERROR_NONE;
8520 mm_player_t *player = (mm_player_t *)hplayer;
8521 int idx = 0, total = 0;
8522 gchar *result = NULL, *tmp = NULL;
8525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8528 total = *num = g_list_length(player->adaptive_info.var_list);
8530 LOGW("There is no stream variant info.");
8534 result = g_strdup("");
8535 for (idx = 0 ; idx < total ; idx++) {
8536 VariantData *v_data = NULL;
8537 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8540 gchar data[64] = {0};
8541 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8543 tmp = g_strconcat(result, data, NULL);
8547 LOGW("There is no variant data in %d", idx);
8552 *var_info = (char *)result;
8554 LOGD("variant info %d:%s", *num, *var_info);
8560 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8562 int ret = MM_ERROR_NONE;
8563 mm_player_t *player = (mm_player_t *)hplayer;
8566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8568 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8570 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8571 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8572 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8574 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8575 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8576 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8577 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8579 /* FIXME: seek to current position for applying new variant limitation */
8588 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8590 int ret = MM_ERROR_NONE;
8591 mm_player_t *player = (mm_player_t *)hplayer;
8594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8597 *bandwidth = player->adaptive_info.limit.bandwidth;
8598 *width = player->adaptive_info.limit.width;
8599 *height = player->adaptive_info.limit.height;
8601 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8608 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8610 int ret = MM_ERROR_NONE;
8611 mm_player_t *player = (mm_player_t *)hplayer;
8614 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8615 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8616 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8618 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8620 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8621 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8622 else /* live case */
8623 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8625 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8632 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8634 #define IDX_FIRST_SW_CODEC 0
8635 mm_player_t *player = (mm_player_t *)hplayer;
8636 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8637 MMHandleType attrs = 0;
8640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8642 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8643 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8644 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8646 switch (stream_type) {
8647 case MM_PLAYER_STREAM_TYPE_AUDIO:
8648 /* to support audio codec selection, codec info have to be added in ini file as below.
8649 audio codec element hw = xxxx
8650 audio codec element sw = avdec */
8651 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8652 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8653 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8654 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8655 LOGE("There is no audio codec info for codec_type %d", codec_type);
8656 return MM_ERROR_PLAYER_NO_OP;
8659 case MM_PLAYER_STREAM_TYPE_VIDEO:
8660 /* to support video codec selection, codec info have to be added in ini file as below.
8661 video codec element hw = omx
8662 video codec element sw = avdec */
8663 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8664 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8665 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8666 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8667 LOGE("There is no video codec info for codec_type %d", codec_type);
8668 return MM_ERROR_PLAYER_NO_OP;
8672 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8673 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8677 LOGD("update %s codec_type to %d", attr_name, codec_type);
8679 attrs = MMPLAYER_GET_ATTRS(player);
8680 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8682 if (mm_attrs_commit_all(player->attrs)) {
8683 LOGE("failed to commit codec_type attributes");
8684 return MM_ERROR_PLAYER_INTERNAL;
8688 return MM_ERROR_NONE;
8692 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8694 mm_player_t *player = (mm_player_t *)hplayer;
8695 GstElement *rg_vol_element = NULL;
8699 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8701 player->sound.rg_enable = enabled;
8703 /* just hold rgvolume enable value if pipeline is not ready */
8704 if (!player->pipeline || !player->pipeline->audiobin) {
8705 LOGD("pipeline is not ready. holding rgvolume enable value");
8706 return MM_ERROR_NONE;
8709 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8711 if (!rg_vol_element) {
8712 LOGD("rgvolume element is not created");
8713 return MM_ERROR_PLAYER_INTERNAL;
8717 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8719 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8723 return MM_ERROR_NONE;
8727 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8729 mm_player_t *player = (mm_player_t *)hplayer;
8730 GstElement *rg_vol_element = NULL;
8731 gboolean enable = FALSE;
8735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8738 /* just hold enable_rg value if pipeline is not ready */
8739 if (!player->pipeline || !player->pipeline->audiobin) {
8740 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8741 *enabled = player->sound.rg_enable;
8742 return MM_ERROR_NONE;
8745 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8747 if (!rg_vol_element) {
8748 LOGD("rgvolume element is not created");
8749 return MM_ERROR_PLAYER_INTERNAL;
8752 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8753 *enabled = (bool)enable;
8757 return MM_ERROR_NONE;
8761 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8763 mm_player_t *player = (mm_player_t *)hplayer;
8764 MMHandleType attrs = 0;
8765 void *handle = NULL;
8766 int ret = MM_ERROR_NONE;
8770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8772 attrs = MMPLAYER_GET_ATTRS(player);
8773 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8775 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8777 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8778 return MM_ERROR_PLAYER_INTERNAL;
8781 player->video_roi.scale_x = scale_x;
8782 player->video_roi.scale_y = scale_y;
8783 player->video_roi.scale_width = scale_width;
8784 player->video_roi.scale_height = scale_height;
8786 /* check video sinkbin is created */
8787 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8788 return MM_ERROR_NONE;
8790 if (!gst_video_overlay_set_video_roi_area(
8791 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8792 scale_x, scale_y, scale_width, scale_height))
8793 ret = MM_ERROR_PLAYER_INTERNAL;
8795 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8796 scale_x, scale_y, scale_width, scale_height);
8804 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8806 mm_player_t *player = (mm_player_t *)hplayer;
8807 int ret = MM_ERROR_NONE;
8811 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8814 *scale_x = player->video_roi.scale_x;
8815 *scale_y = player->video_roi.scale_y;
8816 *scale_width = player->video_roi.scale_width;
8817 *scale_height = player->video_roi.scale_height;
8819 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8820 *scale_x, *scale_y, *scale_width, *scale_height);
8826 __mmplayer_update_duration_value(mm_player_t *player)
8828 gboolean ret = FALSE;
8829 gint64 dur_nsec = 0;
8830 LOGD("try to update duration");
8832 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8833 player->duration = dur_nsec;
8834 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8838 if (player->duration < 0) {
8839 LOGW("duration is Non-Initialized !!!");
8840 player->duration = 0;
8843 /* update streaming service type */
8844 player->streaming_type = __mmplayer_get_stream_service_type(player);
8846 /* check duration is OK */
8847 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8848 /* FIXIT : find another way to get duration here. */
8849 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8855 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8857 /* update audio params
8858 NOTE : We need original audio params and it can be only obtained from src pad of audio
8859 decoder. Below code only valid when we are not using 'resampler' just before
8860 'audioconverter'. */
8861 GstCaps *caps_a = NULL;
8863 gint samplerate = 0, channels = 0;
8864 GstStructure *p = NULL;
8866 LOGD("try to update audio attrs");
8868 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8869 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8871 pad = gst_element_get_static_pad(
8872 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8875 LOGW("failed to get pad from audiosink");
8879 caps_a = gst_pad_get_current_caps(pad);
8881 LOGW("not ready to get audio caps");
8882 gst_object_unref(pad);
8886 p = gst_caps_get_structure(caps_a, 0);
8888 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8890 gst_structure_get_int(p, "rate", &samplerate);
8891 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8893 gst_structure_get_int(p, "channels", &channels);
8894 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8896 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8898 gst_caps_unref(caps_a);
8899 gst_object_unref(pad);
8905 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8907 LOGD("try to update video attrs");
8909 GstCaps *caps_v = NULL;
8913 GstStructure *p = NULL;
8915 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8916 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8918 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8920 LOGD("no videosink sink pad");
8924 caps_v = gst_pad_get_current_caps(pad);
8925 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8926 if (!caps_v && player->v_stream_caps) {
8927 caps_v = player->v_stream_caps;
8928 gst_caps_ref(caps_v);
8932 LOGD("no negitiated caps from videosink");
8933 gst_object_unref(pad);
8937 p = gst_caps_get_structure(caps_v, 0);
8938 gst_structure_get_int(p, "width", &width);
8939 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8941 gst_structure_get_int(p, "height", &height);
8942 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8944 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8946 SECURE_LOGD("width : %d height : %d", width, height);
8948 gst_caps_unref(caps_v);
8949 gst_object_unref(pad);
8952 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8953 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8960 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8962 gboolean ret = FALSE;
8963 guint64 data_size = 0;
8967 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8968 if (!player->duration)
8971 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8972 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8973 if (stat(path, &sb) == 0)
8974 data_size = (guint64)sb.st_size;
8976 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8977 data_size = player->http_content_size;
8980 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8983 guint64 bitrate = 0;
8984 guint64 msec_dur = 0;
8986 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8988 bitrate = data_size * 8 * 1000 / msec_dur;
8989 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8990 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8994 LOGD("player duration is less than 0");
8998 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8999 if (player->total_bitrate) {
9000 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9009 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
9011 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9012 data->uri_type = uri_type;
9016 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
9018 int ret = MM_ERROR_PLAYER_INVALID_URI;
9020 char *buffer = NULL;
9021 char *seperator = strchr(path, ',');
9022 char ext[100] = {0,}, size[100] = {0,};
9025 if ((buffer = strstr(path, "ext="))) {
9026 buffer += strlen("ext=");
9028 if (strlen(buffer)) {
9029 strncpy(ext, buffer, 99);
9031 if ((seperator = strchr(ext, ','))
9032 || (seperator = strchr(ext, ' '))
9033 || (seperator = strchr(ext, '\0'))) {
9034 seperator[0] = '\0';
9039 if ((buffer = strstr(path, "size="))) {
9040 buffer += strlen("size=");
9042 if (strlen(buffer) > 0) {
9043 strncpy(size, buffer, 99);
9045 if ((seperator = strchr(size, ','))
9046 || (seperator = strchr(size, ' '))
9047 || (seperator = strchr(size, '\0'))) {
9048 seperator[0] = '\0';
9051 mem_size = atoi(size);
9056 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9058 if (mem_size && param) {
9059 if (data->input_mem.buf)
9060 free(data->input_mem.buf);
9061 data->input_mem.buf = malloc(mem_size);
9063 if (data->input_mem.buf) {
9064 memcpy(data->input_mem.buf, param, mem_size);
9065 data->input_mem.len = mem_size;
9066 ret = MM_ERROR_NONE;
9068 LOGE("failed to alloc mem %d", mem_size);
9069 ret = MM_ERROR_PLAYER_INTERNAL;
9072 data->input_mem.offset = 0;
9073 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9080 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
9082 gchar *location = NULL;
9085 int ret = MM_ERROR_NONE;
9087 if ((path = strstr(uri, "file://"))) {
9088 location = g_filename_from_uri(uri, NULL, &err);
9089 if (!location || (err != NULL)) {
9090 LOGE("Invalid URI '%s' for filesrc: %s", path,
9091 (err != NULL) ? err->message : "unknown error");
9095 MMPLAYER_FREEIF(location);
9097 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9098 return MM_ERROR_PLAYER_INVALID_URI;
9100 LOGD("path from uri: %s", location);
9103 path = (location != NULL) ? (location) : ((char *)uri);
9106 ret = util_exist_file_path(path);
9108 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9109 if (ret == MM_ERROR_NONE) {
9110 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9111 if (util_is_sdp_file(path)) {
9112 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9113 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9115 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9117 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9118 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9120 LOGE("invalid uri, could not play..");
9121 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9124 MMPLAYER_FREEIF(location);
9129 static MMPlayerVideoStreamDataType *
9130 __mmplayer_create_stream_from_pad(GstPad *pad)
9132 GstCaps *caps = NULL;
9133 GstStructure *structure = NULL;
9134 unsigned int fourcc = 0;
9135 const gchar *string_format = NULL;
9136 MMPlayerVideoStreamDataType *stream = NULL;
9138 MMPixelFormatType format;
9140 caps = gst_pad_get_current_caps(pad);
9142 LOGE("Caps is NULL.");
9146 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9147 structure = gst_caps_get_structure(caps, 0);
9148 gst_structure_get_int(structure, "width", &width);
9149 gst_structure_get_int(structure, "height", &height);
9150 string_format = gst_structure_get_string(structure, "format");
9152 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9153 format = util_get_pixtype(fourcc);
9154 gst_caps_unref(caps);
9157 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9158 LOGE("Wrong condition!!");
9162 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9164 LOGE("failed to alloc mem for video data");
9168 stream->width = width;
9169 stream->height = height;
9170 stream->format = format;
9176 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9178 unsigned int pitch = 0;
9180 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9182 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9183 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9184 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9185 stream->stride[index] = pitch;
9186 stream->elevation[index] = stream->height;
9191 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9193 if (stream->format == MM_PIXEL_FORMAT_I420) {
9194 int ret = TBM_SURFACE_ERROR_NONE;
9195 tbm_surface_h surface;
9196 tbm_surface_info_s info;
9198 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9200 ret = tbm_surface_get_info(surface, &info);
9201 if (ret != TBM_SURFACE_ERROR_NONE) {
9202 tbm_surface_destroy(surface);
9206 tbm_surface_destroy(surface);
9207 stream->stride[0] = info.planes[0].stride;
9208 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9209 stream->stride[1] = info.planes[1].stride;
9210 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9211 stream->stride[2] = info.planes[2].stride;
9212 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9213 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9214 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9215 stream->stride[0] = stream->width * 4;
9216 stream->elevation[0] = stream->height;
9217 stream->bo_size = stream->stride[0] * stream->height;
9219 LOGE("Not support format %d", stream->format);
9227 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9229 tbm_bo_handle thandle;
9231 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9232 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9233 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9237 unsigned char *src = NULL;
9238 unsigned char *dest = NULL;
9239 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9241 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9243 LOGE("fail to gst_memory_map");
9247 if (!mapinfo.data) {
9248 LOGE("data pointer is wrong");
9252 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9253 if (!stream->bo[0]) {
9254 LOGE("Fail to tbm_bo_alloc!!");
9258 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9260 LOGE("thandle pointer is wrong");
9264 if (stream->format == MM_PIXEL_FORMAT_I420) {
9265 src_stride[0] = GST_ROUND_UP_4(stream->width);
9266 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9267 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9268 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9271 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9272 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9274 for (i = 0; i < 3; i++) {
9275 src = mapinfo.data + src_offset[i];
9276 dest = thandle.ptr + dest_offset[i];
9281 for (j = 0; j < stream->height >> k; j++) {
9282 memcpy(dest, src, stream->width>>k);
9283 src += src_stride[i];
9284 dest += stream->stride[i];
9287 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9288 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9290 LOGE("Not support format %d", stream->format);
9294 tbm_bo_unmap(stream->bo[0]);
9295 gst_memory_unmap(mem, &mapinfo);
9301 tbm_bo_unmap(stream->bo[0]);
9304 gst_memory_unmap(mem, &mapinfo);
9310 __mmplayer_set_pause_state(mm_player_t *player)
9312 if (player->sent_bos)
9315 /* rtsp case, get content attrs by GstMessage */
9316 if (MMPLAYER_IS_RTSP_STREAMING(player))
9319 /* it's first time to update all content attrs. */
9320 __mmplayer_update_content_attrs(player, ATTR_ALL);
9324 __mmplayer_set_playing_state(mm_player_t *player)
9326 gchar *audio_codec = NULL;
9328 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9329 /* initialize because auto resume is done well. */
9330 player->resumed_by_rewind = FALSE;
9331 player->playback_rate = 1.0;
9334 if (player->sent_bos)
9337 /* try to get content metadata */
9339 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9340 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9341 * legacy mmfw-player api
9343 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9345 if ((player->cmd == MMPLAYER_COMMAND_START)
9346 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9347 __mmplayer_handle_missed_plugin(player);
9350 /* check audio codec field is set or not
9351 * we can get it from typefinder or codec's caps.
9353 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9355 /* The codec format can't be sent for audio only case like amr, mid etc.
9356 * Because, parser don't make related TAG.
9357 * So, if it's not set yet, fill it with found data.
9360 if (g_strrstr(player->type, "audio/midi"))
9361 audio_codec = "MIDI";
9362 else if (g_strrstr(player->type, "audio/x-amr"))
9363 audio_codec = "AMR";
9364 else if (g_strrstr(player->type, "audio/mpeg")
9365 && !g_strrstr(player->type, "mpegversion=(int)1"))
9366 audio_codec = "AAC";
9368 audio_codec = "unknown";
9370 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9372 if (mm_attrs_commit_all(player->attrs))
9373 LOGE("failed to update attributes");
9375 LOGD("set audio codec type with caps");