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 parsers */
6359 if (player->parsers) {
6360 GList *parsers = player->parsers;
6361 for (; parsers; parsers = g_list_next(parsers)) {
6362 gchar *name = parsers->data;
6363 MMPLAYER_FREEIF(name);
6365 g_list_free(player->parsers);
6366 player->parsers = NULL;
6369 /* clean found audio decoders */
6370 if (player->audio_decoders) {
6371 GList *a_dec = player->audio_decoders;
6372 for (; a_dec; a_dec = g_list_next(a_dec)) {
6373 gchar *name = a_dec->data;
6374 MMPLAYER_FREEIF(name);
6376 g_list_free(player->audio_decoders);
6377 player->audio_decoders = NULL;
6384 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6386 MMPlayerGstElement *mainbin = NULL;
6387 MMMessageParamType msg_param = {0,};
6388 GstElement *element = NULL;
6389 MMHandleType attrs = 0;
6391 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6395 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6396 LOGE("player is not initialized");
6400 mainbin = player->pipeline->mainbin;
6401 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6403 attrs = MMPLAYER_GET_ATTRS(player);
6405 LOGE("fail to get attributes");
6409 /* Initialize Player values */
6410 __mmplayer_initialize_gapless_play(player);
6412 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6414 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6415 LOGE("failed to parse profile");
6416 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6420 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6421 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6422 LOGE("dash or hls is not supportable");
6423 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6427 element = __mmplayer_gst_create_source(player);
6429 LOGE("no source element was created");
6433 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6434 LOGE("failed to add source element to pipeline");
6435 gst_object_unref(GST_OBJECT(element));
6440 /* take source element */
6441 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6442 mainbin[MMPLAYER_M_SRC].gst = element;
6446 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6447 if (player->streamer == NULL) {
6448 player->streamer = __mm_player_streaming_create();
6449 __mm_player_streaming_initialize(player->streamer, TRUE);
6452 elem_idx = MMPLAYER_M_TYPEFIND;
6453 element = gst_element_factory_make("typefind", "typefinder");
6454 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6455 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6457 elem_idx = MMPLAYER_M_AUTOPLUG;
6458 element = __mmplayer_gst_make_decodebin(player);
6461 /* check autoplug element is OK */
6463 LOGE("can not create element(%d)", elem_idx);
6467 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6468 LOGE("failed to add sinkbin to pipeline");
6469 gst_object_unref(GST_OBJECT(element));
6474 mainbin[elem_idx].id = elem_idx;
6475 mainbin[elem_idx].gst = element;
6477 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6478 LOGE("Failed to link src - autoplug(or typefind)");
6482 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6483 LOGE("Failed to change state of src element");
6487 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6488 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6489 LOGE("Failed to change state of decodebin");
6493 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6494 LOGE("Failed to change state of src element");
6499 player->gapless.stream_changed = TRUE;
6500 player->gapless.running = TRUE;
6506 MMPLAYER_PLAYBACK_UNLOCK(player);
6508 if (!player->msg_posted) {
6509 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6510 player->msg_posted = TRUE;
6517 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6519 mm_player_selector_t *selector = &player->selector[type];
6520 MMPlayerGstElement *sinkbin = NULL;
6521 enum MainElementID selectorId = MMPLAYER_M_NUM;
6522 enum MainElementID sinkId = MMPLAYER_M_NUM;
6523 GstPad *srcpad = NULL;
6524 GstPad *sinkpad = NULL;
6525 gboolean send_notice = FALSE;
6528 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6530 LOGD("type %d", type);
6533 case MM_PLAYER_TRACK_TYPE_AUDIO:
6534 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6535 sinkId = MMPLAYER_A_BIN;
6536 sinkbin = player->pipeline->audiobin;
6538 case MM_PLAYER_TRACK_TYPE_VIDEO:
6539 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6540 sinkId = MMPLAYER_V_BIN;
6541 sinkbin = player->pipeline->videobin;
6544 case MM_PLAYER_TRACK_TYPE_TEXT:
6545 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6546 sinkId = MMPLAYER_T_BIN;
6547 sinkbin = player->pipeline->textbin;
6550 LOGE("requested type is not supportable");
6555 if (player->pipeline->mainbin[selectorId].gst) {
6558 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6560 if (selector->event_probe_id != 0)
6561 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6562 selector->event_probe_id = 0;
6564 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6565 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6567 if (srcpad && sinkpad) {
6568 /* after getting drained signal there is no data flows, so no need to do pad_block */
6569 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6570 gst_pad_unlink(srcpad, sinkpad);
6572 /* send custom event to sink pad to handle it at video sink */
6574 LOGD("send custom event to sinkpad");
6575 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6576 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6577 gst_pad_send_event(sinkpad, event);
6581 gst_object_unref(sinkpad);
6584 gst_object_unref(srcpad);
6587 LOGD("selector release");
6589 /* release and unref requests pad from the selector */
6590 for (n = 0; n < selector->channels->len; n++) {
6591 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6592 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6594 g_ptr_array_set_size(selector->channels, 0);
6596 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6597 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6599 player->pipeline->mainbin[selectorId].gst = NULL;
6607 __mmplayer_deactivate_old_path(mm_player_t *player)
6610 MMPLAYER_RETURN_IF_FAIL(player);
6612 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6613 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6614 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6615 LOGE("deactivate selector error");
6619 __mmplayer_track_destroy(player);
6620 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6622 if (player->streamer) {
6623 __mm_player_streaming_initialize(player->streamer, FALSE);
6624 __mm_player_streaming_destroy(player->streamer);
6625 player->streamer = NULL;
6628 MMPLAYER_PLAYBACK_LOCK(player);
6629 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6636 if (!player->msg_posted) {
6637 MMMessageParamType msg = {0,};
6640 msg.code = MM_ERROR_PLAYER_INTERNAL;
6641 LOGE("gapless_uri_play> deactivate error");
6643 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6644 player->msg_posted = TRUE;
6650 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6652 int result = MM_ERROR_NONE;
6653 mm_player_t *player = (mm_player_t *)hplayer;
6656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6658 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6659 if (mm_attrs_commit_all(player->attrs)) {
6660 LOGE("failed to commit the original uri.");
6661 result = MM_ERROR_PLAYER_INTERNAL;
6663 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6664 LOGE("failed to add the original uri in the uri list.");
6672 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6674 mm_player_t *player = (mm_player_t *)hplayer;
6675 guint num_of_list = 0;
6679 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6680 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6682 if (player->pipeline && player->pipeline->textbin) {
6683 LOGE("subtitle path is enabled.");
6684 return MM_ERROR_PLAYER_INVALID_STATE;
6687 num_of_list = g_list_length(player->uri_info.uri_list);
6689 if (is_first_path) {
6690 if (num_of_list == 0) {
6691 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6692 LOGD("add original path : %s", uri);
6694 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6695 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6697 LOGD("change original path : %s", uri);
6700 MMHandleType attrs = 0;
6701 attrs = MMPLAYER_GET_ATTRS(player);
6703 if (num_of_list == 0) {
6704 char *original_uri = NULL;
6707 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6709 if (!original_uri) {
6710 LOGE("there is no original uri.");
6711 return MM_ERROR_PLAYER_INVALID_STATE;
6714 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6715 player->uri_info.uri_idx = 0;
6717 LOGD("add original path at first : %s", original_uri);
6721 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6722 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6726 return MM_ERROR_NONE;
6730 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6732 mm_player_t *player = (mm_player_t *)hplayer;
6733 char *next_uri = NULL;
6734 guint num_of_list = 0;
6737 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6739 num_of_list = g_list_length(player->uri_info.uri_list);
6741 if (num_of_list > 0) {
6742 gint uri_idx = player->uri_info.uri_idx;
6744 if (uri_idx < num_of_list-1)
6749 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6750 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6752 *uri = g_strdup(next_uri);
6756 return MM_ERROR_NONE;
6760 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6761 GstCaps *caps, gpointer data)
6763 mm_player_t *player = (mm_player_t *)data;
6764 const gchar *klass = NULL;
6765 const gchar *mime = NULL;
6766 gchar *caps_str = NULL;
6768 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6769 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6770 caps_str = gst_caps_to_string(caps);
6772 LOGW("unknown type of caps : %s from %s",
6773 caps_str, GST_ELEMENT_NAME(elem));
6775 MMPLAYER_FREEIF(caps_str);
6777 /* There is no available codec. */
6778 __mmplayer_check_not_supported_codec(player, klass, mime);
6782 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6783 GstCaps *caps, gpointer data)
6785 mm_player_t *player = (mm_player_t *)data;
6786 const char *mime = NULL;
6787 gboolean ret = TRUE;
6789 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6790 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6792 if (g_str_has_prefix(mime, "audio")) {
6793 GstStructure *caps_structure = NULL;
6794 gint samplerate = 0;
6796 gchar *caps_str = NULL;
6798 caps_structure = gst_caps_get_structure(caps, 0);
6799 gst_structure_get_int(caps_structure, "rate", &samplerate);
6800 gst_structure_get_int(caps_structure, "channels", &channels);
6802 if ((channels > 0 && samplerate == 0)) {
6803 LOGD("exclude audio...");
6807 caps_str = gst_caps_to_string(caps);
6808 /* set it directly because not sent by TAG */
6809 if (g_strrstr(caps_str, "mobile-xmf"))
6810 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6811 MMPLAYER_FREEIF(caps_str);
6812 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6813 MMMessageParamType msg_param;
6814 memset(&msg_param, 0, sizeof(MMMessageParamType));
6815 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6816 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6817 LOGD("video file is not supported on this device");
6819 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6820 LOGD("already video linked");
6823 LOGD("found new stream");
6830 __mmplayer_is_audio_offload_device_type(mm_player_t *player)
6832 gboolean ret = TRUE;
6833 GDBusConnection *conn = NULL;
6835 GVariant *result = NULL;
6836 const gchar *dbus_device_type = NULL;
6837 const gchar *dbus_ret = NULL;
6840 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6842 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6848 result = g_dbus_connection_call_sync(conn,
6849 "org.pulseaudio.Server",
6850 "/org/pulseaudio/StreamManager",
6851 "org.pulseaudio.StreamManager",
6852 "GetCurrentMediaRoutingPath",
6853 g_variant_new("(s)", "out"),
6854 G_VARIANT_TYPE("(ss)"),
6855 G_DBUS_CALL_FLAGS_NONE,
6859 if (!result || err) {
6860 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6866 /* device type is listed in stream-map.json at mmfw-sysconf */
6867 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6869 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6870 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6875 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6876 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6877 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6878 LOGD("audio offload is supportable");
6884 LOGD("audio offload is not supportable");
6888 g_variant_unref(result);
6889 g_object_unref(conn);
6894 static void __mmplayer_rebuild_audio_pipeline(mm_player_t *player)
6896 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
6897 gint64 position = 0;
6899 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6900 player->pipeline && player->pipeline->mainbin);
6902 MMPLAYER_CMD_LOCK(player);
6903 current_state = MMPLAYER_CURRENT_STATE(player);
6905 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6906 LOGW("getting current position failed in paused");
6908 _mmplayer_unrealize((MMHandleType)player);
6909 _mmplayer_realize((MMHandleType)player);
6911 _mmplayer_set_position((MMHandleType)player, position);
6913 /* async not to be blocked in streaming case */
6914 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6915 if (mm_attrs_commit_all(player->attrs))
6916 LOGE("failed to commit");
6918 _mmplayer_pause((MMHandleType)player);
6920 if (current_state == MM_PLAYER_STATE_PLAYING)
6921 _mmplayer_start((MMHandleType)player);
6922 MMPLAYER_CMD_UNLOCK(player);
6924 LOGD("rebuilding audio pipeline is completed.");
6927 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6929 mm_player_t *player = (mm_player_t *)user_data;
6930 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6931 gboolean is_supportable = FALSE;
6933 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6934 LOGW("failed to get device type");
6936 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6938 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6939 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6940 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6941 LOGD("ignore this dev connected info");
6945 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6946 if (player->build_audio_offload == is_supportable) {
6947 LOGD("keep current pipeline without re-building");
6951 /* rebuild pipeline */
6952 LOGD("re-build pipeline - offload: %d", is_supportable);
6953 player->build_audio_offload = FALSE;
6954 __mmplayer_rebuild_audio_pipeline(player);
6960 __mmplayer_add_audio_device_connected_cb(mm_player_t *player)
6962 unsigned int id = 0;
6964 if (player->audio_device_cb_id != 0) {
6965 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6969 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6970 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6971 LOGD("added device connected cb (%u)", id);
6972 player->audio_device_cb_id = id;
6974 LOGW("failed to add device connected cb");
6982 __mmplayer_can_build_audio_offload_path(mm_player_t *player)
6984 gboolean ret = FALSE;
6985 GstElementFactory *factory = NULL;
6988 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6990 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6991 if (!__mmplayer_is_only_mp3_type(player->type))
6994 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6995 LOGD("there is no audio offload sink");
6999 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7000 LOGW("there is no audio device type to support offload");
7004 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7006 LOGW("there is no installed audio offload sink element");
7009 gst_object_unref(factory);
7011 if (!__mmplayer_add_audio_device_connected_cb(player))
7014 if (!__mmplayer_is_audio_offload_device_type(player))
7017 LOGD("audio offload can be built");
7025 static GstAutoplugSelectResult
7026 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
7028 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7030 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7031 int audio_offload = 0;
7033 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7034 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7036 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7037 LOGD("expose audio path to build offload output path");
7038 player->build_audio_offload = TRUE;
7039 /* update codec info */
7040 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7041 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7042 player->audiodec_linked = 1;
7044 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7048 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7050 LOGD("audio codec type: %d", codec_type);
7051 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7052 /* sw codec will be skipped */
7053 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7054 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7055 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7056 ret = GST_AUTOPLUG_SELECT_SKIP;
7060 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7061 /* hw codec will be skipped */
7062 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7063 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7064 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7065 ret = GST_AUTOPLUG_SELECT_SKIP;
7070 /* set stream information */
7071 if (!player->audiodec_linked)
7072 __mmplayer_set_audio_attrs(player, caps);
7074 /* update codec info */
7075 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7076 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7077 player->audiodec_linked = 1;
7079 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7081 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7083 LOGD("video codec type: %d", codec_type);
7084 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7085 /* sw codec is skipped */
7086 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7087 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7088 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7089 ret = GST_AUTOPLUG_SELECT_SKIP;
7093 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7094 /* hw codec is skipped */
7095 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7096 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7097 ret = GST_AUTOPLUG_SELECT_SKIP;
7102 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7103 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7105 /* mark video decoder for acquire */
7106 if (player->video_decoder_resource == NULL) {
7107 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7108 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7109 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7110 &player->video_decoder_resource)
7111 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7112 LOGE("could not mark video_decoder resource for acquire");
7113 ret = GST_AUTOPLUG_SELECT_SKIP;
7117 LOGW("video decoder resource is already acquired, skip it.");
7118 ret = GST_AUTOPLUG_SELECT_SKIP;
7122 player->interrupted_by_resource = FALSE;
7123 /* acquire resources for video playing */
7124 if (mm_resource_manager_commit(player->resource_manager)
7125 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7126 LOGE("could not acquire resources for video decoding");
7127 ret = GST_AUTOPLUG_SELECT_SKIP;
7132 /* update codec info */
7133 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7134 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7135 player->videodec_linked = 1;
7143 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7144 GstCaps *caps, GstElementFactory *factory, gpointer data)
7146 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7147 mm_player_t *player = (mm_player_t *)data;
7149 gchar *factory_name = NULL;
7150 gchar *caps_str = NULL;
7151 const gchar *klass = NULL;
7154 factory_name = GST_OBJECT_NAME(factory);
7155 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7156 caps_str = gst_caps_to_string(caps);
7158 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7160 /* store type string */
7161 if (player->type == NULL) {
7162 player->type = gst_caps_to_string(caps);
7163 __mmplayer_update_content_type_info(player);
7166 /* filtering exclude keyword */
7167 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7168 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7169 LOGW("skipping [%s] by exculde keyword [%s]",
7170 factory_name, player->ini.exclude_element_keyword[idx]);
7172 result = GST_AUTOPLUG_SELECT_SKIP;
7177 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7178 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7179 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7180 factory_name, player->ini.unsupported_codec_keyword[idx]);
7181 result = GST_AUTOPLUG_SELECT_SKIP;
7186 /* exclude webm format */
7187 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7188 * because webm format is not supportable.
7189 * If webm is disabled in "autoplug-continue", there is no state change
7190 * failure or error because the decodebin will expose the pad directly.
7191 * It make MSL invoke _prepare_async_callback.
7192 * So, we need to disable webm format in "autoplug-select" */
7193 if (caps_str && strstr(caps_str, "webm")) {
7194 LOGW("webm is not supported");
7195 result = GST_AUTOPLUG_SELECT_SKIP;
7199 /* check factory class for filtering */
7200 /* NOTE : msl don't need to use image plugins.
7201 * So, those plugins should be skipped for error handling.
7203 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7204 LOGD("skipping [%s] by not required", factory_name);
7205 result = GST_AUTOPLUG_SELECT_SKIP;
7209 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7210 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7211 // TO CHECK : subtitle if needed, add subparse exception.
7212 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7213 result = GST_AUTOPLUG_SELECT_SKIP;
7217 if (g_strrstr(factory_name, "mpegpsdemux")) {
7218 LOGD("skipping PS container - not support");
7219 result = GST_AUTOPLUG_SELECT_SKIP;
7223 if (g_strrstr(factory_name, "mssdemux"))
7224 player->smooth_streaming = TRUE;
7226 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7227 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7230 GstStructure *str = NULL;
7231 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7233 /* don't make video because of not required */
7234 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7235 (!player->set_mode.media_packet_video_stream)) {
7236 LOGD("no need video decoding, expose pad");
7237 result = GST_AUTOPLUG_SELECT_EXPOSE;
7241 /* get w/h for omx state-tune */
7242 /* FIXME: deprecated? */
7243 str = gst_caps_get_structure(caps, 0);
7244 gst_structure_get_int(str, "width", &width);
7247 if (player->v_stream_caps) {
7248 gst_caps_unref(player->v_stream_caps);
7249 player->v_stream_caps = NULL;
7252 player->v_stream_caps = gst_caps_copy(caps);
7253 LOGD("take caps for video state tune");
7254 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7258 if (g_strrstr(klass, "Codec/Decoder")) {
7259 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7260 if (result != GST_AUTOPLUG_SELECT_TRY) {
7261 LOGW("skip add decoder");
7267 MMPLAYER_FREEIF(caps_str);
7273 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7276 //mm_player_t *player = (mm_player_t *)data;
7277 GstCaps *caps = NULL;
7279 LOGD("[Decodebin2] pad-removed signal");
7281 caps = gst_pad_query_caps(new_pad, NULL);
7283 LOGW("query caps is NULL");
7287 gchar *caps_str = NULL;
7288 caps_str = gst_caps_to_string(caps);
7290 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7292 MMPLAYER_FREEIF(caps_str);
7293 gst_caps_unref(caps);
7297 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7299 mm_player_t *player = (mm_player_t *)data;
7300 GstIterator *iter = NULL;
7301 GValue item = { 0, };
7303 gboolean done = FALSE;
7304 gboolean is_all_drained = TRUE;
7307 MMPLAYER_RETURN_IF_FAIL(player);
7309 LOGD("__mmplayer_gst_decode_drained");
7311 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7312 LOGW("Fail to get cmd lock");
7316 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7317 !__mmplayer_verify_gapless_play_path(player)) {
7318 LOGD("decoding is finished.");
7319 __mmplayer_reset_gapless_state(player);
7320 MMPLAYER_CMD_UNLOCK(player);
7324 player->gapless.reconfigure = TRUE;
7326 /* check decodebin src pads whether they received EOS or not */
7327 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7330 switch (gst_iterator_next(iter, &item)) {
7331 case GST_ITERATOR_OK:
7332 pad = g_value_get_object(&item);
7333 if (pad && !GST_PAD_IS_EOS(pad)) {
7334 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7335 is_all_drained = FALSE;
7338 g_value_reset(&item);
7340 case GST_ITERATOR_RESYNC:
7341 gst_iterator_resync(iter);
7343 case GST_ITERATOR_ERROR:
7344 case GST_ITERATOR_DONE:
7349 g_value_unset(&item);
7350 gst_iterator_free(iter);
7352 if (!is_all_drained) {
7353 LOGD("Wait util the all pads get EOS.");
7354 MMPLAYER_CMD_UNLOCK(player);
7359 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7360 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7362 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7363 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7364 __mmplayer_deactivate_old_path(player);
7365 MMPLAYER_CMD_UNLOCK(player);
7371 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7373 mm_player_t *player = (mm_player_t *)data;
7374 const gchar *klass = NULL;
7375 gchar *factory_name = NULL;
7377 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7378 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7380 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7382 if (__mmplayer_add_dump_buffer_probe(player, element))
7383 LOGD("add buffer probe");
7386 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7387 gchar *selected = NULL;
7388 selected = g_strdup(GST_ELEMENT_NAME(element));
7389 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7393 if (g_strrstr(klass, "Parser")) {
7394 gchar *selected = NULL;
7396 selected = g_strdup(factory_name);
7397 player->parsers = g_list_append(player->parsers, selected);
7400 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7401 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7402 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7404 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7405 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7407 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7408 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7409 "max-video-width", player->adaptive_info.limit.width,
7410 "max-video-height", player->adaptive_info.limit.height, NULL);
7412 } else if (g_strrstr(klass, "Demuxer")) {
7413 //LOGD("plugged element is demuxer. take it");
7414 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7415 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7418 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7419 int surface_type = 0;
7421 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7424 // to support trust-zone only
7425 if (g_strrstr(factory_name, "asfdemux")) {
7426 LOGD("set file-location %s", player->profile.uri);
7427 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7428 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7429 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7430 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7431 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7432 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7433 (__mmplayer_is_only_mp3_type(player->type))) {
7434 LOGD("[mpegaudioparse] set streaming pull mode.");
7435 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7437 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7438 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7441 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7442 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7443 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7445 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7446 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7448 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7449 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7450 (MMPLAYER_IS_DASH_STREAMING(player))) {
7451 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7452 __mm_player_streaming_set_multiqueue(player->streamer, element);
7453 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7462 __mmplayer_release_misc(mm_player_t *player)
7465 bool cur_mode = player->set_mode.rich_audio;
7468 MMPLAYER_RETURN_IF_FAIL(player);
7470 player->video_stream_cb = NULL;
7471 player->video_stream_cb_user_param = NULL;
7472 player->video_stream_prerolled = false;
7474 player->audio_stream_render_cb = NULL;
7475 player->audio_stream_cb_user_param = NULL;
7476 player->audio_stream_sink_sync = false;
7478 player->video_stream_changed_cb = NULL;
7479 player->video_stream_changed_cb_user_param = NULL;
7481 player->audio_stream_changed_cb = NULL;
7482 player->audio_stream_changed_cb_user_param = NULL;
7484 player->sent_bos = FALSE;
7485 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7487 player->seek_state = MMPLAYER_SEEK_NONE;
7489 player->total_bitrate = 0;
7490 player->total_maximum_bitrate = 0;
7492 player->not_found_demuxer = 0;
7494 player->last_position = 0;
7495 player->duration = 0;
7496 player->http_content_size = 0;
7497 player->not_supported_codec = MISSING_PLUGIN_NONE;
7498 player->can_support_codec = FOUND_PLUGIN_NONE;
7499 player->pending_seek.is_pending = false;
7500 player->pending_seek.pos = 0;
7501 player->msg_posted = FALSE;
7502 player->has_many_types = FALSE;
7503 player->is_subtitle_force_drop = FALSE;
7504 player->play_subtitle = FALSE;
7505 player->adjust_subtitle_pos = 0;
7506 player->has_closed_caption = FALSE;
7507 player->set_mode.media_packet_video_stream = false;
7508 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7509 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7511 player->set_mode.rich_audio = cur_mode;
7513 if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7514 LOGW("failed to remove audio device_connected_callback");
7515 player->audio_device_cb_id = 0;
7517 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7518 player->bitrate[i] = 0;
7519 player->maximum_bitrate[i] = 0;
7522 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7524 /* remove media stream cb(appsrc cb) */
7525 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7526 player->media_stream_buffer_status_cb[i] = NULL;
7527 player->media_stream_seek_data_cb[i] = NULL;
7528 player->buffer_cb_user_param[i] = NULL;
7529 player->seek_cb_user_param[i] = NULL;
7531 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7533 /* free memory related to audio effect */
7534 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7536 if (player->adaptive_info.var_list) {
7537 g_list_free_full(player->adaptive_info.var_list, g_free);
7538 player->adaptive_info.var_list = NULL;
7541 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7542 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7543 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7545 /* Reset video360 settings to their defaults in case if the pipeline is to be
7548 player->video360_metadata.is_spherical = -1;
7549 player->is_openal_plugin_used = FALSE;
7551 player->is_content_spherical = FALSE;
7552 player->is_video360_enabled = TRUE;
7553 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7554 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7555 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7556 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7557 player->video360_zoom = 1.0f;
7558 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7559 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7561 player->sound.rg_enable = false;
7563 __mmplayer_initialize_video_roi(player);
7568 __mmplayer_release_misc_post(mm_player_t *player)
7570 char *original_uri = NULL;
7573 /* player->pipeline is already released before. */
7575 MMPLAYER_RETURN_IF_FAIL(player);
7577 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7579 /* clean found parsers */
7580 if (player->parsers) {
7581 GList *parsers = player->parsers;
7582 for (; parsers; parsers = g_list_next(parsers)) {
7583 gchar *name = parsers->data;
7584 MMPLAYER_FREEIF(name);
7586 g_list_free(player->parsers);
7587 player->parsers = NULL;
7590 /* clean found audio decoders */
7591 if (player->audio_decoders) {
7592 GList *a_dec = player->audio_decoders;
7593 for (; a_dec; a_dec = g_list_next(a_dec)) {
7594 gchar *name = a_dec->data;
7595 MMPLAYER_FREEIF(name);
7597 g_list_free(player->audio_decoders);
7598 player->audio_decoders = NULL;
7601 /* clean the uri list except original uri */
7602 if (player->uri_info.uri_list) {
7603 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7605 if (player->attrs) {
7606 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7607 LOGD("restore original uri = %s", original_uri);
7609 if (mm_attrs_commit_all(player->attrs))
7610 LOGE("failed to commit the original uri.");
7613 GList *uri_list = player->uri_info.uri_list;
7614 for (; uri_list; uri_list = g_list_next(uri_list)) {
7615 gchar *uri = uri_list->data;
7616 MMPLAYER_FREEIF(uri);
7618 g_list_free(player->uri_info.uri_list);
7619 player->uri_info.uri_list = NULL;
7622 /* clear the audio stream buffer list */
7623 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7625 /* clear the video stream bo list */
7626 __mmplayer_video_stream_destroy_bo_list(player);
7627 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7629 if (player->profile.input_mem.buf) {
7630 free(player->profile.input_mem.buf);
7631 player->profile.input_mem.buf = NULL;
7633 player->profile.input_mem.len = 0;
7634 player->profile.input_mem.offset = 0;
7636 player->uri_info.uri_idx = 0;
7641 __mmplayer_check_subtitle(mm_player_t *player)
7643 MMHandleType attrs = 0;
7644 char *subtitle_uri = NULL;
7648 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7650 /* get subtitle attribute */
7651 attrs = MMPLAYER_GET_ATTRS(player);
7655 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7656 if (!subtitle_uri || !strlen(subtitle_uri))
7659 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7660 player->is_external_subtitle_present = TRUE;
7668 __mmplayer_cancel_eos_timer(mm_player_t *player)
7670 MMPLAYER_RETURN_IF_FAIL(player);
7672 if (player->eos_timer) {
7673 LOGD("cancel eos timer");
7674 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7675 player->eos_timer = 0;
7682 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7686 MMPLAYER_RETURN_IF_FAIL(player);
7687 MMPLAYER_RETURN_IF_FAIL(sink);
7689 player->sink_elements = g_list_append(player->sink_elements, sink);
7695 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7699 MMPLAYER_RETURN_IF_FAIL(player);
7700 MMPLAYER_RETURN_IF_FAIL(sink);
7702 player->sink_elements = g_list_remove(player->sink_elements, sink);
7708 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7709 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7711 MMPlayerSignalItem *item = NULL;
7714 MMPLAYER_RETURN_IF_FAIL(player);
7716 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7717 LOGE("invalid signal type [%d]", type);
7721 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7723 LOGE("cannot connect signal [%s]", signal);
7728 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7729 player->signals[type] = g_list_append(player->signals[type], item);
7735 /* NOTE : be careful with calling this api. please refer to below glib comment
7736 * glib comment : Note that there is a bug in GObject that makes this function much
7737 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7738 * will no longer be called, but, the signal handler is not currently disconnected.
7739 * If the instance is itself being freed at the same time than this doesn't matter,
7740 * since the signal will automatically be removed, but if instance persists,
7741 * then the signal handler will leak. You should not remove the signal yourself
7742 * because in a future versions of GObject, the handler will automatically be
7745 * It's possible to work around this problem in a way that will continue to work
7746 * with future versions of GObject by checking that the signal handler is still
7747 * connected before disconnected it:
7749 * if (g_signal_handler_is_connected(instance, id))
7750 * g_signal_handler_disconnect(instance, id);
7753 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7755 GList *sig_list = NULL;
7756 MMPlayerSignalItem *item = NULL;
7760 MMPLAYER_RETURN_IF_FAIL(player);
7762 LOGD("release signals type : %d", type);
7764 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7765 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7766 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7767 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7768 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7769 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7773 sig_list = player->signals[type];
7775 for (; sig_list; sig_list = sig_list->next) {
7776 item = sig_list->data;
7778 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7779 if (g_signal_handler_is_connected(item->obj, item->sig))
7780 g_signal_handler_disconnect(item->obj, item->sig);
7783 MMPLAYER_FREEIF(item);
7786 g_list_free(player->signals[type]);
7787 player->signals[type] = NULL;
7795 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7797 mm_player_t *player = 0;
7798 int prev_display_surface_type = 0;
7799 void *prev_display_overlay = NULL;
7803 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7804 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7806 player = MM_PLAYER_CAST(handle);
7808 /* check video sinkbin is created */
7809 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7810 LOGE("Videosink is already created");
7811 return MM_ERROR_NONE;
7814 LOGD("videosink element is not yet ready");
7816 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7817 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7819 return MM_ERROR_INVALID_ARGUMENT;
7822 /* load previous attributes */
7823 if (player->attrs) {
7824 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7825 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7826 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7827 if (prev_display_surface_type == surface_type) {
7828 LOGD("incoming display surface type is same as previous one, do nothing..");
7830 return MM_ERROR_NONE;
7833 LOGE("failed to load attributes");
7835 return MM_ERROR_PLAYER_INTERNAL;
7838 /* videobin is not created yet, so we just set attributes related to display surface */
7839 LOGD("store display attribute for given surface type(%d)", surface_type);
7840 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7841 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7842 if (mm_attrs_commit_all(player->attrs)) {
7843 LOGE("failed to commit attribute");
7845 return MM_ERROR_PLAYER_INTERNAL;
7849 return MM_ERROR_NONE;
7852 /* Note : if silent is true, then subtitle would not be displayed. :*/
7854 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7856 mm_player_t *player = (mm_player_t *)hplayer;
7860 /* check player handle */
7861 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7863 player->set_mode.subtitle_off = silent;
7865 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7869 return MM_ERROR_NONE;
7873 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7875 MMPlayerGstElement *mainbin = NULL;
7876 MMPlayerGstElement *textbin = NULL;
7877 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7878 GstState current_state = GST_STATE_VOID_PENDING;
7879 GstState element_state = GST_STATE_VOID_PENDING;
7880 GstState element_pending_state = GST_STATE_VOID_PENDING;
7882 GstEvent *event = NULL;
7883 int result = MM_ERROR_NONE;
7885 GstClock *curr_clock = NULL;
7886 GstClockTime base_time, start_time, curr_time;
7891 /* check player handle */
7892 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7894 player->pipeline->mainbin &&
7895 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7897 mainbin = player->pipeline->mainbin;
7898 textbin = player->pipeline->textbin;
7900 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7902 // sync clock with current pipeline
7903 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7904 curr_time = gst_clock_get_time(curr_clock);
7906 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7907 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7909 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7910 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7912 if (current_state > GST_STATE_READY) {
7913 // sync state with current pipeline
7914 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7915 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7916 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7918 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7919 if (GST_STATE_CHANGE_FAILURE == ret) {
7920 LOGE("fail to state change.");
7921 result = MM_ERROR_PLAYER_INTERNAL;
7925 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7926 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7929 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7930 gst_object_unref(curr_clock);
7933 // seek to current position
7934 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7935 result = MM_ERROR_PLAYER_INVALID_STATE;
7936 LOGE("gst_element_query_position failed, invalid state");
7940 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7941 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);
7943 __mmplayer_gst_send_event_to_sink(player, event);
7945 result = MM_ERROR_PLAYER_INTERNAL;
7946 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7950 /* sync state with current pipeline */
7951 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7952 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7953 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7955 return MM_ERROR_NONE;
7958 /* release text pipeline resource */
7959 player->textsink_linked = 0;
7961 /* release signal */
7962 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7964 /* release textbin with it's childs */
7965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7966 MMPLAYER_FREEIF(player->pipeline->textbin);
7967 player->pipeline->textbin = NULL;
7969 /* release subtitle elem */
7970 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7971 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7977 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7979 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7980 GstState current_state = GST_STATE_VOID_PENDING;
7982 MMHandleType attrs = 0;
7983 MMPlayerGstElement *mainbin = NULL;
7984 MMPlayerGstElement *textbin = NULL;
7986 gchar *subtitle_uri = NULL;
7987 int result = MM_ERROR_NONE;
7988 const gchar *charset = NULL;
7992 /* check player handle */
7993 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7995 player->pipeline->mainbin &&
7996 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7997 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7999 mainbin = player->pipeline->mainbin;
8000 textbin = player->pipeline->textbin;
8002 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8003 if (current_state < GST_STATE_READY) {
8004 result = MM_ERROR_PLAYER_INVALID_STATE;
8005 LOGE("Pipeline is not in proper state");
8009 attrs = MMPLAYER_GET_ATTRS(player);
8011 LOGE("cannot get content attribute");
8012 result = MM_ERROR_PLAYER_INTERNAL;
8016 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8017 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8018 LOGE("subtitle uri is not proper filepath");
8019 result = MM_ERROR_PLAYER_INVALID_URI;
8023 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8024 LOGE("failed to get storage info of subtitle path");
8025 result = MM_ERROR_PLAYER_INVALID_URI;
8029 LOGD("old subtitle file path is [%s]", subtitle_uri);
8030 LOGD("new subtitle file path is [%s]", filepath);
8032 if (!strcmp(filepath, subtitle_uri)) {
8033 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8036 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8037 if (mm_attrs_commit_all(player->attrs)) {
8038 LOGE("failed to commit.");
8043 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8044 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8045 player->subtitle_language_list = NULL;
8046 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8048 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8049 if (ret != GST_STATE_CHANGE_SUCCESS) {
8050 LOGE("failed to change state of textbin to READY");
8051 result = MM_ERROR_PLAYER_INTERNAL;
8055 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8056 if (ret != GST_STATE_CHANGE_SUCCESS) {
8057 LOGE("failed to change state of subparse to READY");
8058 result = MM_ERROR_PLAYER_INTERNAL;
8062 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8063 if (ret != GST_STATE_CHANGE_SUCCESS) {
8064 LOGE("failed to change state of filesrc to READY");
8065 result = MM_ERROR_PLAYER_INTERNAL;
8069 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8071 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8073 charset = util_get_charset(filepath);
8075 LOGD("detected charset is %s", charset);
8076 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8079 result = _mmplayer_sync_subtitle_pipeline(player);
8086 /* API to switch between external subtitles */
8088 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8090 int result = MM_ERROR_NONE;
8091 mm_player_t *player = (mm_player_t *)hplayer;
8096 /* check player handle */
8097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8099 /* filepath can be null in idle state */
8101 /* check file path */
8102 if ((path = strstr(filepath, "file://")))
8103 result = util_exist_file_path(path + 7);
8105 result = util_exist_file_path(filepath);
8107 if (result != MM_ERROR_NONE) {
8108 LOGE("invalid subtitle path 0x%X", result);
8109 return result; /* file not found or permission denied */
8113 if (!player->pipeline) {
8115 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8116 if (mm_attrs_commit_all(player->attrs)) {
8117 LOGE("failed to commit"); /* subtitle path will not be created */
8118 return MM_ERROR_PLAYER_INTERNAL;
8121 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8122 /* check filepath */
8123 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8125 if (!__mmplayer_check_subtitle(player)) {
8126 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8127 if (mm_attrs_commit_all(player->attrs)) {
8128 LOGE("failed to commit");
8129 return MM_ERROR_PLAYER_INTERNAL;
8132 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8133 LOGE("fail to create text pipeline");
8134 return MM_ERROR_PLAYER_INTERNAL;
8137 result = _mmplayer_sync_subtitle_pipeline(player);
8139 result = __mmplayer_change_external_subtitle_language(player, filepath);
8142 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8143 player->is_external_subtitle_added_now = TRUE;
8145 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8146 if (!player->subtitle_language_list) {
8147 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8148 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8149 LOGW("subtitle language list is not updated yet");
8151 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8159 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
8161 int result = MM_ERROR_NONE;
8162 gchar *change_pad_name = NULL;
8163 GstPad *sinkpad = NULL;
8164 MMPlayerGstElement *mainbin = NULL;
8165 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8166 GstCaps *caps = NULL;
8167 gint total_track_num = 0;
8171 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8172 MM_ERROR_PLAYER_NOT_INITIALIZED);
8174 LOGD("Change Track(%d) to %d", type, index);
8176 mainbin = player->pipeline->mainbin;
8178 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8179 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8180 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8181 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8183 /* Changing Video Track is not supported. */
8184 LOGE("Track Type Error");
8188 if (mainbin[elem_idx].gst == NULL) {
8189 result = MM_ERROR_PLAYER_NO_OP;
8190 LOGD("Req track doesn't exist");
8194 total_track_num = player->selector[type].total_track_num;
8195 if (total_track_num <= 0) {
8196 result = MM_ERROR_PLAYER_NO_OP;
8197 LOGD("Language list is not available");
8201 if ((index < 0) || (index >= total_track_num)) {
8202 result = MM_ERROR_INVALID_ARGUMENT;
8203 LOGD("Not a proper index : %d", index);
8207 /*To get the new pad from the selector*/
8208 change_pad_name = g_strdup_printf("sink_%u", index);
8209 if (change_pad_name == NULL) {
8210 result = MM_ERROR_PLAYER_INTERNAL;
8211 LOGD("Pad does not exists");
8215 LOGD("new active pad name: %s", change_pad_name);
8217 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8218 if (sinkpad == NULL) {
8219 LOGD("sinkpad is NULL");
8220 result = MM_ERROR_PLAYER_INTERNAL;
8224 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8225 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8227 caps = gst_pad_get_current_caps(sinkpad);
8228 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8231 gst_object_unref(sinkpad);
8233 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8234 __mmplayer_set_audio_attrs(player, caps);
8237 MMPLAYER_FREEIF(change_pad_name);
8242 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8244 int result = MM_ERROR_NONE;
8245 mm_player_t *player = NULL;
8246 MMPlayerGstElement *mainbin = NULL;
8248 gint current_active_index = 0;
8250 GstState current_state = GST_STATE_VOID_PENDING;
8251 GstEvent *event = NULL;
8256 player = (mm_player_t *)hplayer;
8257 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8259 if (!player->pipeline) {
8260 LOGE("Track %d pre setting -> %d", type, index);
8262 player->selector[type].active_pad_index = index;
8266 mainbin = player->pipeline->mainbin;
8268 current_active_index = player->selector[type].active_pad_index;
8270 /*If index is same as running index no need to change the pad*/
8271 if (current_active_index == index)
8274 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8275 result = MM_ERROR_PLAYER_INVALID_STATE;
8279 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8280 if (current_state < GST_STATE_PAUSED) {
8281 result = MM_ERROR_PLAYER_INVALID_STATE;
8282 LOGW("Pipeline not in porper state");
8286 result = __mmplayer_change_selector_pad(player, type, index);
8287 if (result != MM_ERROR_NONE) {
8288 LOGE("change selector pad error");
8292 player->selector[type].active_pad_index = index;
8294 if (current_state == GST_STATE_PLAYING) {
8295 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8296 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8297 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8299 __mmplayer_gst_send_event_to_sink(player, event);
8301 result = MM_ERROR_PLAYER_INTERNAL;
8311 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8313 mm_player_t *player = (mm_player_t *)hplayer;
8317 /* check player handle */
8318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8320 *silent = player->set_mode.subtitle_off;
8322 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8326 return MM_ERROR_NONE;
8330 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8332 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8333 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8335 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8336 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8340 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8341 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8342 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8343 mm_player_dump_t *dump_s;
8344 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8345 if (dump_s == NULL) {
8346 LOGE("malloc fail");
8350 dump_s->dump_element_file = NULL;
8351 dump_s->dump_pad = NULL;
8352 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8354 if (dump_s->dump_pad) {
8355 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8356 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]);
8357 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8358 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);
8359 /* add list for removed buffer probe and close FILE */
8360 player->dump_list = g_list_append(player->dump_list, dump_s);
8361 LOGD("%s sink pad added buffer probe for dump", factory_name);
8364 MMPLAYER_FREEIF(dump_s);
8365 LOGE("failed to get %s sink pad added", factory_name);
8372 static GstPadProbeReturn
8373 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8375 FILE *dump_data = (FILE *)u_data;
8377 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8378 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8380 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8382 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8384 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8386 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8388 return GST_PAD_PROBE_OK;
8392 __mmplayer_release_dump_list(GList *dump_list)
8394 GList *d_list = dump_list;
8399 for (; d_list; d_list = g_list_next(d_list)) {
8400 mm_player_dump_t *dump_s = d_list->data;
8401 if (dump_s->dump_pad) {
8402 if (dump_s->probe_handle_id)
8403 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8404 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8406 if (dump_s->dump_element_file) {
8407 fclose(dump_s->dump_element_file);
8408 dump_s->dump_element_file = NULL;
8410 MMPLAYER_FREEIF(dump_s);
8412 g_list_free(dump_list);
8417 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8419 mm_player_t *player = (mm_player_t *)hplayer;
8423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8424 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8426 *exist = (bool)player->has_closed_caption;
8430 return MM_ERROR_NONE;
8434 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8438 // LOGD("unref internal gst buffer %p", buffer);
8439 gst_buffer_unref((GstBuffer *)buffer);
8446 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8448 mm_player_t *player = (mm_player_t *)hplayer;
8452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8453 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8455 if (MMPLAYER_IS_STREAMING(player))
8456 *timeout = (int)player->ini.live_state_change_timeout;
8458 *timeout = (int)player->ini.localplayback_state_change_timeout;
8460 LOGD("timeout = %d", *timeout);
8463 return MM_ERROR_NONE;
8467 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8469 mm_player_t *player = (mm_player_t *)hplayer;
8473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8476 *num = player->video_num_buffers;
8477 *extra_num = player->video_extra_num_buffers;
8479 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8482 return MM_ERROR_NONE;
8486 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8490 MMPLAYER_RETURN_IF_FAIL(player);
8492 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8494 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8495 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8496 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8497 player->storage_info[i].id = -1;
8498 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8500 if (path_type != MMPLAYER_PATH_MAX)
8509 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8511 int ret = MM_ERROR_NONE;
8512 mm_player_t *player = (mm_player_t *)hplayer;
8513 MMMessageParamType msg_param = {0, };
8516 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8518 LOGW("state changed storage %d:%d", id, state);
8520 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8521 return MM_ERROR_NONE;
8523 /* FIXME: text path should be handled seperately. */
8524 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8525 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8526 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8527 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8528 LOGW("external storage is removed");
8530 if (player->msg_posted == FALSE) {
8531 memset(&msg_param, 0, sizeof(MMMessageParamType));
8532 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8533 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8534 player->msg_posted = TRUE;
8537 /* unrealize the player */
8538 ret = _mmplayer_unrealize(hplayer);
8539 if (ret != MM_ERROR_NONE)
8540 LOGE("failed to unrealize");
8548 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8550 int ret = MM_ERROR_NONE;
8551 mm_player_t *player = (mm_player_t *)hplayer;
8552 int idx = 0, total = 0;
8553 gchar *result = NULL, *tmp = NULL;
8556 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8557 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8559 total = *num = g_list_length(player->adaptive_info.var_list);
8561 LOGW("There is no stream variant info.");
8565 result = g_strdup("");
8566 for (idx = 0 ; idx < total ; idx++) {
8567 VariantData *v_data = NULL;
8568 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8571 gchar data[64] = {0};
8572 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8574 tmp = g_strconcat(result, data, NULL);
8578 LOGW("There is no variant data in %d", idx);
8583 *var_info = (char *)result;
8585 LOGD("variant info %d:%s", *num, *var_info);
8591 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8593 int ret = MM_ERROR_NONE;
8594 mm_player_t *player = (mm_player_t *)hplayer;
8597 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8599 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8601 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8602 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8603 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8605 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8606 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8607 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8608 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8610 /* FIXME: seek to current position for applying new variant limitation */
8619 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8621 int ret = MM_ERROR_NONE;
8622 mm_player_t *player = (mm_player_t *)hplayer;
8625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8626 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8628 *bandwidth = player->adaptive_info.limit.bandwidth;
8629 *width = player->adaptive_info.limit.width;
8630 *height = player->adaptive_info.limit.height;
8632 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8639 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8641 int ret = MM_ERROR_NONE;
8642 mm_player_t *player = (mm_player_t *)hplayer;
8645 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8646 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8647 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8649 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8651 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8652 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8653 else /* live case */
8654 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8656 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8663 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8665 #define IDX_FIRST_SW_CODEC 0
8666 mm_player_t *player = (mm_player_t *)hplayer;
8667 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8668 MMHandleType attrs = 0;
8671 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8673 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8674 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8675 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8677 switch (stream_type) {
8678 case MM_PLAYER_STREAM_TYPE_AUDIO:
8679 /* to support audio codec selection, codec info have to be added in ini file as below.
8680 audio codec element hw = xxxx
8681 audio codec element sw = avdec */
8682 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8683 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8684 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8685 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8686 LOGE("There is no audio codec info for codec_type %d", codec_type);
8687 return MM_ERROR_PLAYER_NO_OP;
8690 case MM_PLAYER_STREAM_TYPE_VIDEO:
8691 /* to support video codec selection, codec info have to be added in ini file as below.
8692 video codec element hw = omx
8693 video codec element sw = avdec */
8694 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8695 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8696 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8697 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8698 LOGE("There is no video codec info for codec_type %d", codec_type);
8699 return MM_ERROR_PLAYER_NO_OP;
8703 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8704 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8708 LOGD("update %s codec_type to %d", attr_name, codec_type);
8710 attrs = MMPLAYER_GET_ATTRS(player);
8711 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8713 if (mm_attrs_commit_all(player->attrs)) {
8714 LOGE("failed to commit codec_type attributes");
8715 return MM_ERROR_PLAYER_INTERNAL;
8719 return MM_ERROR_NONE;
8723 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8725 mm_player_t *player = (mm_player_t *)hplayer;
8726 GstElement *rg_vol_element = NULL;
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8732 player->sound.rg_enable = enabled;
8734 /* just hold rgvolume enable value if pipeline is not ready */
8735 if (!player->pipeline || !player->pipeline->audiobin) {
8736 LOGD("pipeline is not ready. holding rgvolume enable value");
8737 return MM_ERROR_NONE;
8740 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8742 if (!rg_vol_element) {
8743 LOGD("rgvolume element is not created");
8744 return MM_ERROR_PLAYER_INTERNAL;
8748 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8750 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8754 return MM_ERROR_NONE;
8758 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8760 mm_player_t *player = (mm_player_t *)hplayer;
8761 GstElement *rg_vol_element = NULL;
8762 gboolean enable = FALSE;
8766 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8767 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8769 /* just hold enable_rg value if pipeline is not ready */
8770 if (!player->pipeline || !player->pipeline->audiobin) {
8771 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8772 *enabled = player->sound.rg_enable;
8773 return MM_ERROR_NONE;
8776 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8778 if (!rg_vol_element) {
8779 LOGD("rgvolume element is not created");
8780 return MM_ERROR_PLAYER_INTERNAL;
8783 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8784 *enabled = (bool)enable;
8788 return MM_ERROR_NONE;
8792 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8794 mm_player_t *player = (mm_player_t *)hplayer;
8795 MMHandleType attrs = 0;
8796 void *handle = NULL;
8797 int ret = MM_ERROR_NONE;
8801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8803 attrs = MMPLAYER_GET_ATTRS(player);
8804 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8806 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8808 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8809 return MM_ERROR_PLAYER_INTERNAL;
8812 player->video_roi.scale_x = scale_x;
8813 player->video_roi.scale_y = scale_y;
8814 player->video_roi.scale_width = scale_width;
8815 player->video_roi.scale_height = scale_height;
8817 /* check video sinkbin is created */
8818 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8819 return MM_ERROR_NONE;
8821 if (!gst_video_overlay_set_video_roi_area(
8822 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8823 scale_x, scale_y, scale_width, scale_height))
8824 ret = MM_ERROR_PLAYER_INTERNAL;
8826 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8827 scale_x, scale_y, scale_width, scale_height);
8835 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8837 mm_player_t *player = (mm_player_t *)hplayer;
8838 int ret = MM_ERROR_NONE;
8842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8843 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8845 *scale_x = player->video_roi.scale_x;
8846 *scale_y = player->video_roi.scale_y;
8847 *scale_width = player->video_roi.scale_width;
8848 *scale_height = player->video_roi.scale_height;
8850 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8851 *scale_x, *scale_y, *scale_width, *scale_height);
8857 __mmplayer_update_duration_value(mm_player_t *player)
8859 gboolean ret = FALSE;
8860 gint64 dur_nsec = 0;
8861 LOGD("try to update duration");
8863 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8864 player->duration = dur_nsec;
8865 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8869 if (player->duration < 0) {
8870 LOGW("duration is Non-Initialized !!!");
8871 player->duration = 0;
8874 /* update streaming service type */
8875 player->streaming_type = __mmplayer_get_stream_service_type(player);
8877 /* check duration is OK */
8878 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8879 /* FIXIT : find another way to get duration here. */
8880 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8886 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8888 /* update audio params
8889 NOTE : We need original audio params and it can be only obtained from src pad of audio
8890 decoder. Below code only valid when we are not using 'resampler' just before
8891 'audioconverter'. */
8892 GstCaps *caps_a = NULL;
8894 gint samplerate = 0, channels = 0;
8895 GstStructure *p = NULL;
8897 LOGD("try to update audio attrs");
8899 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8900 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8902 pad = gst_element_get_static_pad(
8903 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8906 LOGW("failed to get pad from audiosink");
8910 caps_a = gst_pad_get_current_caps(pad);
8912 LOGW("not ready to get audio caps");
8913 gst_object_unref(pad);
8917 p = gst_caps_get_structure(caps_a, 0);
8919 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8921 gst_structure_get_int(p, "rate", &samplerate);
8922 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8924 gst_structure_get_int(p, "channels", &channels);
8925 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8927 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8929 gst_caps_unref(caps_a);
8930 gst_object_unref(pad);
8936 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8938 LOGD("try to update video attrs");
8940 GstCaps *caps_v = NULL;
8944 GstStructure *p = NULL;
8946 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8947 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8949 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8951 LOGD("no videosink sink pad");
8955 caps_v = gst_pad_get_current_caps(pad);
8956 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8957 if (!caps_v && player->v_stream_caps) {
8958 caps_v = player->v_stream_caps;
8959 gst_caps_ref(caps_v);
8963 LOGD("no negitiated caps from videosink");
8964 gst_object_unref(pad);
8968 p = gst_caps_get_structure(caps_v, 0);
8969 gst_structure_get_int(p, "width", &width);
8970 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8972 gst_structure_get_int(p, "height", &height);
8973 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8975 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8977 SECURE_LOGD("width : %d height : %d", width, height);
8979 gst_caps_unref(caps_v);
8980 gst_object_unref(pad);
8983 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8984 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8991 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8993 gboolean ret = FALSE;
8994 guint64 data_size = 0;
8998 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8999 if (!player->duration)
9002 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9003 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9004 if (stat(path, &sb) == 0)
9005 data_size = (guint64)sb.st_size;
9007 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9008 data_size = player->http_content_size;
9011 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9014 guint64 bitrate = 0;
9015 guint64 msec_dur = 0;
9017 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9019 bitrate = data_size * 8 * 1000 / msec_dur;
9020 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9021 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9025 LOGD("player duration is less than 0");
9029 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9030 if (player->total_bitrate) {
9031 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9040 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
9042 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9043 data->uri_type = uri_type;
9047 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
9049 int ret = MM_ERROR_PLAYER_INVALID_URI;
9051 char *buffer = NULL;
9052 char *seperator = strchr(path, ',');
9053 char ext[100] = {0,}, size[100] = {0,};
9056 if ((buffer = strstr(path, "ext="))) {
9057 buffer += strlen("ext=");
9059 if (strlen(buffer)) {
9060 strncpy(ext, buffer, 99);
9062 if ((seperator = strchr(ext, ','))
9063 || (seperator = strchr(ext, ' '))
9064 || (seperator = strchr(ext, '\0'))) {
9065 seperator[0] = '\0';
9070 if ((buffer = strstr(path, "size="))) {
9071 buffer += strlen("size=");
9073 if (strlen(buffer) > 0) {
9074 strncpy(size, buffer, 99);
9076 if ((seperator = strchr(size, ','))
9077 || (seperator = strchr(size, ' '))
9078 || (seperator = strchr(size, '\0'))) {
9079 seperator[0] = '\0';
9082 mem_size = atoi(size);
9087 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9089 if (mem_size && param) {
9090 if (data->input_mem.buf)
9091 free(data->input_mem.buf);
9092 data->input_mem.buf = malloc(mem_size);
9094 if (data->input_mem.buf) {
9095 memcpy(data->input_mem.buf, param, mem_size);
9096 data->input_mem.len = mem_size;
9097 ret = MM_ERROR_NONE;
9099 LOGE("failed to alloc mem %d", mem_size);
9100 ret = MM_ERROR_PLAYER_INTERNAL;
9103 data->input_mem.offset = 0;
9104 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9111 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
9113 gchar *location = NULL;
9116 int ret = MM_ERROR_NONE;
9118 if ((path = strstr(uri, "file://"))) {
9119 location = g_filename_from_uri(uri, NULL, &err);
9120 if (!location || (err != NULL)) {
9121 LOGE("Invalid URI '%s' for filesrc: %s", path,
9122 (err != NULL) ? err->message : "unknown error");
9126 MMPLAYER_FREEIF(location);
9128 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9129 return MM_ERROR_PLAYER_INVALID_URI;
9131 LOGD("path from uri: %s", location);
9134 path = (location != NULL) ? (location) : ((char *)uri);
9137 ret = util_exist_file_path(path);
9139 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9140 if (ret == MM_ERROR_NONE) {
9141 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9142 if (util_is_sdp_file(path)) {
9143 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9144 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9146 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9148 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9149 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9151 LOGE("invalid uri, could not play..");
9152 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9155 MMPLAYER_FREEIF(location);
9160 static MMPlayerVideoStreamDataType *
9161 __mmplayer_create_stream_from_pad(GstPad *pad)
9163 GstCaps *caps = NULL;
9164 GstStructure *structure = NULL;
9165 unsigned int fourcc = 0;
9166 const gchar *string_format = NULL;
9167 MMPlayerVideoStreamDataType *stream = NULL;
9169 MMPixelFormatType format;
9171 caps = gst_pad_get_current_caps(pad);
9173 LOGE("Caps is NULL.");
9177 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9178 structure = gst_caps_get_structure(caps, 0);
9179 gst_structure_get_int(structure, "width", &width);
9180 gst_structure_get_int(structure, "height", &height);
9181 string_format = gst_structure_get_string(structure, "format");
9183 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9184 format = util_get_pixtype(fourcc);
9185 gst_caps_unref(caps);
9188 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9189 LOGE("Wrong condition!!");
9193 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9195 LOGE("failed to alloc mem for video data");
9199 stream->width = width;
9200 stream->height = height;
9201 stream->format = format;
9207 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9209 unsigned int pitch = 0;
9211 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9213 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9214 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9215 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9216 stream->stride[index] = pitch;
9217 stream->elevation[index] = stream->height;
9222 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9224 if (stream->format == MM_PIXEL_FORMAT_I420) {
9225 int ret = TBM_SURFACE_ERROR_NONE;
9226 tbm_surface_h surface;
9227 tbm_surface_info_s info;
9229 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9231 ret = tbm_surface_get_info(surface, &info);
9232 if (ret != TBM_SURFACE_ERROR_NONE) {
9233 tbm_surface_destroy(surface);
9237 tbm_surface_destroy(surface);
9238 stream->stride[0] = info.planes[0].stride;
9239 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9240 stream->stride[1] = info.planes[1].stride;
9241 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9242 stream->stride[2] = info.planes[2].stride;
9243 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9244 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9245 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9246 stream->stride[0] = stream->width * 4;
9247 stream->elevation[0] = stream->height;
9248 stream->bo_size = stream->stride[0] * stream->height;
9250 LOGE("Not support format %d", stream->format);
9258 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9260 tbm_bo_handle thandle;
9262 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9263 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9264 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9268 unsigned char *src = NULL;
9269 unsigned char *dest = NULL;
9270 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9272 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9274 LOGE("fail to gst_memory_map");
9278 if (!mapinfo.data) {
9279 LOGE("data pointer is wrong");
9283 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9284 if (!stream->bo[0]) {
9285 LOGE("Fail to tbm_bo_alloc!!");
9289 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9291 LOGE("thandle pointer is wrong");
9295 if (stream->format == MM_PIXEL_FORMAT_I420) {
9296 src_stride[0] = GST_ROUND_UP_4(stream->width);
9297 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9298 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9299 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9302 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9303 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9305 for (i = 0; i < 3; i++) {
9306 src = mapinfo.data + src_offset[i];
9307 dest = thandle.ptr + dest_offset[i];
9312 for (j = 0; j < stream->height >> k; j++) {
9313 memcpy(dest, src, stream->width>>k);
9314 src += src_stride[i];
9315 dest += stream->stride[i];
9318 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9319 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9321 LOGE("Not support format %d", stream->format);
9325 tbm_bo_unmap(stream->bo[0]);
9326 gst_memory_unmap(mem, &mapinfo);
9332 tbm_bo_unmap(stream->bo[0]);
9335 gst_memory_unmap(mem, &mapinfo);
9341 __mmplayer_set_pause_state(mm_player_t *player)
9343 if (player->sent_bos)
9346 /* rtsp case, get content attrs by GstMessage */
9347 if (MMPLAYER_IS_RTSP_STREAMING(player))
9350 /* it's first time to update all content attrs. */
9351 __mmplayer_update_content_attrs(player, ATTR_ALL);
9355 __mmplayer_set_playing_state(mm_player_t *player)
9357 gchar *audio_codec = NULL;
9359 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9360 /* initialize because auto resume is done well. */
9361 player->resumed_by_rewind = FALSE;
9362 player->playback_rate = 1.0;
9365 if (player->sent_bos)
9368 /* try to get content metadata */
9370 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9371 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9372 * legacy mmfw-player api
9374 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9376 if ((player->cmd == MMPLAYER_COMMAND_START)
9377 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9378 __mmplayer_handle_missed_plugin(player);
9381 /* check audio codec field is set or not
9382 * we can get it from typefinder or codec's caps.
9384 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9386 /* The codec format can't be sent for audio only case like amr, mid etc.
9387 * Because, parser don't make related TAG.
9388 * So, if it's not set yet, fill it with found data.
9391 if (g_strrstr(player->type, "audio/midi"))
9392 audio_codec = "MIDI";
9393 else if (g_strrstr(player->type, "audio/x-amr"))
9394 audio_codec = "AMR";
9395 else if (g_strrstr(player->type, "audio/mpeg")
9396 && !g_strrstr(player->type, "mpegversion=(int)1"))
9397 audio_codec = "AAC";
9399 audio_codec = "unknown";
9401 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9403 if (mm_attrs_commit_all(player->attrs))
9404 LOGE("failed to update attributes");
9406 LOGD("set audio codec type with caps");