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(mmplayer_t *player);
136 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
137 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
139 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_sink_bin(mmplayer_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(mmplayer_t *player, GstCaps *caps);
154 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_release_misc(mmplayer_t *player);
156 static void __mmplayer_release_misc_post(mmplayer_t *player);
157 static gboolean __mmplayer_init_gstreamer(mmplayer_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(mmplayer_t *player, mmplayer_track_type_e type, int index);
163 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
164 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
165 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
166 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
167 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
168 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
169 static gpointer __mmplayer_gapless_play_thread(gpointer data);
170 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_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(mmplayer_t *player);
174 static int __mmplayer_gst_unrealize(mmplayer_t *player);
175 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
176 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
179 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
180 static void __mmplayer_activate_next_source(mmplayer_t *player, GstState target);
181 static void __mmplayer_check_pipeline(mmplayer_t *player);
182 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
183 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
184 static int __mmplayer_gst_create_plain_text_elements(mmplayer_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(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
188 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e 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(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_t *player, mmplayer_command_state_e command)
431 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
432 mmplayer_state_e 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 mmplayer_t *player = (mmplayer_t *)data;
601 mmplayer_gst_element_t *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 mmplayer_t *player = (mmplayer_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(mmplayer_t *player, mmplayer_gst_element_t *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(mmplayer_t *player, mmplayer_track_type_e 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 mmplayer_t *player = (mmplayer_t *)data;
831 GstCaps *caps = NULL;
832 GstStructure *str = NULL;
833 const gchar *name = NULL;
834 mmplayer_track_type_e 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(mmplayer_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(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e 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 mmplayer_t *player = (mmplayer_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 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1083 mmplayer_track_type_e 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(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e 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(mmplayer_t *player, mmplayer_track_type_e 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(mmplayer_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(mmplayer_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(mmplayer_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 mmplayer_t *player = NULL;
1377 GstElement *video_selector = NULL;
1378 GstElement *audio_selector = NULL;
1379 GstElement *text_selector = NULL;
1382 player = (mmplayer_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(mmplayer_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 mmplayer_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 = (mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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 mmplayer_t *player = (mmplayer_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 mmplayer_t *player = (mmplayer_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 mmplayer_gst_element_t *element = NULL;
2105 mmplayer_gst_element_t *prv_element = NULL;
2106 gint successful_link_count = 0;
2110 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2112 prv_element = (mmplayer_gst_element_t *)bucket->data;
2113 bucket = bucket->next;
2115 for (; bucket; bucket = bucket->next) {
2116 element = (mmplayer_gst_element_t *)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 mmplayer_gst_element_t *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 = (mmplayer_gst_element_t *)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 mmplayer_t *player = (mmplayer_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(mmplayer_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 mmplayer_audio_stream_buff_t *tmp = (mmplayer_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(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2283 mmplayer_audio_decoded_data_info_t 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 mmplayer_t *player = (mmplayer_t *)data;
2309 gint endianness = 0;
2310 guint64 channel_mask = 0;
2311 void *a_data = NULL;
2313 mmplayer_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 mmplayer_audio_stream_buff_t *tmp = (mmplayer_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 = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_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 mmplayer_t *player = (mmplayer_t *)data;
2413 mmplayer_gst_element_t *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(mmplayer_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 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2508 stream_type, stream_id);
2509 props = gst_structure_from_string(stream_props, NULL);
2510 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2511 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2512 gst_structure_free(props);
2515 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2517 switch (latency_mode) {
2518 case AUDIO_LATENCY_MODE_LOW:
2519 latency = g_strndup("low", 3);
2521 case AUDIO_LATENCY_MODE_MID:
2522 latency = g_strndup("mid", 3);
2524 case AUDIO_LATENCY_MODE_HIGH:
2525 latency = g_strndup("high", 4);
2529 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2533 LOGD("audiosink property - latency=%s", latency);
2535 MMPLAYER_FREEIF(latency);
2541 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2543 mmplayer_gst_element_t *audiobin = NULL;
2546 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2548 audiobin = player->pipeline->audiobin;
2550 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2551 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2552 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2554 if (player->video360_yaw_radians <= M_PI &&
2555 player->video360_yaw_radians >= -M_PI &&
2556 player->video360_pitch_radians <= M_PI_2 &&
2557 player->video360_pitch_radians >= -M_PI_2) {
2558 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2559 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2560 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2561 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2562 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2563 "source-orientation-y", player->video360_metadata.init_view_heading,
2564 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2571 __mmplayer_gst_fill_audio_bucket(mmplayer_t *player, GList **bucket)
2573 mmplayer_gst_element_t *audiobin = NULL;
2574 MMHandleType attrs = 0;
2575 GList *element_bucket = NULL;
2576 GstCaps *acaps = NULL;
2577 GstPad *sink_pad = NULL;
2578 int pitch_control = 0;
2579 double pitch_value = 1.0;
2582 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2583 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2585 audiobin = player->pipeline->audiobin;
2586 attrs = MMPLAYER_GET_ATTRS(player);
2588 if (player->build_audio_offload) { /* skip all the audio filters */
2589 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2590 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2591 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2592 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2597 mm_attrs_multiple_get(player->attrs, NULL,
2598 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2599 MM_PLAYER_PITCH_VALUE, &pitch_value,
2602 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2603 if (pitch_control && (player->videodec_linked == 0)) {
2604 GstElementFactory *factory;
2606 factory = gst_element_factory_find("pitch");
2608 gst_object_unref(factory);
2611 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2615 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2617 LOGW("there is no pitch element");
2622 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2624 /* replaygain volume */
2625 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2626 if (player->sound.rg_enable)
2627 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2629 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2632 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2634 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2635 gchar *dst_format = NULL;
2637 int dst_samplerate = 0;
2638 int dst_channels = 0;
2639 GstCaps *caps = NULL;
2640 char *caps_str = NULL;
2642 /* get conf. values */
2643 mm_attrs_multiple_get(player->attrs, NULL,
2644 "pcm_audioformat", &dst_format, &dst_len,
2645 "pcm_extraction_samplerate", &dst_samplerate,
2646 "pcm_extraction_channels", &dst_channels,
2649 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2653 caps = gst_caps_new_simple("audio/x-raw",
2654 "format", G_TYPE_STRING, dst_format,
2655 "rate", G_TYPE_INT, dst_samplerate,
2656 "channels", G_TYPE_INT, dst_channels,
2659 caps_str = gst_caps_to_string(caps);
2660 LOGD("new caps : %s", caps_str);
2662 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2665 gst_caps_unref(caps);
2666 MMPLAYER_FREEIF(caps_str);
2668 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2670 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2672 /* raw pad handling signal, audiosink will be added after getting signal */
2673 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2674 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2678 /* normal playback */
2681 /* for logical volume control */
2682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2683 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2685 if (player->sound.mute) {
2686 LOGD("mute enabled");
2687 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2690 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2692 /* audio effect element. if audio effect is enabled */
2693 if ((strcmp(player->ini.audioeffect_element, ""))
2695 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2698 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2700 if ((!player->bypass_audio_effect)
2701 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2702 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2703 if (!_mmplayer_audio_effect_custom_apply(player))
2704 LOGI("apply audio effect(custom) setting success");
2708 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2709 && (player->set_mode.rich_audio))
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2713 /* create audio sink */
2714 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2715 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2716 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2718 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2719 if (player->is_360_feature_enabled &&
2720 player->is_content_spherical &&
2722 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2723 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2724 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2726 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2730 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2731 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2733 gst_caps_unref(acaps);
2735 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2737 player->is_openal_plugin_used = TRUE;
2739 if (player->is_360_feature_enabled && player->is_content_spherical)
2740 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2741 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2744 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2745 (player->videodec_linked && player->ini.use_system_clock)) {
2746 LOGD("system clock will be used.");
2747 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2750 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2751 __mmplayer_gst_set_pulsesink_property(player, attrs);
2752 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2753 __mmplayer_gst_set_openalsink_property(player);
2756 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2757 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2759 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2760 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2761 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2762 gst_object_unref(GST_OBJECT(sink_pad));
2764 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2768 *bucket = element_bucket;
2771 return MM_ERROR_NONE;
2774 g_list_free(element_bucket);
2778 return MM_ERROR_PLAYER_INTERNAL;
2782 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2784 mmplayer_gst_element_t *first_element = NULL;
2785 mmplayer_gst_element_t *audiobin = NULL;
2787 GstPad *ghostpad = NULL;
2788 GList *element_bucket = NULL;
2792 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2795 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2797 LOGE("failed to allocate memory for audiobin");
2798 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2802 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2803 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2804 if (!audiobin[MMPLAYER_A_BIN].gst) {
2805 LOGE("failed to create audiobin");
2810 player->pipeline->audiobin = audiobin;
2812 /* create audio filters and audiosink */
2813 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2816 /* adding created elements to bin */
2817 LOGD("adding created elements to bin");
2818 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2821 /* linking elements in the bucket by added order. */
2822 LOGD("Linking elements in the bucket by added order.");
2823 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2826 /* get first element's sinkpad for creating ghostpad */
2827 first_element = (mmplayer_gst_element_t *)element_bucket->data;
2828 if (!first_element) {
2829 LOGE("failed to get first elem");
2833 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2835 LOGE("failed to get pad from first element of audiobin");
2839 ghostpad = gst_ghost_pad_new("sink", pad);
2841 LOGE("failed to create ghostpad");
2845 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2846 LOGE("failed to add ghostpad to audiobin");
2850 gst_object_unref(pad);
2852 g_list_free(element_bucket);
2855 return MM_ERROR_NONE;
2858 LOGD("ERROR : releasing audiobin");
2861 gst_object_unref(GST_OBJECT(pad));
2864 gst_object_unref(GST_OBJECT(ghostpad));
2867 g_list_free(element_bucket);
2869 /* release element which are not added to bin */
2870 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2871 /* NOTE : skip bin */
2872 if (audiobin[i].gst) {
2873 GstObject *parent = NULL;
2874 parent = gst_element_get_parent(audiobin[i].gst);
2877 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2878 audiobin[i].gst = NULL;
2880 gst_object_unref(GST_OBJECT(parent));
2884 /* release audiobin with it's childs */
2885 if (audiobin[MMPLAYER_A_BIN].gst)
2886 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2888 MMPLAYER_FREEIF(audiobin);
2890 player->pipeline->audiobin = NULL;
2892 return MM_ERROR_PLAYER_INTERNAL;
2896 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2898 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2902 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
2904 int ret = MM_ERROR_NONE;
2906 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2907 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2909 MMPLAYER_VIDEO_BO_LOCK(player);
2911 if (player->video_bo_list) {
2912 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2913 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
2914 if (tmp && tmp->bo == bo) {
2916 LOGD("release bo %p", bo);
2917 tbm_bo_unref(tmp->bo);
2918 MMPLAYER_VIDEO_BO_UNLOCK(player);
2919 MMPLAYER_VIDEO_BO_SIGNAL(player);
2924 /* hw codec is running or the list was reset for DRC. */
2925 LOGW("there is no bo list.");
2927 MMPLAYER_VIDEO_BO_UNLOCK(player);
2929 LOGW("failed to find bo %p", bo);
2934 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
2939 MMPLAYER_RETURN_IF_FAIL(player);
2941 MMPLAYER_VIDEO_BO_LOCK(player);
2942 if (player->video_bo_list) {
2943 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2944 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2945 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
2948 tbm_bo_unref(tmp->bo);
2952 g_list_free(player->video_bo_list);
2953 player->video_bo_list = NULL;
2955 player->video_bo_size = 0;
2956 MMPLAYER_VIDEO_BO_UNLOCK(player);
2963 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
2966 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2967 gboolean ret = TRUE;
2969 /* check DRC, if it is, destroy the prev bo list to create again */
2970 if (player->video_bo_size != size) {
2971 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2972 __mmplayer_video_stream_destroy_bo_list(player);
2973 player->video_bo_size = size;
2976 MMPLAYER_VIDEO_BO_LOCK(player);
2978 if ((!player->video_bo_list) ||
2979 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2981 /* create bo list */
2983 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2985 if (player->video_bo_list) {
2986 /* if bo list did not created all, try it again. */
2987 idx = g_list_length(player->video_bo_list);
2988 LOGD("bo list exist(len: %d)", idx);
2991 for (; idx < player->ini.num_of_video_bo; idx++) {
2992 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
2994 LOGE("Fail to alloc bo_info.");
2997 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2999 LOGE("Fail to tbm_bo_alloc.");
3000 MMPLAYER_FREEIF(bo_info);
3003 bo_info->used = FALSE;
3004 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3007 /* update video num buffers */
3008 player->video_num_buffers = idx;
3009 if (idx == player->ini.num_of_video_bo)
3010 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3013 MMPLAYER_VIDEO_BO_UNLOCK(player);
3017 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3021 /* get bo from list*/
3022 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3023 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3024 if (tmp && (tmp->used == FALSE)) {
3025 LOGD("found bo %p to use", tmp->bo);
3027 MMPLAYER_VIDEO_BO_UNLOCK(player);
3028 return tbm_bo_ref(tmp->bo);
3032 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3033 MMPLAYER_VIDEO_BO_UNLOCK(player);
3037 if (player->ini.video_bo_timeout <= 0) {
3038 MMPLAYER_VIDEO_BO_WAIT(player);
3040 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3041 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3048 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3050 mmplayer_t *player = (mmplayer_t *)data;
3052 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3054 /* send prerolled pkt */
3055 player->video_stream_prerolled = false;
3057 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3059 /* not to send prerolled pkt again */
3060 player->video_stream_prerolled = true;
3064 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3066 mmplayer_t *player = (mmplayer_t *)data;
3067 mmplayer_video_decoded_data_info_t *stream = NULL;
3068 GstMemory *mem = NULL;
3071 MMPLAYER_RETURN_IF_FAIL(player);
3072 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3074 if (player->video_stream_prerolled) {
3075 player->video_stream_prerolled = false;
3076 LOGD("skip the prerolled pkt not to send it again");
3080 /* clear stream data structure */
3081 stream = __mmplayer_create_stream_from_pad(pad);
3083 LOGE("failed to alloc stream");
3087 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3089 /* set size and timestamp */
3090 mem = gst_buffer_peek_memory(buffer, 0);
3091 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3092 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3094 /* check zero-copy */
3095 if (player->set_mode.video_zc &&
3096 player->set_mode.media_packet_video_stream &&
3097 gst_is_tizen_memory(mem)) {
3098 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3099 stream->internal_buffer = gst_buffer_ref(buffer);
3100 } else { /* sw codec */
3101 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3104 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3108 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3109 LOGE("failed to send video stream data.");
3116 LOGE("release video stream resource.");
3117 if (gst_is_tizen_memory(mem)) {
3119 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3121 tbm_bo_unref(stream->bo[i]);
3124 /* unref gst buffer */
3125 if (stream->internal_buffer)
3126 gst_buffer_unref(stream->internal_buffer);
3129 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3131 MMPLAYER_FREEIF(stream);
3136 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3138 mmplayer_gst_element_t *videobin = NULL;
3141 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3143 videobin = player->pipeline->videobin;
3145 /* Set spatial media metadata and/or user settings to the element.
3147 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3148 "projection-type", player->video360_metadata.projection_type, NULL);
3150 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3151 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3153 if (player->video360_metadata.full_pano_width_pixels &&
3154 player->video360_metadata.full_pano_height_pixels &&
3155 player->video360_metadata.cropped_area_image_width &&
3156 player->video360_metadata.cropped_area_image_height) {
3157 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3158 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3159 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3160 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3161 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3162 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3163 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3167 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3168 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3169 "horizontal-fov", player->video360_horizontal_fov,
3170 "vertical-fov", player->video360_vertical_fov, NULL);
3173 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3174 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3175 "zoom", 1.0f / player->video360_zoom, NULL);
3178 if (player->video360_yaw_radians <= M_PI &&
3179 player->video360_yaw_radians >= -M_PI &&
3180 player->video360_pitch_radians <= M_PI_2 &&
3181 player->video360_pitch_radians >= -M_PI_2) {
3182 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3183 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3184 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3185 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3186 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3187 "pose-yaw", player->video360_metadata.init_view_heading,
3188 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3191 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3192 "passthrough", !player->is_video360_enabled, NULL);
3199 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3201 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3202 GList *element_bucket = NULL;
3205 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3207 /* create video360 filter */
3208 if (player->is_360_feature_enabled && player->is_content_spherical) {
3209 LOGD("create video360 element");
3210 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3211 __mmplayer_gst_set_video360_property(player);
3215 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3216 LOGD("skip creating the videoconv and rotator");
3217 return MM_ERROR_NONE;
3220 /* in case of sw codec & overlay surface type, except 360 playback.
3221 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3222 LOGD("create video converter: %s", video_csc);
3223 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3226 *bucket = element_bucket;
3228 return MM_ERROR_NONE;
3230 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3231 g_list_free(element_bucket);
3235 return MM_ERROR_PLAYER_INTERNAL;
3239 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3241 gchar *factory_name = NULL;
3243 switch (surface_type) {
3244 case MM_DISPLAY_SURFACE_OVERLAY:
3245 if (strlen(player->ini.videosink_element_overlay) > 0)
3246 factory_name = player->ini.videosink_element_overlay;
3248 case MM_DISPLAY_SURFACE_REMOTE:
3249 case MM_DISPLAY_SURFACE_NULL:
3250 if (strlen(player->ini.videosink_element_fake) > 0)
3251 factory_name = player->ini.videosink_element_fake;
3254 LOGE("unidentified surface type");
3258 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3259 return factory_name;
3263 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3265 gchar *factory_name = NULL;
3266 mmplayer_gst_element_t *videobin = NULL;
3271 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3273 videobin = player->pipeline->videobin;
3274 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3276 attrs = MMPLAYER_GET_ATTRS(player);
3278 LOGE("cannot get content attribute");
3279 return MM_ERROR_PLAYER_INTERNAL;
3282 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3283 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3284 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3286 /* support shard memory with S/W codec on HawkP */
3287 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3288 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3289 "use-tbm", use_tbm, NULL);
3293 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3294 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3297 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3299 LOGD("disable last-sample");
3300 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3303 if (player->set_mode.media_packet_video_stream) {
3305 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3306 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3307 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3309 __mmplayer_add_signal_connection(player,
3310 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3311 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3313 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3316 __mmplayer_add_signal_connection(player,
3317 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3318 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3320 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3324 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3325 return MM_ERROR_PLAYER_INTERNAL;
3327 if (videobin[MMPLAYER_V_SINK].gst) {
3328 GstPad *sink_pad = NULL;
3329 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3331 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3332 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3333 gst_object_unref(GST_OBJECT(sink_pad));
3335 LOGE("failed to get sink pad from videosink");
3339 return MM_ERROR_NONE;
3344 * - video overlay surface(arm/x86) : tizenwlsink
3347 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3350 GList *element_bucket = NULL;
3351 mmplayer_gst_element_t *first_element = NULL;
3352 mmplayer_gst_element_t *videobin = NULL;
3353 gchar *videosink_factory_name = NULL;
3356 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3359 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3361 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3363 player->pipeline->videobin = videobin;
3366 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3367 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3368 if (!videobin[MMPLAYER_V_BIN].gst) {
3369 LOGE("failed to create videobin");
3373 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3376 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3377 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3379 /* additional setting for sink plug-in */
3380 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3381 LOGE("failed to set video property");
3385 /* store it as it's sink element */
3386 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3388 /* adding created elements to bin */
3389 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3390 LOGE("failed to add elements");
3394 /* Linking elements in the bucket by added order */
3395 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3396 LOGE("failed to link elements");
3400 /* get first element's sinkpad for creating ghostpad */
3401 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3402 if (!first_element) {
3403 LOGE("failed to get first element from bucket");
3407 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3409 LOGE("failed to get pad from first element");
3413 /* create ghostpad */
3414 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3415 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3416 LOGE("failed to add ghostpad to videobin");
3419 gst_object_unref(pad);
3421 /* done. free allocated variables */
3422 g_list_free(element_bucket);
3426 return MM_ERROR_NONE;
3429 LOGE("ERROR : releasing videobin");
3430 g_list_free(element_bucket);
3433 gst_object_unref(GST_OBJECT(pad));
3435 /* release videobin with it's childs */
3436 if (videobin[MMPLAYER_V_BIN].gst)
3437 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3439 MMPLAYER_FREEIF(videobin);
3440 player->pipeline->videobin = NULL;
3442 return MM_ERROR_PLAYER_INTERNAL;
3446 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3448 GList *element_bucket = NULL;
3449 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3451 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3452 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3453 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3454 "signal-handoffs", FALSE,
3457 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3458 __mmplayer_add_signal_connection(player,
3459 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3460 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3462 G_CALLBACK(__mmplayer_update_subtitle),
3465 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3466 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3468 if (!player->play_subtitle) {
3469 LOGD("add textbin sink as sink element of whole pipeline.");
3470 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3473 /* adding created elements to bin */
3474 LOGD("adding created elements to bin");
3475 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3476 LOGE("failed to add elements");
3480 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3481 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3482 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3484 /* linking elements in the bucket by added order. */
3485 LOGD("Linking elements in the bucket by added order.");
3486 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3487 LOGE("failed to link elements");
3491 /* done. free allocated variables */
3492 g_list_free(element_bucket);
3494 if (textbin[MMPLAYER_T_QUEUE].gst) {
3496 GstPad *ghostpad = NULL;
3498 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3500 LOGE("failed to get sink pad of text queue");
3504 ghostpad = gst_ghost_pad_new("text_sink", pad);
3505 gst_object_unref(pad);
3508 LOGE("failed to create ghostpad of textbin");
3512 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3513 LOGE("failed to add ghostpad to textbin");
3514 gst_object_unref(ghostpad);
3519 return MM_ERROR_NONE;
3522 g_list_free(element_bucket);
3524 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3525 LOGE("remove textbin sink from sink list");
3526 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3529 /* release element at __mmplayer_gst_create_text_sink_bin */
3530 return MM_ERROR_PLAYER_INTERNAL;
3534 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3536 mmplayer_gst_element_t *textbin = NULL;
3537 GList *element_bucket = NULL;
3538 int surface_type = 0;
3543 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3546 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3548 LOGE("failed to allocate memory for textbin");
3549 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3553 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3554 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3555 if (!textbin[MMPLAYER_T_BIN].gst) {
3556 LOGE("failed to create textbin");
3561 player->pipeline->textbin = textbin;
3564 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3565 LOGD("surface type for subtitle : %d", surface_type);
3566 switch (surface_type) {
3567 case MM_DISPLAY_SURFACE_OVERLAY:
3568 case MM_DISPLAY_SURFACE_NULL:
3569 case MM_DISPLAY_SURFACE_REMOTE:
3570 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3571 LOGE("failed to make plain text elements");
3582 return MM_ERROR_NONE;
3586 LOGD("ERROR : releasing textbin");
3588 g_list_free(element_bucket);
3590 /* release signal */
3591 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3593 /* release element which are not added to bin */
3594 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3595 /* NOTE : skip bin */
3596 if (textbin[i].gst) {
3597 GstObject *parent = NULL;
3598 parent = gst_element_get_parent(textbin[i].gst);
3601 gst_object_unref(GST_OBJECT(textbin[i].gst));
3602 textbin[i].gst = NULL;
3604 gst_object_unref(GST_OBJECT(parent));
3609 /* release textbin with it's childs */
3610 if (textbin[MMPLAYER_T_BIN].gst)
3611 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3613 MMPLAYER_FREEIF(player->pipeline->textbin);
3614 player->pipeline->textbin = NULL;
3617 return MM_ERROR_PLAYER_INTERNAL;
3621 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3623 mmplayer_gst_element_t *mainbin = NULL;
3624 mmplayer_gst_element_t *textbin = NULL;
3625 MMHandleType attrs = 0;
3626 GstElement *subsrc = NULL;
3627 GstElement *subparse = NULL;
3628 gchar *subtitle_uri = NULL;
3629 const gchar *charset = NULL;
3635 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3637 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3639 mainbin = player->pipeline->mainbin;
3641 attrs = MMPLAYER_GET_ATTRS(player);
3643 LOGE("cannot get content attribute");
3644 return MM_ERROR_PLAYER_INTERNAL;
3647 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3648 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3649 LOGE("subtitle uri is not proper filepath.");
3650 return MM_ERROR_PLAYER_INVALID_URI;
3653 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3654 LOGE("failed to get storage info of subtitle path");
3655 return MM_ERROR_PLAYER_INVALID_URI;
3658 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3660 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3661 player->subtitle_language_list = NULL;
3662 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3664 /* create the subtitle source */
3665 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3667 LOGE("failed to create filesrc element");
3670 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3672 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3673 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3675 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3676 LOGW("failed to add queue");
3677 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3678 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3679 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3684 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3686 LOGE("failed to create subparse element");
3690 charset = util_get_charset(subtitle_uri);
3692 LOGD("detected charset is %s", charset);
3693 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3696 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3697 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3699 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3700 LOGW("failed to add subparse");
3701 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3702 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3703 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3707 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3708 LOGW("failed to link subsrc and subparse");
3712 player->play_subtitle = TRUE;
3713 player->adjust_subtitle_pos = 0;
3715 LOGD("play subtitle using subtitle file");
3717 if (player->pipeline->textbin == NULL) {
3718 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3719 LOGE("failed to create text sink bin. continuing without text");
3723 textbin = player->pipeline->textbin;
3725 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3726 LOGW("failed to add textbin");
3728 /* release signal */
3729 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3731 /* release textbin with it's childs */
3732 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3733 MMPLAYER_FREEIF(player->pipeline->textbin);
3734 player->pipeline->textbin = textbin = NULL;
3738 LOGD("link text input selector and textbin ghost pad");
3740 player->textsink_linked = 1;
3741 player->external_text_idx = 0;
3742 LOGI("textsink is linked");
3744 textbin = player->pipeline->textbin;
3745 LOGD("text bin has been created. reuse it.");
3746 player->external_text_idx = 1;
3749 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3750 LOGW("failed to link subparse and textbin");
3754 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3756 LOGE("failed to get sink pad from textsink to probe data");
3760 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3761 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3763 gst_object_unref(pad);
3766 /* create dot. for debugging */
3767 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3770 return MM_ERROR_NONE;
3773 /* release text pipeline resource */
3774 player->textsink_linked = 0;
3776 /* release signal */
3777 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3779 if (player->pipeline->textbin) {
3780 LOGE("remove textbin");
3782 /* release textbin with it's childs */
3783 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3784 MMPLAYER_FREEIF(player->pipeline->textbin);
3785 player->pipeline->textbin = NULL;
3789 /* release subtitle elem */
3790 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3791 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3793 return MM_ERROR_PLAYER_INTERNAL;
3797 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3799 mmplayer_t *player = (mmplayer_t *)data;
3800 MMMessageParamType msg = {0, };
3801 GstClockTime duration = 0;
3802 gpointer text = NULL;
3803 guint text_size = 0;
3804 gboolean ret = TRUE;
3805 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3809 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3810 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3812 if (player->is_subtitle_force_drop) {
3813 LOGW("subtitle is dropped forcedly.");
3817 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3818 text = mapinfo.data;
3819 text_size = mapinfo.size;
3821 if (player->set_mode.subtitle_off) {
3822 LOGD("subtitle is OFF.");
3826 if (!text || (text_size == 0)) {
3827 LOGD("There is no subtitle to be displayed.");
3831 msg.data = (void *)text;
3833 duration = GST_BUFFER_DURATION(buffer);
3835 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3836 if (player->duration > GST_BUFFER_PTS(buffer))
3837 duration = player->duration - GST_BUFFER_PTS(buffer);
3840 LOGI("subtitle duration is invalid, subtitle duration change "
3841 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3843 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3845 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3847 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3848 gst_buffer_unmap(buffer, &mapinfo);
3855 static GstPadProbeReturn
3856 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3858 mmplayer_t *player = (mmplayer_t *)u_data;
3859 GstClockTime cur_timestamp = 0;
3860 gint64 adjusted_timestamp = 0;
3861 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3863 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3865 if (player->set_mode.subtitle_off) {
3866 LOGD("subtitle is OFF.");
3870 if (player->adjust_subtitle_pos == 0) {
3871 LOGD("nothing to do");
3875 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3876 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3878 if (adjusted_timestamp < 0) {
3879 LOGD("adjusted_timestamp under zero");
3884 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3885 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3886 GST_TIME_ARGS(cur_timestamp),
3887 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3889 return GST_PAD_PROBE_OK;
3893 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
3897 /* check player and subtitlebin are created */
3898 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3899 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3901 if (position == 0) {
3902 LOGD("nothing to do");
3904 return MM_ERROR_NONE;
3907 /* check current postion */
3908 player->adjust_subtitle_pos = position;
3910 LOGD("save adjust_subtitle_pos in player");
3914 return MM_ERROR_NONE;
3918 * This function is to create audio or video pipeline for playing.
3920 * @param player [in] handle of player
3922 * @return This function returns zero on success.
3927 __mmplayer_gst_create_pipeline(mmplayer_t *player)
3929 int ret = MM_ERROR_NONE;
3930 mmplayer_gst_element_t *mainbin = NULL;
3931 MMHandleType attrs = 0;
3934 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3936 /* get profile attribute */
3937 attrs = MMPLAYER_GET_ATTRS(player);
3939 LOGE("failed to get content attribute");
3943 /* create pipeline handles */
3944 if (player->pipeline) {
3945 LOGE("pipeline should be released before create new one");
3949 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
3950 if (player->pipeline == NULL)
3953 /* create mainbin */
3954 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
3955 if (mainbin == NULL)
3958 /* create pipeline */
3959 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3960 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3961 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3962 LOGE("failed to create pipeline");
3967 player->pipeline->mainbin = mainbin;
3969 /* create the source and decoder elements */
3970 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3971 ret = __mmplayer_gst_build_es_pipeline(player);
3973 ret = __mmplayer_gst_build_pipeline(player);
3975 if (ret != MM_ERROR_NONE) {
3976 LOGE("failed to create some elements");
3980 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3981 if (__mmplayer_check_subtitle(player)
3982 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3983 LOGE("failed to create text pipeline");
3986 ret = __mmplayer_gst_add_bus_watch(player);
3987 if (ret != MM_ERROR_NONE) {
3988 LOGE("failed to add bus watch");
3993 return MM_ERROR_NONE;
3996 __mmplayer_gst_destroy_pipeline(player);
3997 return MM_ERROR_PLAYER_INTERNAL;
4001 __mmplayer_reset_gapless_state(mmplayer_t *player)
4004 MMPLAYER_RETURN_IF_FAIL(player
4006 && player->pipeline->audiobin
4007 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4009 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4016 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4019 int ret = MM_ERROR_NONE;
4023 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4025 /* cleanup stuffs */
4026 MMPLAYER_FREEIF(player->type);
4027 player->no_more_pad = FALSE;
4028 player->num_dynamic_pad = 0;
4029 player->demux_pad_index = 0;
4031 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4032 player->subtitle_language_list = NULL;
4033 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4035 __mmplayer_reset_gapless_state(player);
4037 if (player->streamer) {
4038 __mm_player_streaming_initialize(player->streamer, FALSE);
4039 __mm_player_streaming_destroy(player->streamer);
4040 player->streamer = NULL;
4043 /* cleanup unlinked mime type */
4044 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4045 MMPLAYER_FREEIF(player->unlinked_video_mime);
4046 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4048 /* cleanup running stuffs */
4049 __mmplayer_cancel_eos_timer(player);
4051 /* cleanup gst stuffs */
4052 if (player->pipeline) {
4053 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4054 GstTagList *tag_list = player->pipeline->tag_list;
4056 /* first we need to disconnect all signal hander */
4057 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4060 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4061 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4062 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4063 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4064 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4065 gst_object_unref(bus);
4067 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4068 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4069 if (ret != MM_ERROR_NONE) {
4070 LOGE("fail to change state to NULL");
4071 return MM_ERROR_PLAYER_INTERNAL;
4074 LOGW("succeeded in changing state to NULL");
4076 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4079 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4080 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4082 /* free avsysaudiosink
4083 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4084 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4086 MMPLAYER_FREEIF(audiobin);
4087 MMPLAYER_FREEIF(videobin);
4088 MMPLAYER_FREEIF(textbin);
4089 MMPLAYER_FREEIF(mainbin);
4093 gst_tag_list_unref(tag_list);
4095 MMPLAYER_FREEIF(player->pipeline);
4097 MMPLAYER_FREEIF(player->album_art);
4099 if (player->v_stream_caps) {
4100 gst_caps_unref(player->v_stream_caps);
4101 player->v_stream_caps = NULL;
4104 if (player->a_stream_caps) {
4105 gst_caps_unref(player->a_stream_caps);
4106 player->a_stream_caps = NULL;
4109 if (player->s_stream_caps) {
4110 gst_caps_unref(player->s_stream_caps);
4111 player->s_stream_caps = NULL;
4113 __mmplayer_track_destroy(player);
4115 if (player->sink_elements)
4116 g_list_free(player->sink_elements);
4117 player->sink_elements = NULL;
4119 if (player->bufmgr) {
4120 tbm_bufmgr_deinit(player->bufmgr);
4121 player->bufmgr = NULL;
4124 LOGW("finished destroy pipeline");
4132 __mmplayer_gst_realize(mmplayer_t *player)
4135 int ret = MM_ERROR_NONE;
4139 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4141 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4143 ret = __mmplayer_gst_create_pipeline(player);
4145 LOGE("failed to create pipeline");
4149 /* set pipeline state to READY */
4150 /* NOTE : state change to READY must be performed sync. */
4151 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4152 ret = __mmplayer_gst_set_state(player,
4153 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4155 if (ret != MM_ERROR_NONE) {
4156 /* return error if failed to set state */
4157 LOGE("failed to set READY state");
4161 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4163 /* create dot before error-return. for debugging */
4164 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4172 __mmplayer_gst_unrealize(mmplayer_t *player)
4174 int ret = MM_ERROR_NONE;
4178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4180 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4181 MMPLAYER_PRINT_STATE(player);
4183 /* release miscellaneous information */
4184 __mmplayer_release_misc(player);
4186 /* destroy pipeline */
4187 ret = __mmplayer_gst_destroy_pipeline(player);
4188 if (ret != MM_ERROR_NONE) {
4189 LOGE("failed to destory pipeline");
4193 /* release miscellaneous information.
4194 these info needs to be released after pipeline is destroyed. */
4195 __mmplayer_release_misc_post(player);
4197 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4205 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4210 LOGW("set_message_callback is called with invalid player handle");
4211 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4214 player->msg_cb = callback;
4215 player->msg_cb_param = user_param;
4217 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4221 return MM_ERROR_NONE;
4225 __mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4227 int ret = MM_ERROR_NONE;
4232 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4233 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4234 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4236 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4238 if (strstr(uri, "es_buff://")) {
4239 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4240 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4241 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4242 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4244 tmp = g_ascii_strdown(uri, strlen(uri));
4245 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4246 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4248 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4250 } else if (strstr(uri, "mms://")) {
4251 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4252 } else if ((path = strstr(uri, "mem://"))) {
4253 ret = __mmplayer_set_mem_uri(data, path, param);
4255 ret = __mmplayer_set_file_uri(data, uri);
4258 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4259 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4260 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4261 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4263 /* dump parse result */
4264 SECURE_LOGW("incoming uri : %s", uri);
4265 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4266 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4274 __mmplayer_can_do_interrupt(mmplayer_t *player)
4276 if (!player || !player->pipeline || !player->attrs) {
4277 LOGW("not initialized");
4281 if (player->audio_stream_render_cb) {
4282 LOGW("not support in pcm extraction mode");
4286 /* check if seeking */
4287 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4288 MMMessageParamType msg_param;
4289 memset(&msg_param, 0, sizeof(MMMessageParamType));
4290 msg_param.code = MM_ERROR_PLAYER_SEEK;
4291 player->seek_state = MMPLAYER_SEEK_NONE;
4292 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4296 /* check other thread */
4297 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4298 LOGW("locked already, cmd state : %d", player->cmd);
4300 /* check application command */
4301 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4302 LOGW("playing.. should wait cmd lock then, will be interrupted");
4304 /* lock will be released at mrp_resource_release_cb() */
4305 MMPLAYER_CMD_LOCK(player);
4308 LOGW("nothing to do");
4311 LOGW("can interrupt immediately");
4315 FAILED: /* with CMD UNLOCKED */
4318 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4323 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4326 mmplayer_t *player = NULL;
4330 if (user_data == NULL) {
4331 LOGE("- user_data is null");
4334 player = (mmplayer_t *)user_data;
4336 /* do something to release resource here.
4337 * player stop and interrupt forwarding */
4338 if (!__mmplayer_can_do_interrupt(player)) {
4339 LOGW("no need to interrupt, so leave");
4341 MMMessageParamType msg = {0, };
4344 player->interrupted_by_resource = TRUE;
4346 /* get last play position */
4347 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4348 LOGW("failed to get play position.");
4350 msg.union_type = MM_MSG_UNION_TIME;
4351 msg.time.elapsed = pos;
4352 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4354 LOGD("video resource conflict so, resource will be freed by unrealizing");
4355 if (_mmplayer_unrealize((MMHandleType)player))
4356 LOGW("failed to unrealize");
4358 /* lock is called in __mmplayer_can_do_interrupt() */
4359 MMPLAYER_CMD_UNLOCK(player);
4362 if (res == player->video_overlay_resource)
4363 player->video_overlay_resource = FALSE;
4365 player->video_decoder_resource = FALSE;
4373 __mmplayer_initialize_video_roi(mmplayer_t *player)
4375 player->video_roi.scale_x = 0.0;
4376 player->video_roi.scale_y = 0.0;
4377 player->video_roi.scale_width = 1.0;
4378 player->video_roi.scale_height = 1.0;
4382 _mmplayer_create_player(MMHandleType handle)
4384 int ret = MM_ERROR_PLAYER_INTERNAL;
4385 bool enabled = false;
4387 mmplayer_t *player = MM_PLAYER_CAST(handle);
4391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4393 /* initialize player state */
4394 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4395 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4396 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4397 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4399 /* check current state */
4400 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4402 /* construct attributes */
4403 player->attrs = _mmplayer_construct_attribute(handle);
4405 if (!player->attrs) {
4406 LOGE("Failed to construct attributes");
4410 /* initialize gstreamer with configured parameter */
4411 if (!__mmplayer_init_gstreamer(player)) {
4412 LOGE("Initializing gstreamer failed");
4413 _mmplayer_deconstruct_attribute(handle);
4417 /* create lock. note that g_tread_init() has already called in gst_init() */
4418 g_mutex_init(&player->fsink_lock);
4420 /* create update tag lock */
4421 g_mutex_init(&player->update_tag_lock);
4423 /* create gapless play mutex */
4424 g_mutex_init(&player->gapless_play_thread_mutex);
4426 /* create gapless play cond */
4427 g_cond_init(&player->gapless_play_thread_cond);
4429 /* create gapless play thread */
4430 player->gapless_play_thread =
4431 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4432 if (!player->gapless_play_thread) {
4433 LOGE("failed to create gapless play thread");
4434 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4435 g_mutex_clear(&player->gapless_play_thread_mutex);
4436 g_cond_clear(&player->gapless_play_thread_cond);
4440 player->bus_msg_q = g_queue_new();
4441 if (!player->bus_msg_q) {
4442 LOGE("failed to create queue for bus_msg");
4443 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4447 ret = _mmplayer_initialize_video_capture(player);
4448 if (ret != MM_ERROR_NONE) {
4449 LOGE("failed to initialize video capture");
4453 /* initialize resource manager */
4454 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4455 __resource_release_cb, player, &player->resource_manager)
4456 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4457 LOGE("failed to initialize resource manager");
4458 ret = MM_ERROR_PLAYER_INTERNAL;
4462 /* create video bo lock and cond */
4463 g_mutex_init(&player->video_bo_mutex);
4464 g_cond_init(&player->video_bo_cond);
4466 /* create media stream callback mutex */
4467 g_mutex_init(&player->media_stream_cb_lock);
4469 /* create subtitle info lock and cond */
4470 g_mutex_init(&player->subtitle_info_mutex);
4471 g_cond_init(&player->subtitle_info_cond);
4473 player->streaming_type = STREAMING_SERVICE_NONE;
4475 /* give default value of audio effect setting */
4476 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4477 player->sound.rg_enable = false;
4478 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4480 player->play_subtitle = FALSE;
4481 player->has_closed_caption = FALSE;
4482 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4483 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4484 player->pending_resume = FALSE;
4485 if (player->ini.dump_element_keyword[0][0] == '\0')
4486 player->ini.set_dump_element_flag = FALSE;
4488 player->ini.set_dump_element_flag = TRUE;
4490 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4491 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4492 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4494 /* Set video360 settings to their defaults for just-created player.
4497 player->is_360_feature_enabled = FALSE;
4498 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4499 LOGI("spherical feature info: %d", enabled);
4501 player->is_360_feature_enabled = TRUE;
4503 LOGE("failed to get spherical feature info");
4506 player->is_content_spherical = FALSE;
4507 player->is_video360_enabled = TRUE;
4508 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4509 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4510 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4511 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4512 player->video360_zoom = 1.0f;
4513 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4514 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4516 __mmplayer_initialize_video_roi(player);
4518 /* set player state to null */
4519 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4520 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4524 return MM_ERROR_NONE;
4528 g_mutex_clear(&player->fsink_lock);
4529 /* free update tag lock */
4530 g_mutex_clear(&player->update_tag_lock);
4531 g_queue_free(player->bus_msg_q);
4532 /* free gapless play thread */
4533 if (player->gapless_play_thread) {
4534 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4535 player->gapless_play_thread_exit = TRUE;
4536 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4537 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4539 g_thread_join(player->gapless_play_thread);
4540 player->gapless_play_thread = NULL;
4542 g_mutex_clear(&player->gapless_play_thread_mutex);
4543 g_cond_clear(&player->gapless_play_thread_cond);
4546 /* release attributes */
4547 _mmplayer_deconstruct_attribute(handle);
4555 __mmplayer_init_gstreamer(mmplayer_t *player)
4557 static gboolean initialized = FALSE;
4558 static const int max_argc = 50;
4560 gchar **argv = NULL;
4561 gchar **argv2 = NULL;
4567 LOGD("gstreamer already initialized.");
4572 argc = malloc(sizeof(int));
4573 argv = malloc(sizeof(gchar *) * max_argc);
4574 argv2 = malloc(sizeof(gchar *) * max_argc);
4576 if (!argc || !argv || !argv2)
4579 memset(argv, 0, sizeof(gchar *) * max_argc);
4580 memset(argv2, 0, sizeof(gchar *) * max_argc);
4584 argv[0] = g_strdup("mmplayer");
4587 for (i = 0; i < 5; i++) {
4588 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4589 if (strlen(player->ini.gst_param[i]) > 0) {
4590 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4595 /* we would not do fork for scanning plugins */
4596 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4599 /* check disable registry scan */
4600 if (player->ini.skip_rescan) {
4601 argv[*argc] = g_strdup("--gst-disable-registry-update");
4605 /* check disable segtrap */
4606 if (player->ini.disable_segtrap) {
4607 argv[*argc] = g_strdup("--gst-disable-segtrap");
4611 LOGD("initializing gstreamer with following parameter");
4612 LOGD("argc : %d", *argc);
4615 for (i = 0; i < arg_count; i++) {
4617 LOGD("argv[%d] : %s", i, argv2[i]);
4620 /* initializing gstreamer */
4621 if (!gst_init_check(argc, &argv, &err)) {
4622 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4629 for (i = 0; i < arg_count; i++) {
4630 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4631 MMPLAYER_FREEIF(argv2[i]);
4634 MMPLAYER_FREEIF(argv);
4635 MMPLAYER_FREEIF(argv2);
4636 MMPLAYER_FREEIF(argc);
4646 for (i = 0; i < arg_count; i++) {
4647 LOGD("free[%d] : %s", i, argv2[i]);
4648 MMPLAYER_FREEIF(argv2[i]);
4651 MMPLAYER_FREEIF(argv);
4652 MMPLAYER_FREEIF(argv2);
4653 MMPLAYER_FREEIF(argc);
4659 __mmplayer_check_async_state_transition(mmplayer_t *player)
4661 GstState element_state = GST_STATE_VOID_PENDING;
4662 GstState element_pending_state = GST_STATE_VOID_PENDING;
4663 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4664 GstElement *element = NULL;
4665 gboolean async = FALSE;
4667 /* check player handle */
4668 MMPLAYER_RETURN_IF_FAIL(player &&
4670 player->pipeline->mainbin &&
4671 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4674 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4676 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4677 LOGD("don't need to check the pipeline state");
4681 MMPLAYER_PRINT_STATE(player);
4683 /* wait for state transition */
4684 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4685 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4687 if (ret == GST_STATE_CHANGE_FAILURE) {
4688 LOGE(" [%s] state : %s pending : %s",
4689 GST_ELEMENT_NAME(element),
4690 gst_element_state_get_name(element_state),
4691 gst_element_state_get_name(element_pending_state));
4693 /* dump state of all element */
4694 __mmplayer_dump_pipeline_state(player);
4699 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4704 _mmplayer_destroy(MMHandleType handle)
4706 mmplayer_t *player = MM_PLAYER_CAST(handle);
4710 /* check player handle */
4711 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4713 /* destroy can called at anytime */
4714 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4716 /* check async state transition */
4717 __mmplayer_check_async_state_transition(player);
4719 /* release gapless play thread */
4720 if (player->gapless_play_thread) {
4721 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4722 player->gapless_play_thread_exit = TRUE;
4723 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4724 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4726 LOGD("waitting for gapless play thread exit");
4727 g_thread_join(player->gapless_play_thread);
4728 g_mutex_clear(&player->gapless_play_thread_mutex);
4729 g_cond_clear(&player->gapless_play_thread_cond);
4730 LOGD("gapless play thread released");
4733 _mmplayer_release_video_capture(player);
4735 /* de-initialize resource manager */
4736 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4737 player->resource_manager))
4738 LOGE("failed to deinitialize resource manager");
4740 /* release pipeline */
4741 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4742 LOGE("failed to destory pipeline");
4743 return MM_ERROR_PLAYER_INTERNAL;
4746 g_queue_free(player->bus_msg_q);
4748 /* release subtitle info lock and cond */
4749 g_mutex_clear(&player->subtitle_info_mutex);
4750 g_cond_clear(&player->subtitle_info_cond);
4752 __mmplayer_release_dump_list(player->dump_list);
4754 /* release miscellaneous information */
4755 __mmplayer_release_misc(player);
4757 /* release miscellaneous information.
4758 these info needs to be released after pipeline is destroyed. */
4759 __mmplayer_release_misc_post(player);
4761 /* release attributes */
4762 _mmplayer_deconstruct_attribute(handle);
4765 g_mutex_clear(&player->fsink_lock);
4768 g_mutex_clear(&player->update_tag_lock);
4770 /* release video bo lock and cond */
4771 g_mutex_clear(&player->video_bo_mutex);
4772 g_cond_clear(&player->video_bo_cond);
4774 /* release media stream callback lock */
4775 g_mutex_clear(&player->media_stream_cb_lock);
4779 return MM_ERROR_NONE;
4783 _mmplayer_realize(MMHandleType hplayer)
4785 mmplayer_t *player = (mmplayer_t *)hplayer;
4788 MMHandleType attrs = 0;
4789 int ret = MM_ERROR_NONE;
4793 /* check player handle */
4794 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4796 /* check current state */
4797 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4799 attrs = MMPLAYER_GET_ATTRS(player);
4801 LOGE("fail to get attributes.");
4802 return MM_ERROR_PLAYER_INTERNAL;
4804 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4805 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4807 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4808 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4810 if (ret != MM_ERROR_NONE) {
4811 LOGE("failed to parse profile");
4816 if (uri && (strstr(uri, "es_buff://"))) {
4817 if (strstr(uri, "es_buff://push_mode"))
4818 player->es_player_push_mode = TRUE;
4820 player->es_player_push_mode = FALSE;
4823 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4824 LOGW("mms protocol is not supported format.");
4825 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4828 if (MMPLAYER_IS_STREAMING(player))
4829 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4831 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4833 player->smooth_streaming = FALSE;
4834 player->videodec_linked = 0;
4835 player->audiodec_linked = 0;
4836 player->textsink_linked = 0;
4837 player->is_external_subtitle_present = FALSE;
4838 player->is_external_subtitle_added_now = FALSE;
4839 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4840 player->video360_metadata.is_spherical = -1;
4841 player->is_openal_plugin_used = FALSE;
4842 player->demux_pad_index = 0;
4843 player->subtitle_language_list = NULL;
4844 player->is_subtitle_force_drop = FALSE;
4846 __mmplayer_track_initialize(player);
4847 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4849 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4850 gint prebuffer_ms = 0, rebuffer_ms = 0;
4852 player->streamer = __mm_player_streaming_create();
4853 __mm_player_streaming_initialize(player->streamer, TRUE);
4855 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4856 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4858 if (prebuffer_ms > 0) {
4859 prebuffer_ms = MAX(prebuffer_ms, 1000);
4860 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4863 if (rebuffer_ms > 0) {
4864 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4865 rebuffer_ms = MAX(rebuffer_ms, 1000);
4866 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4869 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4870 player->streamer->buffering_req.rebuffer_time);
4873 /* realize pipeline */
4874 ret = __mmplayer_gst_realize(player);
4875 if (ret != MM_ERROR_NONE)
4876 LOGE("fail to realize the player.");
4878 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4886 _mmplayer_unrealize(MMHandleType hplayer)
4888 mmplayer_t *player = (mmplayer_t *)hplayer;
4889 int ret = MM_ERROR_NONE;
4893 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4895 MMPLAYER_CMD_UNLOCK(player);
4896 /* destroy the gst bus msg thread which is created during realize.
4897 this funct have to be called before getting cmd lock. */
4898 __mmplayer_bus_msg_thread_destroy(player);
4899 MMPLAYER_CMD_LOCK(player);
4901 /* check current state */
4902 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4904 /* check async state transition */
4905 __mmplayer_check_async_state_transition(player);
4907 /* unrealize pipeline */
4908 ret = __mmplayer_gst_unrealize(player);
4910 /* set asm stop if success */
4911 if (MM_ERROR_NONE == ret) {
4912 if (!player->interrupted_by_resource) {
4913 if (player->video_decoder_resource != NULL) {
4914 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4915 player->video_decoder_resource);
4916 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4917 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4919 player->video_decoder_resource = NULL;
4922 if (player->video_overlay_resource != NULL) {
4923 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4924 player->video_overlay_resource);
4925 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4926 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4928 player->video_overlay_resource = NULL;
4931 ret = mm_resource_manager_commit(player->resource_manager);
4932 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4933 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4936 LOGE("failed and don't change asm state to stop");
4944 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4946 mmplayer_t *player = (mmplayer_t *)hplayer;
4948 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4950 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4954 _mmplayer_get_state(MMHandleType hplayer, int *state)
4956 mmplayer_t *player = (mmplayer_t *)hplayer;
4958 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4960 *state = MMPLAYER_CURRENT_STATE(player);
4962 return MM_ERROR_NONE;
4967 _mmplayer_set_volume(MMHandleType hplayer, mmplayer_volume_type_t volume)
4969 mmplayer_t *player = (mmplayer_t *)hplayer;
4970 GstElement *vol_element = NULL;
4975 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4977 LOGD("volume [L]=%f:[R]=%f",
4978 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4980 /* invalid factor range or not */
4981 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4982 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4983 LOGE("Invalid factor!(valid factor:0~1.0)");
4984 return MM_ERROR_INVALID_ARGUMENT;
4988 /* not support to set other value into each channel */
4989 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4990 return MM_ERROR_INVALID_ARGUMENT;
4992 /* Save volume to handle. Currently the first array element will be saved. */
4993 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4995 /* check pipeline handle */
4996 if (!player->pipeline || !player->pipeline->audiobin) {
4997 LOGD("audiobin is not created yet");
4998 LOGD("but, current stored volume will be set when it's created.");
5000 /* NOTE : stored volume will be used in create_audiobin
5001 * returning MM_ERROR_NONE here makes application to able to
5002 * set volume at anytime.
5004 return MM_ERROR_NONE;
5007 /* setting volume to volume element */
5008 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5011 LOGD("volume is set [%f]", player->sound.volume);
5012 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5017 return MM_ERROR_NONE;
5021 _mmplayer_get_volume(MMHandleType hplayer, mmplayer_volume_type_t *volume)
5023 mmplayer_t *player = (mmplayer_t *)hplayer;
5028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5029 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5031 /* returning stored volume */
5032 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5033 volume->level[i] = player->sound.volume;
5037 return MM_ERROR_NONE;
5041 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5043 mmplayer_t *player = (mmplayer_t *)hplayer;
5044 GstElement *vol_element = NULL;
5048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5050 /* mute value shoud 0 or 1 */
5051 if (mute != 0 && mute != 1) {
5052 LOGE("bad mute value");
5054 /* FIXIT : definitly, we need _BAD_PARAM error code */
5055 return MM_ERROR_INVALID_ARGUMENT;
5058 player->sound.mute = mute;
5060 /* just hold mute value if pipeline is not ready */
5061 if (!player->pipeline || !player->pipeline->audiobin) {
5062 LOGD("pipeline is not ready. holding mute value");
5063 return MM_ERROR_NONE;
5066 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5068 /* NOTE : volume will only created when the bt is enabled */
5070 LOGD("mute : %d", mute);
5071 g_object_set(vol_element, "mute", mute, NULL);
5073 LOGD("volume elemnet is not created. using volume in audiosink");
5077 return MM_ERROR_NONE;
5081 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5083 mmplayer_t *player = (mmplayer_t *)hplayer;
5087 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5088 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5090 /* just hold mute value if pipeline is not ready */
5091 if (!player->pipeline || !player->pipeline->audiobin) {
5092 LOGD("pipeline is not ready. returning stored value");
5093 *pmute = player->sound.mute;
5094 return MM_ERROR_NONE;
5097 *pmute = player->sound.mute;
5101 return MM_ERROR_NONE;
5105 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5107 mmplayer_t *player = (mmplayer_t *)hplayer;
5111 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5113 player->video_stream_changed_cb = callback;
5114 player->video_stream_changed_cb_user_param = user_param;
5115 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5119 return MM_ERROR_NONE;
5123 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5125 mmplayer_t *player = (mmplayer_t *)hplayer;
5129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5131 player->audio_stream_changed_cb = callback;
5132 player->audio_stream_changed_cb_user_param = user_param;
5133 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5137 return MM_ERROR_NONE;
5141 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5143 mmplayer_t *player = (mmplayer_t *)hplayer;
5147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 player->audio_stream_render_cb = callback;
5150 player->audio_stream_cb_user_param = user_param;
5151 player->audio_stream_sink_sync = sync;
5152 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5156 return MM_ERROR_NONE;
5160 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5162 mmplayer_t *player = (mmplayer_t *)hplayer;
5166 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5168 if (callback && !player->bufmgr)
5169 player->bufmgr = tbm_bufmgr_init(-1);
5171 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5172 player->video_stream_cb = callback;
5173 player->video_stream_cb_user_param = user_param;
5175 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5179 return MM_ERROR_NONE;
5183 _mmplayer_start(MMHandleType hplayer)
5185 mmplayer_t *player = (mmplayer_t *)hplayer;
5186 gint ret = MM_ERROR_NONE;
5190 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5192 /* check current state */
5193 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5195 /* start pipeline */
5196 ret = __mmplayer_gst_start(player);
5197 if (ret != MM_ERROR_NONE)
5198 LOGE("failed to start player.");
5200 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5201 LOGD("force playing start even during buffering");
5202 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5210 /* NOTE: post "not supported codec message" to application
5211 * when one codec is not found during AUTOPLUGGING in MSL.
5212 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5213 * And, if any codec is not found, don't send message here.
5214 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5217 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5219 MMMessageParamType msg_param;
5220 memset(&msg_param, 0, sizeof(MMMessageParamType));
5221 gboolean post_msg_direct = FALSE;
5225 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5227 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5228 player->not_supported_codec, player->can_support_codec);
5230 if (player->not_found_demuxer) {
5231 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5232 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5234 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5235 MMPLAYER_FREEIF(msg_param.data);
5237 return MM_ERROR_NONE;
5240 if (player->not_supported_codec) {
5241 if (player->can_support_codec) {
5242 // There is one codec to play
5243 post_msg_direct = TRUE;
5245 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5246 post_msg_direct = TRUE;
5249 if (post_msg_direct) {
5250 MMMessageParamType msg_param;
5251 memset(&msg_param, 0, sizeof(MMMessageParamType));
5253 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5254 LOGW("not found AUDIO codec, posting error code to application.");
5256 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5257 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5258 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5259 LOGW("not found VIDEO codec, posting error code to application.");
5261 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5262 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5265 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5267 MMPLAYER_FREEIF(msg_param.data);
5269 return MM_ERROR_NONE;
5271 // no any supported codec case
5272 LOGW("not found any codec, posting error code to application.");
5274 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5275 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5276 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5278 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5279 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5282 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5284 MMPLAYER_FREEIF(msg_param.data);
5290 return MM_ERROR_NONE;
5294 __mmplayer_check_pipeline(mmplayer_t *player)
5296 GstState element_state = GST_STATE_VOID_PENDING;
5297 GstState element_pending_state = GST_STATE_VOID_PENDING;
5299 int ret = MM_ERROR_NONE;
5301 if (!player->gapless.reconfigure)
5304 LOGW("pipeline is under construction.");
5306 MMPLAYER_PLAYBACK_LOCK(player);
5307 MMPLAYER_PLAYBACK_UNLOCK(player);
5309 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5311 /* wait for state transition */
5312 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5313 if (ret == GST_STATE_CHANGE_FAILURE)
5314 LOGE("failed to change pipeline state within %d sec", timeout);
5317 /* NOTE : it should be able to call 'stop' anytime*/
5319 _mmplayer_stop(MMHandleType hplayer)
5321 mmplayer_t *player = (mmplayer_t *)hplayer;
5322 int ret = MM_ERROR_NONE;
5326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5328 /* check current state */
5329 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5331 /* check pipline building state */
5332 __mmplayer_check_pipeline(player);
5333 __mmplayer_reset_gapless_state(player);
5335 /* NOTE : application should not wait for EOS after calling STOP */
5336 __mmplayer_cancel_eos_timer(player);
5339 player->seek_state = MMPLAYER_SEEK_NONE;
5342 ret = __mmplayer_gst_stop(player);
5344 if (ret != MM_ERROR_NONE)
5345 LOGE("failed to stop player.");
5353 _mmplayer_pause(MMHandleType hplayer)
5355 mmplayer_t *player = (mmplayer_t *)hplayer;
5356 gint64 pos_nsec = 0;
5357 gboolean async = FALSE;
5358 gint ret = MM_ERROR_NONE;
5362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5364 /* check current state */
5365 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5367 /* check pipline building state */
5368 __mmplayer_check_pipeline(player);
5370 switch (MMPLAYER_CURRENT_STATE(player)) {
5371 case MM_PLAYER_STATE_READY:
5373 /* check prepare async or not.
5374 * In the case of streaming playback, it's recommned to avoid blocking wait.
5376 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5377 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5379 /* Changing back sync of rtspsrc to async */
5380 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5381 LOGD("async prepare working mode for rtsp");
5387 case MM_PLAYER_STATE_PLAYING:
5389 /* NOTE : store current point to overcome some bad operation
5390 *(returning zero when getting current position in paused state) of some
5393 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5394 LOGW("getting current position failed in paused");
5396 player->last_position = pos_nsec;
5398 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5399 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5400 This causes problem is position calculation during normal pause resume scenarios also.
5401 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5402 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5403 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5404 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5410 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5411 LOGD("doing async pause in case of ms buff src");
5415 /* pause pipeline */
5416 ret = __mmplayer_gst_pause(player, async);
5418 if (ret != MM_ERROR_NONE)
5419 LOGE("failed to pause player. ret : 0x%x", ret);
5421 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5422 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5423 LOGE("failed to update display_rotation");
5431 /* in case of streaming, pause could take long time.*/
5433 _mmplayer_abort_pause(MMHandleType hplayer)
5435 mmplayer_t *player = (mmplayer_t *)hplayer;
5436 int ret = MM_ERROR_NONE;
5440 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5442 player->pipeline->mainbin,
5443 MM_ERROR_PLAYER_NOT_INITIALIZED);
5445 LOGD("set the pipeline state to READY");
5447 /* set state to READY */
5448 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5449 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5450 if (ret != MM_ERROR_NONE) {
5451 LOGE("fail to change state to READY");
5452 return MM_ERROR_PLAYER_INTERNAL;
5455 LOGD("succeeded in changing state to READY");
5460 _mmplayer_resume(MMHandleType hplayer)
5462 mmplayer_t *player = (mmplayer_t *)hplayer;
5463 int ret = MM_ERROR_NONE;
5464 gboolean async = FALSE;
5468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5470 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5471 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5472 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5476 /* Changing back sync mode rtspsrc to async */
5477 LOGD("async resume for rtsp case");
5481 /* check current state */
5482 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5484 ret = __mmplayer_gst_resume(player, async);
5485 if (ret != MM_ERROR_NONE)
5486 LOGE("failed to resume player.");
5488 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5489 LOGD("force resume even during buffering");
5490 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5499 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5501 mmplayer_t *player = (mmplayer_t *)hplayer;
5502 gint64 pos_nsec = 0;
5503 int ret = MM_ERROR_NONE;
5505 signed long long start = 0, stop = 0;
5506 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5509 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5510 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5512 /* The sound of video is not supported under 0.0 and over 2.0. */
5513 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5514 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5517 _mmplayer_set_mute(hplayer, mute);
5519 if (player->playback_rate == rate)
5520 return MM_ERROR_NONE;
5522 /* If the position is reached at start potion during fast backward, EOS is posted.
5523 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5525 player->playback_rate = rate;
5527 current_state = MMPLAYER_CURRENT_STATE(player);
5529 if (current_state != MM_PLAYER_STATE_PAUSED)
5530 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5532 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5534 if ((current_state == MM_PLAYER_STATE_PAUSED)
5535 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5536 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5537 pos_nsec = player->last_position;
5542 stop = GST_CLOCK_TIME_NONE;
5544 start = GST_CLOCK_TIME_NONE;
5548 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5549 player->playback_rate,
5551 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5552 GST_SEEK_TYPE_SET, start,
5553 GST_SEEK_TYPE_SET, stop)) {
5554 LOGE("failed to set speed playback");
5555 return MM_ERROR_PLAYER_SEEK;
5558 LOGD("succeeded to set speed playback as %0.1f", rate);
5562 return MM_ERROR_NONE;;
5566 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5568 mmplayer_t *player = (mmplayer_t *)hplayer;
5569 int ret = MM_ERROR_NONE;
5573 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5575 /* check pipline building state */
5576 __mmplayer_check_pipeline(player);
5578 ret = __mmplayer_gst_set_position(player, position, FALSE);
5586 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5588 mmplayer_t *player = (mmplayer_t *)hplayer;
5589 int ret = MM_ERROR_NONE;
5591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5593 ret = __mmplayer_gst_get_position(player, position);
5599 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5601 mmplayer_t *player = (mmplayer_t *)hplayer;
5602 int ret = MM_ERROR_NONE;
5604 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5605 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5607 if (g_strrstr(player->type, "video/mpegts"))
5608 __mmplayer_update_duration_value(player);
5610 *duration = player->duration;
5615 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5617 mmplayer_t *player = (mmplayer_t *)hplayer;
5618 int ret = MM_ERROR_NONE;
5620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5622 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5628 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5630 mmplayer_t *player = (mmplayer_t *)hplayer;
5631 int ret = MM_ERROR_NONE;
5635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5637 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5645 __mmplayer_is_midi_type(gchar *str_caps)
5647 if ((g_strrstr(str_caps, "audio/midi")) ||
5648 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5649 (g_strrstr(str_caps, "application/x-smaf")) ||
5650 (g_strrstr(str_caps, "audio/x-imelody")) ||
5651 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5652 (g_strrstr(str_caps, "audio/xmf")) ||
5653 (g_strrstr(str_caps, "audio/mxmf"))) {
5662 __mmplayer_is_only_mp3_type(gchar *str_caps)
5664 if (g_strrstr(str_caps, "application/x-id3") ||
5665 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5671 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5673 GstStructure *caps_structure = NULL;
5674 gint samplerate = 0;
5678 MMPLAYER_RETURN_IF_FAIL(player && caps);
5680 caps_structure = gst_caps_get_structure(caps, 0);
5682 /* set stream information */
5683 gst_structure_get_int(caps_structure, "rate", &samplerate);
5684 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5686 gst_structure_get_int(caps_structure, "channels", &channels);
5687 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5689 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5693 __mmplayer_update_content_type_info(mmplayer_t *player)
5696 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5698 if (__mmplayer_is_midi_type(player->type)) {
5699 player->bypass_audio_effect = TRUE;
5703 if (!player->streamer) {
5704 LOGD("no need to check streaming type");
5708 if (g_strrstr(player->type, "application/x-hls")) {
5709 /* If it can't know exact type when it parses uri because of redirection case,
5710 * it will be fixed by typefinder or when doing autoplugging.
5712 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5713 player->streamer->is_adaptive_streaming = TRUE;
5714 } else if (g_strrstr(player->type, "application/dash+xml")) {
5715 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5716 player->streamer->is_adaptive_streaming = TRUE;
5719 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5720 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5721 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5723 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5724 if (player->streamer->is_adaptive_streaming)
5725 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5727 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5731 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5736 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5737 GstCaps *caps, gpointer data)
5739 mmplayer_t *player = (mmplayer_t *)data;
5744 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5746 /* store type string */
5747 MMPLAYER_FREEIF(player->type);
5748 player->type = gst_caps_to_string(caps);
5750 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5751 player, player->type, probability, gst_caps_get_size(caps));
5753 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5754 (g_strrstr(player->type, "audio/x-raw-int"))) {
5755 LOGE("not support media format");
5757 if (player->msg_posted == FALSE) {
5758 MMMessageParamType msg_param;
5759 memset(&msg_param, 0, sizeof(MMMessageParamType));
5761 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5762 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5764 /* don't post more if one was sent already */
5765 player->msg_posted = TRUE;
5770 __mmplayer_update_content_type_info(player);
5772 pad = gst_element_get_static_pad(tf, "src");
5774 LOGE("fail to get typefind src pad.");
5778 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5779 gboolean async = FALSE;
5780 LOGE("failed to autoplug %s", player->type);
5782 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5784 if (async && player->msg_posted == FALSE)
5785 __mmplayer_handle_missed_plugin(player);
5789 gst_object_unref(GST_OBJECT(pad));
5797 __mmplayer_gst_make_decodebin(mmplayer_t *player)
5799 GstElement *decodebin = NULL;
5803 /* create decodebin */
5804 decodebin = gst_element_factory_make("decodebin", NULL);
5807 LOGE("fail to create decodebin");
5811 /* raw pad handling signal */
5812 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5813 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5815 /* no-more-pad pad handling signal */
5816 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5817 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5819 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5820 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5822 /* This signal is emitted when a pad for which there is no further possible
5823 decoding is added to the decodebin.*/
5824 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5825 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5827 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5828 before looking for any elements that can handle that stream.*/
5829 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5830 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5832 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5833 before looking for any elements that can handle that stream.*/
5834 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5835 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5837 /* This signal is emitted once decodebin has finished decoding all the data.*/
5838 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5839 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5841 /* This signal is emitted when a element is added to the bin.*/
5842 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5843 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5850 __mmplayer_gst_make_queue2(mmplayer_t *player)
5852 GstElement *queue2 = NULL;
5853 gint64 dur_bytes = 0L;
5854 mmplayer_gst_element_t *mainbin = NULL;
5855 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5858 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5860 mainbin = player->pipeline->mainbin;
5862 queue2 = gst_element_factory_make("queue2", "queue2");
5864 LOGE("failed to create buffering queue element");
5868 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5869 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5871 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5873 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5874 * skip the pull mode(file or ring buffering) setting. */
5875 if (dur_bytes > 0) {
5876 if (!g_strrstr(player->type, "video/mpegts")) {
5877 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5878 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5884 __mm_player_streaming_set_queue2(player->streamer,
5888 (guint64)dur_bytes); /* no meaning at the moment */
5894 __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
5896 mmplayer_gst_element_t *mainbin = NULL;
5897 GstElement *decodebin = NULL;
5898 GstElement *queue2 = NULL;
5899 GstPad *sinkpad = NULL;
5900 GstPad *qsrcpad = NULL;
5903 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5905 mainbin = player->pipeline->mainbin;
5907 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5909 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5910 LOGW("need to check: muxed buffer is not null");
5913 queue2 = __mmplayer_gst_make_queue2(player);
5915 LOGE("failed to make queue2");
5919 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5920 LOGE("failed to add buffering queue");
5924 sinkpad = gst_element_get_static_pad(queue2, "sink");
5925 qsrcpad = gst_element_get_static_pad(queue2, "src");
5927 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5928 LOGE("failed to link [%s:%s]-[%s:%s]",
5929 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5933 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5934 LOGE("failed to sync queue2 state with parent");
5938 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5939 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5943 gst_object_unref(GST_OBJECT(sinkpad));
5947 /* create decodebin */
5948 decodebin = __mmplayer_gst_make_decodebin(player);
5950 LOGE("failed to make decodebin");
5954 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5955 LOGE("failed to add decodebin");
5959 /* to force caps on the decodebin element and avoid reparsing stuff by
5960 * typefind. It also avoids a deadlock in the way typefind activates pads in
5961 * the state change */
5962 g_object_set(decodebin, "sink-caps", caps, NULL);
5964 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5966 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5967 LOGE("failed to link [%s:%s]-[%s:%s]",
5968 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5972 gst_object_unref(GST_OBJECT(sinkpad));
5974 gst_object_unref(GST_OBJECT(qsrcpad));
5977 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5978 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5980 /* set decodebin property about buffer in streaming playback. *
5981 * in case of HLS/DASH, it does not need to have big buffer *
5982 * because it is kind of adaptive streaming. */
5983 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5984 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5985 gint high_percent = 0;
5987 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5988 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5990 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5992 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5994 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5995 "high-percent", high_percent,
5996 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
5997 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
5998 "max-size-buffers", 0, NULL); // disable or automatic
6001 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6002 LOGE("failed to sync decodebin state with parent");
6013 gst_object_unref(GST_OBJECT(sinkpad));
6016 gst_object_unref(GST_OBJECT(qsrcpad));
6019 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6020 * You need to explicitly set elements to the NULL state before
6021 * dropping the final reference, to allow them to clean up.
6023 gst_element_set_state(queue2, GST_STATE_NULL);
6025 /* And, it still has a parent "player".
6026 * You need to let the parent manage the object instead of unreffing the object directly.
6028 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6029 gst_object_unref(queue2);
6034 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6035 * You need to explicitly set elements to the NULL state before
6036 * dropping the final reference, to allow them to clean up.
6038 gst_element_set_state(decodebin, GST_STATE_NULL);
6040 /* And, it still has a parent "player".
6041 * You need to let the parent manage the object instead of unreffing the object directly.
6044 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6045 gst_object_unref(decodebin);
6053 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6057 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6058 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6060 LOGD("class : %s, mime : %s", factory_class, mime);
6062 /* add missing plugin */
6063 /* NOTE : msl should check missing plugin for image mime type.
6064 * Some motion jpeg clips can have playable audio track.
6065 * So, msl have to play audio after displaying popup written video format not supported.
6067 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6068 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6069 LOGD("not found demuxer");
6070 player->not_found_demuxer = TRUE;
6071 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6077 if (!g_strrstr(factory_class, "Demuxer")) {
6078 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6079 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6080 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6082 /* check that clip have multi tracks or not */
6083 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6084 LOGD("video plugin is already linked");
6086 LOGW("add VIDEO to missing plugin");
6087 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6088 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6090 } else if (g_str_has_prefix(mime, "audio")) {
6091 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6092 LOGD("audio plugin is already linked");
6094 LOGW("add AUDIO to missing plugin");
6095 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6096 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6104 return MM_ERROR_NONE;
6108 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6110 mmplayer_t *player = (mmplayer_t *)data;
6114 MMPLAYER_RETURN_IF_FAIL(player);
6116 /* remove fakesink. */
6117 if (!__mmplayer_gst_remove_fakesink(player,
6118 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6119 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6120 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6121 * source element are not same. To overcome this situation, this function will called
6122 * several places and several times. Therefore, this is not an error case.
6127 LOGD("[handle: %p] pipeline has completely constructed", player);
6129 if ((player->ini.async_start) &&
6130 (player->msg_posted == FALSE) &&
6131 (player->cmd >= MMPLAYER_COMMAND_START))
6132 __mmplayer_handle_missed_plugin(player);
6134 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6138 __mmplayer_check_profile(void)
6141 static int profile_tv = -1;
6143 if (__builtin_expect(profile_tv != -1, 1))
6146 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6147 switch (*profileName) {
6162 __mmplayer_get_next_uri(mmplayer_t *player)
6164 mmplayer_parse_profile_t profile;
6166 guint num_of_list = 0;
6169 num_of_list = g_list_length(player->uri_info.uri_list);
6170 uri_idx = player->uri_info.uri_idx;
6172 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6173 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6174 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6176 LOGW("next uri does not exist");
6180 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6181 LOGE("failed to parse profile");
6185 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6186 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6187 LOGW("uri type is not supported(%d)", profile.uri_type);
6191 LOGD("success to find next uri %d", uri_idx);
6195 if (uri_idx == num_of_list) {
6196 LOGE("failed to find next uri");
6200 player->uri_info.uri_idx = uri_idx;
6201 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6203 if (mm_attrs_commit_all(player->attrs)) {
6204 LOGE("failed to commit");
6208 SECURE_LOGD("next playback uri: %s", uri);
6213 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6215 #define REPEAT_COUNT_INFINITELY -1
6216 #define REPEAT_COUNT_MIN 2
6218 MMHandleType attrs = 0;
6222 guint num_of_list = 0;
6223 int profile_tv = -1;
6227 LOGD("checking for gapless play option");
6229 if (player->pipeline->textbin) {
6230 LOGE("subtitle path is enabled. gapless play is not supported.");
6234 attrs = MMPLAYER_GET_ATTRS(player);
6236 LOGE("fail to get attributes.");
6240 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6242 /* gapless playback is not supported in case of video at TV profile. */
6243 profile_tv = __mmplayer_check_profile();
6244 if (profile_tv && video) {
6245 LOGW("not support video gapless playback");
6249 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6250 LOGE("failed to get play count");
6252 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6253 LOGE("failed to get gapless mode");
6255 /* check repeat count in case of audio */
6257 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6258 LOGW("gapless is disabled");
6262 num_of_list = g_list_length(player->uri_info.uri_list);
6264 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6266 if (num_of_list == 0) {
6267 /* audio looping path */
6268 if (count >= REPEAT_COUNT_MIN) {
6269 /* decrease play count */
6270 /* we succeeded to rewind. update play count and then wait for next EOS */
6272 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6273 /* commit attribute */
6274 if (mm_attrs_commit_all(attrs))
6275 LOGE("failed to commit attribute");
6277 } else if (count != REPEAT_COUNT_INFINITELY) {
6278 LOGD("there is no next uri and no repeat");
6281 LOGD("looping cnt %d", count);
6283 /* gapless playback path */
6284 if (!__mmplayer_get_next_uri(player)) {
6285 LOGE("failed to get next uri");
6292 LOGE("unable to play gapless path. EOS will be posted soon");
6297 __mmplayer_initialize_gapless_play(mmplayer_t *player)
6303 player->smooth_streaming = FALSE;
6304 player->videodec_linked = 0;
6305 player->audiodec_linked = 0;
6306 player->textsink_linked = 0;
6307 player->is_external_subtitle_present = FALSE;
6308 player->is_external_subtitle_added_now = FALSE;
6309 player->not_supported_codec = MISSING_PLUGIN_NONE;
6310 player->can_support_codec = FOUND_PLUGIN_NONE;
6311 player->pending_seek.is_pending = false;
6312 player->pending_seek.pos = 0;
6313 player->msg_posted = FALSE;
6314 player->has_many_types = FALSE;
6315 player->no_more_pad = FALSE;
6316 player->not_found_demuxer = 0;
6317 player->seek_state = MMPLAYER_SEEK_NONE;
6318 player->is_subtitle_force_drop = FALSE;
6319 player->play_subtitle = FALSE;
6320 player->adjust_subtitle_pos = 0;
6322 player->total_bitrate = 0;
6323 player->total_maximum_bitrate = 0;
6325 __mmplayer_track_initialize(player);
6326 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6328 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6329 player->bitrate[i] = 0;
6330 player->maximum_bitrate[i] = 0;
6333 if (player->v_stream_caps) {
6334 gst_caps_unref(player->v_stream_caps);
6335 player->v_stream_caps = NULL;
6338 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6340 /* clean found audio decoders */
6341 if (player->audio_decoders) {
6342 GList *a_dec = player->audio_decoders;
6343 for (; a_dec; a_dec = g_list_next(a_dec)) {
6344 gchar *name = a_dec->data;
6345 MMPLAYER_FREEIF(name);
6347 g_list_free(player->audio_decoders);
6348 player->audio_decoders = NULL;
6355 __mmplayer_activate_next_source(mmplayer_t *player, GstState target)
6357 mmplayer_gst_element_t *mainbin = NULL;
6358 MMMessageParamType msg_param = {0,};
6359 GstElement *element = NULL;
6360 MMHandleType attrs = 0;
6362 main_element_id_e elem_idx = MMPLAYER_M_NUM;
6366 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6367 LOGE("player is not initialized");
6371 mainbin = player->pipeline->mainbin;
6372 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6374 attrs = MMPLAYER_GET_ATTRS(player);
6376 LOGE("fail to get attributes");
6380 /* Initialize Player values */
6381 __mmplayer_initialize_gapless_play(player);
6383 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6385 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6386 LOGE("failed to parse profile");
6387 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6391 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6392 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6393 LOGE("dash or hls is not supportable");
6394 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6398 element = __mmplayer_gst_create_source(player);
6400 LOGE("no source element was created");
6404 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6405 LOGE("failed to add source element to pipeline");
6406 gst_object_unref(GST_OBJECT(element));
6411 /* take source element */
6412 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6413 mainbin[MMPLAYER_M_SRC].gst = element;
6417 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6418 if (player->streamer == NULL) {
6419 player->streamer = __mm_player_streaming_create();
6420 __mm_player_streaming_initialize(player->streamer, TRUE);
6423 elem_idx = MMPLAYER_M_TYPEFIND;
6424 element = gst_element_factory_make("typefind", "typefinder");
6425 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6426 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6428 elem_idx = MMPLAYER_M_AUTOPLUG;
6429 element = __mmplayer_gst_make_decodebin(player);
6432 /* check autoplug element is OK */
6434 LOGE("can not create element(%d)", elem_idx);
6438 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6439 LOGE("failed to add sinkbin to pipeline");
6440 gst_object_unref(GST_OBJECT(element));
6445 mainbin[elem_idx].id = elem_idx;
6446 mainbin[elem_idx].gst = element;
6448 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6449 LOGE("Failed to link src - autoplug(or typefind)");
6453 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6454 LOGE("Failed to change state of src element");
6458 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6459 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6460 LOGE("Failed to change state of decodebin");
6464 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6465 LOGE("Failed to change state of src element");
6470 player->gapless.stream_changed = TRUE;
6471 player->gapless.running = TRUE;
6477 MMPLAYER_PLAYBACK_UNLOCK(player);
6479 if (!player->msg_posted) {
6480 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6481 player->msg_posted = TRUE;
6488 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6490 mmplayer_selector_t *selector = &player->selector[type];
6491 mmplayer_gst_element_t *sinkbin = NULL;
6492 main_element_id_e selectorId = MMPLAYER_M_NUM;
6493 main_element_id_e sinkId = MMPLAYER_M_NUM;
6494 GstPad *srcpad = NULL;
6495 GstPad *sinkpad = NULL;
6496 gboolean send_notice = FALSE;
6499 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6501 LOGD("type %d", type);
6504 case MM_PLAYER_TRACK_TYPE_AUDIO:
6505 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6506 sinkId = MMPLAYER_A_BIN;
6507 sinkbin = player->pipeline->audiobin;
6509 case MM_PLAYER_TRACK_TYPE_VIDEO:
6510 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6511 sinkId = MMPLAYER_V_BIN;
6512 sinkbin = player->pipeline->videobin;
6515 case MM_PLAYER_TRACK_TYPE_TEXT:
6516 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6517 sinkId = MMPLAYER_T_BIN;
6518 sinkbin = player->pipeline->textbin;
6521 LOGE("requested type is not supportable");
6526 if (player->pipeline->mainbin[selectorId].gst) {
6529 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6531 if (selector->event_probe_id != 0)
6532 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6533 selector->event_probe_id = 0;
6535 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6536 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6538 if (srcpad && sinkpad) {
6539 /* after getting drained signal there is no data flows, so no need to do pad_block */
6540 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6541 gst_pad_unlink(srcpad, sinkpad);
6543 /* send custom event to sink pad to handle it at video sink */
6545 LOGD("send custom event to sinkpad");
6546 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6547 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6548 gst_pad_send_event(sinkpad, event);
6552 gst_object_unref(sinkpad);
6555 gst_object_unref(srcpad);
6558 LOGD("selector release");
6560 /* release and unref requests pad from the selector */
6561 for (n = 0; n < selector->channels->len; n++) {
6562 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6563 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6565 g_ptr_array_set_size(selector->channels, 0);
6567 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6568 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6570 player->pipeline->mainbin[selectorId].gst = NULL;
6578 __mmplayer_deactivate_old_path(mmplayer_t *player)
6581 MMPLAYER_RETURN_IF_FAIL(player);
6583 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6584 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6585 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6586 LOGE("deactivate selector error");
6590 __mmplayer_track_destroy(player);
6591 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6593 if (player->streamer) {
6594 __mm_player_streaming_initialize(player->streamer, FALSE);
6595 __mm_player_streaming_destroy(player->streamer);
6596 player->streamer = NULL;
6599 MMPLAYER_PLAYBACK_LOCK(player);
6600 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6607 if (!player->msg_posted) {
6608 MMMessageParamType msg = {0,};
6611 msg.code = MM_ERROR_PLAYER_INTERNAL;
6612 LOGE("gapless_uri_play> deactivate error");
6614 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6615 player->msg_posted = TRUE;
6621 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6623 int result = MM_ERROR_NONE;
6624 mmplayer_t *player = (mmplayer_t *)hplayer;
6627 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6629 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6630 if (mm_attrs_commit_all(player->attrs)) {
6631 LOGE("failed to commit the original uri.");
6632 result = MM_ERROR_PLAYER_INTERNAL;
6634 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6635 LOGE("failed to add the original uri in the uri list.");
6643 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6645 mmplayer_t *player = (mmplayer_t *)hplayer;
6646 guint num_of_list = 0;
6650 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6651 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6653 if (player->pipeline && player->pipeline->textbin) {
6654 LOGE("subtitle path is enabled.");
6655 return MM_ERROR_PLAYER_INVALID_STATE;
6658 num_of_list = g_list_length(player->uri_info.uri_list);
6660 if (is_first_path) {
6661 if (num_of_list == 0) {
6662 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6663 SECURE_LOGD("add original path : %s", uri);
6665 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6666 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6668 SECURE_LOGD("change original path : %s", uri);
6671 MMHandleType attrs = 0;
6672 attrs = MMPLAYER_GET_ATTRS(player);
6674 if (num_of_list == 0) {
6675 char *original_uri = NULL;
6678 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6680 if (!original_uri) {
6681 LOGE("there is no original uri.");
6682 return MM_ERROR_PLAYER_INVALID_STATE;
6685 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6686 player->uri_info.uri_idx = 0;
6688 SECURE_LOGD("add original path at first : %s", original_uri);
6692 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6693 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6697 return MM_ERROR_NONE;
6701 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6703 mmplayer_t *player = (mmplayer_t *)hplayer;
6704 char *next_uri = NULL;
6705 guint num_of_list = 0;
6708 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6710 num_of_list = g_list_length(player->uri_info.uri_list);
6712 if (num_of_list > 0) {
6713 gint uri_idx = player->uri_info.uri_idx;
6715 if (uri_idx < num_of_list-1)
6720 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6721 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6723 *uri = g_strdup(next_uri);
6727 return MM_ERROR_NONE;
6731 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6732 GstCaps *caps, gpointer data)
6734 mmplayer_t *player = (mmplayer_t *)data;
6735 const gchar *klass = NULL;
6736 const gchar *mime = NULL;
6737 gchar *caps_str = NULL;
6739 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6740 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6741 caps_str = gst_caps_to_string(caps);
6743 LOGW("unknown type of caps : %s from %s",
6744 caps_str, GST_ELEMENT_NAME(elem));
6746 MMPLAYER_FREEIF(caps_str);
6748 /* There is no available codec. */
6749 __mmplayer_check_not_supported_codec(player, klass, mime);
6753 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6754 GstCaps *caps, gpointer data)
6756 mmplayer_t *player = (mmplayer_t *)data;
6757 const char *mime = NULL;
6758 gboolean ret = TRUE;
6760 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6761 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6763 if (g_str_has_prefix(mime, "audio")) {
6764 GstStructure *caps_structure = NULL;
6765 gint samplerate = 0;
6767 gchar *caps_str = NULL;
6769 caps_structure = gst_caps_get_structure(caps, 0);
6770 gst_structure_get_int(caps_structure, "rate", &samplerate);
6771 gst_structure_get_int(caps_structure, "channels", &channels);
6773 if ((channels > 0 && samplerate == 0)) {
6774 LOGD("exclude audio...");
6778 caps_str = gst_caps_to_string(caps);
6779 /* set it directly because not sent by TAG */
6780 if (g_strrstr(caps_str, "mobile-xmf"))
6781 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6782 MMPLAYER_FREEIF(caps_str);
6783 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6784 MMMessageParamType msg_param;
6785 memset(&msg_param, 0, sizeof(MMMessageParamType));
6786 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6787 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6788 LOGD("video file is not supported on this device");
6790 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6791 LOGD("already video linked");
6794 LOGD("found new stream");
6801 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6803 gboolean ret = TRUE;
6804 GDBusConnection *conn = NULL;
6806 GVariant *result = NULL;
6807 const gchar *dbus_device_type = NULL;
6808 const gchar *dbus_ret = NULL;
6811 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6813 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6819 result = g_dbus_connection_call_sync(conn,
6820 "org.pulseaudio.Server",
6821 "/org/pulseaudio/StreamManager",
6822 "org.pulseaudio.StreamManager",
6823 "GetCurrentMediaRoutingPath",
6824 g_variant_new("(s)", "out"),
6825 G_VARIANT_TYPE("(ss)"),
6826 G_DBUS_CALL_FLAGS_NONE,
6830 if (!result || err) {
6831 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6837 /* device type is listed in stream-map.json at mmfw-sysconf */
6838 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6840 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6841 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6846 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6847 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6848 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6849 LOGD("audio offload is supportable");
6855 LOGD("audio offload is not supportable");
6859 g_variant_unref(result);
6860 g_object_unref(conn);
6865 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6867 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6868 gint64 position = 0;
6870 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6871 player->pipeline && player->pipeline->mainbin);
6873 MMPLAYER_CMD_LOCK(player);
6874 current_state = MMPLAYER_CURRENT_STATE(player);
6876 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6877 LOGW("getting current position failed in paused");
6879 _mmplayer_unrealize((MMHandleType)player);
6880 _mmplayer_realize((MMHandleType)player);
6882 _mmplayer_set_position((MMHandleType)player, position);
6884 /* async not to be blocked in streaming case */
6885 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6886 if (mm_attrs_commit_all(player->attrs))
6887 LOGE("failed to commit");
6889 _mmplayer_pause((MMHandleType)player);
6891 if (current_state == MM_PLAYER_STATE_PLAYING)
6892 _mmplayer_start((MMHandleType)player);
6893 MMPLAYER_CMD_UNLOCK(player);
6895 LOGD("rebuilding audio pipeline is completed.");
6898 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6900 mmplayer_t *player = (mmplayer_t *)user_data;
6901 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6902 gboolean is_supportable = FALSE;
6904 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6905 LOGW("failed to get device type");
6907 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6909 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6910 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6911 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6912 LOGD("ignore this dev connected info");
6916 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6917 if (player->build_audio_offload == is_supportable) {
6918 LOGD("keep current pipeline without re-building");
6922 /* rebuild pipeline */
6923 LOGD("re-build pipeline - offload: %d", is_supportable);
6924 player->build_audio_offload = FALSE;
6925 __mmplayer_rebuild_audio_pipeline(player);
6931 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6933 unsigned int id = 0;
6935 if (player->audio_device_cb_id != 0) {
6936 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6940 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6941 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6942 LOGD("added device connected cb (%u)", id);
6943 player->audio_device_cb_id = id;
6945 LOGW("failed to add device connected cb");
6953 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6955 gboolean ret = FALSE;
6956 GstElementFactory *factory = NULL;
6959 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6961 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6962 if (!__mmplayer_is_only_mp3_type(player->type))
6965 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6966 LOGD("there is no audio offload sink");
6970 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6971 LOGW("there is no audio device type to support offload");
6975 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6977 LOGW("there is no installed audio offload sink element");
6980 gst_object_unref(factory);
6982 if (!__mmplayer_add_audio_device_connected_cb(player))
6985 if (!__mmplayer_is_audio_offload_device_type(player))
6988 LOGD("audio offload can be built");
6996 static GstAutoplugSelectResult
6997 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6999 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7001 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7002 int audio_offload = 0;
7004 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7005 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7007 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7008 LOGD("expose audio path to build offload output path");
7009 player->build_audio_offload = TRUE;
7010 /* update codec info */
7011 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7012 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7013 player->audiodec_linked = 1;
7015 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7019 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7021 LOGD("audio codec type: %d", codec_type);
7022 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7023 /* sw codec will be skipped */
7024 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7025 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7026 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7027 ret = GST_AUTOPLUG_SELECT_SKIP;
7031 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7032 /* hw codec will be skipped */
7033 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7034 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7035 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7036 ret = GST_AUTOPLUG_SELECT_SKIP;
7041 /* set stream information */
7042 if (!player->audiodec_linked)
7043 __mmplayer_set_audio_attrs(player, caps);
7045 /* update codec info */
7046 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7047 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7048 player->audiodec_linked = 1;
7050 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7052 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7054 LOGD("video codec type: %d", codec_type);
7055 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7056 /* sw codec is skipped */
7057 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7058 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7059 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7060 ret = GST_AUTOPLUG_SELECT_SKIP;
7064 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7065 /* hw codec is skipped */
7066 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7067 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7068 ret = GST_AUTOPLUG_SELECT_SKIP;
7073 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7074 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7076 /* mark video decoder for acquire */
7077 if (player->video_decoder_resource == NULL) {
7078 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7079 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7080 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7081 &player->video_decoder_resource)
7082 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7083 LOGE("could not mark video_decoder resource for acquire");
7084 ret = GST_AUTOPLUG_SELECT_SKIP;
7088 LOGW("video decoder resource is already acquired, skip it.");
7089 ret = GST_AUTOPLUG_SELECT_SKIP;
7093 player->interrupted_by_resource = FALSE;
7094 /* acquire resources for video playing */
7095 if (mm_resource_manager_commit(player->resource_manager)
7096 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7097 LOGE("could not acquire resources for video decoding");
7098 ret = GST_AUTOPLUG_SELECT_SKIP;
7103 /* update codec info */
7104 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7105 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7106 player->videodec_linked = 1;
7114 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7115 GstCaps *caps, GstElementFactory *factory, gpointer data)
7117 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7118 mmplayer_t *player = (mmplayer_t *)data;
7120 gchar *factory_name = NULL;
7121 gchar *caps_str = NULL;
7122 const gchar *klass = NULL;
7125 factory_name = GST_OBJECT_NAME(factory);
7126 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7127 caps_str = gst_caps_to_string(caps);
7129 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7131 /* store type string */
7132 if (player->type == NULL) {
7133 player->type = gst_caps_to_string(caps);
7134 __mmplayer_update_content_type_info(player);
7137 /* filtering exclude keyword */
7138 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7139 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7140 LOGW("skipping [%s] by exculde keyword [%s]",
7141 factory_name, player->ini.exclude_element_keyword[idx]);
7143 result = GST_AUTOPLUG_SELECT_SKIP;
7148 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7149 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7150 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7151 factory_name, player->ini.unsupported_codec_keyword[idx]);
7152 result = GST_AUTOPLUG_SELECT_SKIP;
7157 /* exclude webm format */
7158 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7159 * because webm format is not supportable.
7160 * If webm is disabled in "autoplug-continue", there is no state change
7161 * failure or error because the decodebin will expose the pad directly.
7162 * It make MSL invoke _prepare_async_callback.
7163 * So, we need to disable webm format in "autoplug-select" */
7164 if (caps_str && strstr(caps_str, "webm")) {
7165 LOGW("webm is not supported");
7166 result = GST_AUTOPLUG_SELECT_SKIP;
7170 /* check factory class for filtering */
7171 /* NOTE : msl don't need to use image plugins.
7172 * So, those plugins should be skipped for error handling.
7174 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7175 LOGD("skipping [%s] by not required", factory_name);
7176 result = GST_AUTOPLUG_SELECT_SKIP;
7180 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7181 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7182 // TO CHECK : subtitle if needed, add subparse exception.
7183 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7184 result = GST_AUTOPLUG_SELECT_SKIP;
7188 if (g_strrstr(factory_name, "mpegpsdemux")) {
7189 LOGD("skipping PS container - not support");
7190 result = GST_AUTOPLUG_SELECT_SKIP;
7194 if (g_strrstr(factory_name, "mssdemux"))
7195 player->smooth_streaming = TRUE;
7197 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7198 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7201 GstStructure *str = NULL;
7202 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7204 /* don't make video because of not required */
7205 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7206 (!player->set_mode.media_packet_video_stream)) {
7207 LOGD("no need video decoding, expose pad");
7208 result = GST_AUTOPLUG_SELECT_EXPOSE;
7212 /* get w/h for omx state-tune */
7213 /* FIXME: deprecated? */
7214 str = gst_caps_get_structure(caps, 0);
7215 gst_structure_get_int(str, "width", &width);
7218 if (player->v_stream_caps) {
7219 gst_caps_unref(player->v_stream_caps);
7220 player->v_stream_caps = NULL;
7223 player->v_stream_caps = gst_caps_copy(caps);
7224 LOGD("take caps for video state tune");
7225 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7229 if (g_strrstr(klass, "Codec/Decoder")) {
7230 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7231 if (result != GST_AUTOPLUG_SELECT_TRY) {
7232 LOGW("skip add decoder");
7238 MMPLAYER_FREEIF(caps_str);
7244 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7247 //mmplayer_t *player = (mmplayer_t *)data;
7248 GstCaps *caps = NULL;
7250 LOGD("[Decodebin2] pad-removed signal");
7252 caps = gst_pad_query_caps(new_pad, NULL);
7254 LOGW("query caps is NULL");
7258 gchar *caps_str = NULL;
7259 caps_str = gst_caps_to_string(caps);
7261 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7263 MMPLAYER_FREEIF(caps_str);
7264 gst_caps_unref(caps);
7268 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7270 mmplayer_t *player = (mmplayer_t *)data;
7271 GstIterator *iter = NULL;
7272 GValue item = { 0, };
7274 gboolean done = FALSE;
7275 gboolean is_all_drained = TRUE;
7278 MMPLAYER_RETURN_IF_FAIL(player);
7280 LOGD("__mmplayer_gst_decode_drained");
7282 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7283 LOGW("Fail to get cmd lock");
7287 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7288 !__mmplayer_verify_gapless_play_path(player)) {
7289 LOGD("decoding is finished.");
7290 __mmplayer_reset_gapless_state(player);
7291 MMPLAYER_CMD_UNLOCK(player);
7295 player->gapless.reconfigure = TRUE;
7297 /* check decodebin src pads whether they received EOS or not */
7298 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7301 switch (gst_iterator_next(iter, &item)) {
7302 case GST_ITERATOR_OK:
7303 pad = g_value_get_object(&item);
7304 if (pad && !GST_PAD_IS_EOS(pad)) {
7305 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7306 is_all_drained = FALSE;
7309 g_value_reset(&item);
7311 case GST_ITERATOR_RESYNC:
7312 gst_iterator_resync(iter);
7314 case GST_ITERATOR_ERROR:
7315 case GST_ITERATOR_DONE:
7320 g_value_unset(&item);
7321 gst_iterator_free(iter);
7323 if (!is_all_drained) {
7324 LOGD("Wait util the all pads get EOS.");
7325 MMPLAYER_CMD_UNLOCK(player);
7330 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7331 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7333 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7334 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7335 __mmplayer_deactivate_old_path(player);
7336 MMPLAYER_CMD_UNLOCK(player);
7342 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7344 mmplayer_t *player = (mmplayer_t *)data;
7345 const gchar *klass = NULL;
7346 gchar *factory_name = NULL;
7348 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7349 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7351 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7353 if (__mmplayer_add_dump_buffer_probe(player, element))
7354 LOGD("add buffer probe");
7356 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7357 gchar *selected = NULL;
7358 selected = g_strdup(GST_ELEMENT_NAME(element));
7359 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7362 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7363 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7364 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7366 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7367 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7369 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7370 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7371 "max-video-width", player->adaptive_info.limit.width,
7372 "max-video-height", player->adaptive_info.limit.height, NULL);
7374 } else if (g_strrstr(klass, "Demuxer")) {
7375 //LOGD("plugged element is demuxer. take it");
7376 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7377 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7380 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7381 int surface_type = 0;
7383 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7386 // to support trust-zone only
7387 if (g_strrstr(factory_name, "asfdemux")) {
7388 LOGD("set file-location %s", player->profile.uri);
7389 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7390 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7391 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7392 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7393 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7394 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7395 (__mmplayer_is_only_mp3_type(player->type))) {
7396 LOGD("[mpegaudioparse] set streaming pull mode.");
7397 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7399 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7400 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7403 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7404 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7405 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7407 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7408 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7410 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7411 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7412 (MMPLAYER_IS_DASH_STREAMING(player))) {
7413 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7414 __mm_player_streaming_set_multiqueue(player->streamer, element);
7415 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7424 __mmplayer_release_misc(mmplayer_t *player)
7427 bool cur_mode = player->set_mode.rich_audio;
7430 MMPLAYER_RETURN_IF_FAIL(player);
7432 player->video_stream_cb = NULL;
7433 player->video_stream_cb_user_param = NULL;
7434 player->video_stream_prerolled = false;
7436 player->audio_stream_render_cb = NULL;
7437 player->audio_stream_cb_user_param = NULL;
7438 player->audio_stream_sink_sync = false;
7440 player->video_stream_changed_cb = NULL;
7441 player->video_stream_changed_cb_user_param = NULL;
7443 player->audio_stream_changed_cb = NULL;
7444 player->audio_stream_changed_cb_user_param = NULL;
7446 player->sent_bos = FALSE;
7447 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7449 player->seek_state = MMPLAYER_SEEK_NONE;
7451 player->total_bitrate = 0;
7452 player->total_maximum_bitrate = 0;
7454 player->not_found_demuxer = 0;
7456 player->last_position = 0;
7457 player->duration = 0;
7458 player->http_content_size = 0;
7459 player->not_supported_codec = MISSING_PLUGIN_NONE;
7460 player->can_support_codec = FOUND_PLUGIN_NONE;
7461 player->pending_seek.is_pending = false;
7462 player->pending_seek.pos = 0;
7463 player->msg_posted = FALSE;
7464 player->has_many_types = FALSE;
7465 player->is_subtitle_force_drop = FALSE;
7466 player->play_subtitle = FALSE;
7467 player->adjust_subtitle_pos = 0;
7468 player->has_closed_caption = FALSE;
7469 player->set_mode.media_packet_video_stream = false;
7470 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7471 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7473 player->set_mode.rich_audio = cur_mode;
7475 if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7476 LOGW("failed to remove audio device_connected_callback");
7477 player->audio_device_cb_id = 0;
7479 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7480 player->bitrate[i] = 0;
7481 player->maximum_bitrate[i] = 0;
7484 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7486 /* remove media stream cb(appsrc cb) */
7487 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7488 player->media_stream_buffer_status_cb[i] = NULL;
7489 player->media_stream_seek_data_cb[i] = NULL;
7490 player->buffer_cb_user_param[i] = NULL;
7491 player->seek_cb_user_param[i] = NULL;
7493 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7495 /* free memory related to audio effect */
7496 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7498 if (player->adaptive_info.var_list) {
7499 g_list_free_full(player->adaptive_info.var_list, g_free);
7500 player->adaptive_info.var_list = NULL;
7503 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7504 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7505 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7507 /* Reset video360 settings to their defaults in case if the pipeline is to be
7510 player->video360_metadata.is_spherical = -1;
7511 player->is_openal_plugin_used = FALSE;
7513 player->is_content_spherical = FALSE;
7514 player->is_video360_enabled = TRUE;
7515 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7516 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7517 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7518 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7519 player->video360_zoom = 1.0f;
7520 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7521 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7523 player->sound.rg_enable = false;
7525 __mmplayer_initialize_video_roi(player);
7530 __mmplayer_release_misc_post(mmplayer_t *player)
7532 char *original_uri = NULL;
7535 /* player->pipeline is already released before. */
7537 MMPLAYER_RETURN_IF_FAIL(player);
7539 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7541 /* clean found audio decoders */
7542 if (player->audio_decoders) {
7543 GList *a_dec = player->audio_decoders;
7544 for (; a_dec; a_dec = g_list_next(a_dec)) {
7545 gchar *name = a_dec->data;
7546 MMPLAYER_FREEIF(name);
7548 g_list_free(player->audio_decoders);
7549 player->audio_decoders = NULL;
7552 /* clean the uri list except original uri */
7553 if (player->uri_info.uri_list) {
7554 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7556 if (player->attrs) {
7557 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7558 LOGD("restore original uri = %s", original_uri);
7560 if (mm_attrs_commit_all(player->attrs))
7561 LOGE("failed to commit the original uri.");
7564 GList *uri_list = player->uri_info.uri_list;
7565 for (; uri_list; uri_list = g_list_next(uri_list)) {
7566 gchar *uri = uri_list->data;
7567 MMPLAYER_FREEIF(uri);
7569 g_list_free(player->uri_info.uri_list);
7570 player->uri_info.uri_list = NULL;
7573 /* clear the audio stream buffer list */
7574 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7576 /* clear the video stream bo list */
7577 __mmplayer_video_stream_destroy_bo_list(player);
7578 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7580 if (player->profile.input_mem.buf) {
7581 free(player->profile.input_mem.buf);
7582 player->profile.input_mem.buf = NULL;
7584 player->profile.input_mem.len = 0;
7585 player->profile.input_mem.offset = 0;
7587 player->uri_info.uri_idx = 0;
7592 __mmplayer_check_subtitle(mmplayer_t *player)
7594 MMHandleType attrs = 0;
7595 char *subtitle_uri = NULL;
7599 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7601 /* get subtitle attribute */
7602 attrs = MMPLAYER_GET_ATTRS(player);
7606 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7607 if (!subtitle_uri || !strlen(subtitle_uri))
7610 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7611 player->is_external_subtitle_present = TRUE;
7619 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7621 MMPLAYER_RETURN_IF_FAIL(player);
7623 if (player->eos_timer) {
7624 LOGD("cancel eos timer");
7625 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7626 player->eos_timer = 0;
7633 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7637 MMPLAYER_RETURN_IF_FAIL(player);
7638 MMPLAYER_RETURN_IF_FAIL(sink);
7640 player->sink_elements = g_list_append(player->sink_elements, sink);
7646 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7650 MMPLAYER_RETURN_IF_FAIL(player);
7651 MMPLAYER_RETURN_IF_FAIL(sink);
7653 player->sink_elements = g_list_remove(player->sink_elements, sink);
7659 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7660 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7662 mmplayer_signal_item_t *item = NULL;
7665 MMPLAYER_RETURN_IF_FAIL(player);
7667 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7668 LOGE("invalid signal type [%d]", type);
7672 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7674 LOGE("cannot connect signal [%s]", signal);
7679 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7680 player->signals[type] = g_list_append(player->signals[type], item);
7686 /* NOTE : be careful with calling this api. please refer to below glib comment
7687 * glib comment : Note that there is a bug in GObject that makes this function much
7688 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7689 * will no longer be called, but, the signal handler is not currently disconnected.
7690 * If the instance is itself being freed at the same time than this doesn't matter,
7691 * since the signal will automatically be removed, but if instance persists,
7692 * then the signal handler will leak. You should not remove the signal yourself
7693 * because in a future versions of GObject, the handler will automatically be
7696 * It's possible to work around this problem in a way that will continue to work
7697 * with future versions of GObject by checking that the signal handler is still
7698 * connected before disconnected it:
7700 * if (g_signal_handler_is_connected(instance, id))
7701 * g_signal_handler_disconnect(instance, id);
7704 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7706 GList *sig_list = NULL;
7707 mmplayer_signal_item_t *item = NULL;
7711 MMPLAYER_RETURN_IF_FAIL(player);
7713 LOGD("release signals type : %d", type);
7715 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7716 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7717 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7718 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7719 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7720 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7724 sig_list = player->signals[type];
7726 for (; sig_list; sig_list = sig_list->next) {
7727 item = sig_list->data;
7729 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7730 if (g_signal_handler_is_connected(item->obj, item->sig))
7731 g_signal_handler_disconnect(item->obj, item->sig);
7734 MMPLAYER_FREEIF(item);
7737 g_list_free(player->signals[type]);
7738 player->signals[type] = NULL;
7746 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7748 mmplayer_t *player = 0;
7749 int prev_display_surface_type = 0;
7750 void *prev_display_overlay = NULL;
7754 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7755 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7757 player = MM_PLAYER_CAST(handle);
7759 /* check video sinkbin is created */
7760 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7761 LOGE("Videosink is already created");
7762 return MM_ERROR_NONE;
7765 LOGD("videosink element is not yet ready");
7767 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7768 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7770 return MM_ERROR_INVALID_ARGUMENT;
7773 /* load previous attributes */
7774 if (player->attrs) {
7775 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7776 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7777 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7778 if (prev_display_surface_type == surface_type) {
7779 LOGD("incoming display surface type is same as previous one, do nothing..");
7781 return MM_ERROR_NONE;
7784 LOGE("failed to load attributes");
7786 return MM_ERROR_PLAYER_INTERNAL;
7789 /* videobin is not created yet, so we just set attributes related to display surface */
7790 LOGD("store display attribute for given surface type(%d)", surface_type);
7791 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7792 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7793 if (mm_attrs_commit_all(player->attrs)) {
7794 LOGE("failed to commit attribute");
7796 return MM_ERROR_PLAYER_INTERNAL;
7800 return MM_ERROR_NONE;
7803 /* Note : if silent is true, then subtitle would not be displayed. :*/
7805 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7807 mmplayer_t *player = (mmplayer_t *)hplayer;
7811 /* check player handle */
7812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7814 player->set_mode.subtitle_off = silent;
7816 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7820 return MM_ERROR_NONE;
7824 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7826 mmplayer_gst_element_t *mainbin = NULL;
7827 mmplayer_gst_element_t *textbin = NULL;
7828 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7829 GstState current_state = GST_STATE_VOID_PENDING;
7830 GstState element_state = GST_STATE_VOID_PENDING;
7831 GstState element_pending_state = GST_STATE_VOID_PENDING;
7833 GstEvent *event = NULL;
7834 int result = MM_ERROR_NONE;
7836 GstClock *curr_clock = NULL;
7837 GstClockTime base_time, start_time, curr_time;
7842 /* check player handle */
7843 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7845 player->pipeline->mainbin &&
7846 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7848 mainbin = player->pipeline->mainbin;
7849 textbin = player->pipeline->textbin;
7851 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7853 // sync clock with current pipeline
7854 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7855 curr_time = gst_clock_get_time(curr_clock);
7857 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7858 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7860 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7861 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7863 if (current_state > GST_STATE_READY) {
7864 // sync state with current pipeline
7865 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7866 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7867 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7869 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7870 if (GST_STATE_CHANGE_FAILURE == ret) {
7871 LOGE("fail to state change.");
7872 result = MM_ERROR_PLAYER_INTERNAL;
7876 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7877 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7880 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7881 gst_object_unref(curr_clock);
7884 // seek to current position
7885 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7886 result = MM_ERROR_PLAYER_INVALID_STATE;
7887 LOGE("gst_element_query_position failed, invalid state");
7891 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7892 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);
7894 __mmplayer_gst_send_event_to_sink(player, event);
7896 result = MM_ERROR_PLAYER_INTERNAL;
7897 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7901 /* sync state with current pipeline */
7902 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7903 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7904 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7906 return MM_ERROR_NONE;
7909 /* release text pipeline resource */
7910 player->textsink_linked = 0;
7912 /* release signal */
7913 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7915 /* release textbin with it's childs */
7916 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7917 MMPLAYER_FREEIF(player->pipeline->textbin);
7918 player->pipeline->textbin = NULL;
7920 /* release subtitle elem */
7921 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7922 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7928 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7930 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7931 GstState current_state = GST_STATE_VOID_PENDING;
7933 MMHandleType attrs = 0;
7934 mmplayer_gst_element_t *mainbin = NULL;
7935 mmplayer_gst_element_t *textbin = NULL;
7937 gchar *subtitle_uri = NULL;
7938 int result = MM_ERROR_NONE;
7939 const gchar *charset = NULL;
7943 /* check player handle */
7944 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7946 player->pipeline->mainbin &&
7947 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7948 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7950 mainbin = player->pipeline->mainbin;
7951 textbin = player->pipeline->textbin;
7953 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7954 if (current_state < GST_STATE_READY) {
7955 result = MM_ERROR_PLAYER_INVALID_STATE;
7956 LOGE("Pipeline is not in proper state");
7960 attrs = MMPLAYER_GET_ATTRS(player);
7962 LOGE("cannot get content attribute");
7963 result = MM_ERROR_PLAYER_INTERNAL;
7967 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7968 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7969 LOGE("subtitle uri is not proper filepath");
7970 result = MM_ERROR_PLAYER_INVALID_URI;
7974 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7975 LOGE("failed to get storage info of subtitle path");
7976 result = MM_ERROR_PLAYER_INVALID_URI;
7980 LOGD("old subtitle file path is [%s]", subtitle_uri);
7981 LOGD("new subtitle file path is [%s]", filepath);
7983 if (!strcmp(filepath, subtitle_uri)) {
7984 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7987 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7988 if (mm_attrs_commit_all(player->attrs)) {
7989 LOGE("failed to commit.");
7994 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7995 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7996 player->subtitle_language_list = NULL;
7997 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7999 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8000 if (ret != GST_STATE_CHANGE_SUCCESS) {
8001 LOGE("failed to change state of textbin to READY");
8002 result = MM_ERROR_PLAYER_INTERNAL;
8006 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8007 if (ret != GST_STATE_CHANGE_SUCCESS) {
8008 LOGE("failed to change state of subparse to READY");
8009 result = MM_ERROR_PLAYER_INTERNAL;
8013 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8014 if (ret != GST_STATE_CHANGE_SUCCESS) {
8015 LOGE("failed to change state of filesrc to READY");
8016 result = MM_ERROR_PLAYER_INTERNAL;
8020 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8022 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8024 charset = util_get_charset(filepath);
8026 LOGD("detected charset is %s", charset);
8027 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8030 result = _mmplayer_sync_subtitle_pipeline(player);
8037 /* API to switch between external subtitles */
8039 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8041 int result = MM_ERROR_NONE;
8042 mmplayer_t *player = (mmplayer_t *)hplayer;
8047 /* check player handle */
8048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8050 /* filepath can be null in idle state */
8052 /* check file path */
8053 if ((path = strstr(filepath, "file://")))
8054 result = util_exist_file_path(path + 7);
8056 result = util_exist_file_path(filepath);
8058 if (result != MM_ERROR_NONE) {
8059 LOGE("invalid subtitle path 0x%X", result);
8060 return result; /* file not found or permission denied */
8064 if (!player->pipeline) {
8066 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8067 if (mm_attrs_commit_all(player->attrs)) {
8068 LOGE("failed to commit"); /* subtitle path will not be created */
8069 return MM_ERROR_PLAYER_INTERNAL;
8072 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8073 /* check filepath */
8074 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8076 if (!__mmplayer_check_subtitle(player)) {
8077 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8078 if (mm_attrs_commit_all(player->attrs)) {
8079 LOGE("failed to commit");
8080 return MM_ERROR_PLAYER_INTERNAL;
8083 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8084 LOGE("fail to create text pipeline");
8085 return MM_ERROR_PLAYER_INTERNAL;
8088 result = _mmplayer_sync_subtitle_pipeline(player);
8090 result = __mmplayer_change_external_subtitle_language(player, filepath);
8093 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8094 player->is_external_subtitle_added_now = TRUE;
8096 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8097 if (!player->subtitle_language_list) {
8098 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8099 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8100 LOGW("subtitle language list is not updated yet");
8102 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8110 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8112 int result = MM_ERROR_NONE;
8113 gchar *change_pad_name = NULL;
8114 GstPad *sinkpad = NULL;
8115 mmplayer_gst_element_t *mainbin = NULL;
8116 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8117 GstCaps *caps = NULL;
8118 gint total_track_num = 0;
8122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8123 MM_ERROR_PLAYER_NOT_INITIALIZED);
8125 LOGD("Change Track(%d) to %d", type, index);
8127 mainbin = player->pipeline->mainbin;
8129 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8130 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8131 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8132 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8134 /* Changing Video Track is not supported. */
8135 LOGE("Track Type Error");
8139 if (mainbin[elem_idx].gst == NULL) {
8140 result = MM_ERROR_PLAYER_NO_OP;
8141 LOGD("Req track doesn't exist");
8145 total_track_num = player->selector[type].total_track_num;
8146 if (total_track_num <= 0) {
8147 result = MM_ERROR_PLAYER_NO_OP;
8148 LOGD("Language list is not available");
8152 if ((index < 0) || (index >= total_track_num)) {
8153 result = MM_ERROR_INVALID_ARGUMENT;
8154 LOGD("Not a proper index : %d", index);
8158 /*To get the new pad from the selector*/
8159 change_pad_name = g_strdup_printf("sink_%u", index);
8160 if (change_pad_name == NULL) {
8161 result = MM_ERROR_PLAYER_INTERNAL;
8162 LOGD("Pad does not exists");
8166 LOGD("new active pad name: %s", change_pad_name);
8168 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8169 if (sinkpad == NULL) {
8170 LOGD("sinkpad is NULL");
8171 result = MM_ERROR_PLAYER_INTERNAL;
8175 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8176 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8178 caps = gst_pad_get_current_caps(sinkpad);
8179 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8182 gst_object_unref(sinkpad);
8184 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8185 __mmplayer_set_audio_attrs(player, caps);
8188 MMPLAYER_FREEIF(change_pad_name);
8193 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8195 int result = MM_ERROR_NONE;
8196 mmplayer_t *player = NULL;
8197 mmplayer_gst_element_t *mainbin = NULL;
8199 gint current_active_index = 0;
8201 GstState current_state = GST_STATE_VOID_PENDING;
8202 GstEvent *event = NULL;
8207 player = (mmplayer_t *)hplayer;
8208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8210 if (!player->pipeline) {
8211 LOGE("Track %d pre setting -> %d", type, index);
8213 player->selector[type].active_pad_index = index;
8217 mainbin = player->pipeline->mainbin;
8219 current_active_index = player->selector[type].active_pad_index;
8221 /*If index is same as running index no need to change the pad*/
8222 if (current_active_index == index)
8225 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8226 result = MM_ERROR_PLAYER_INVALID_STATE;
8230 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8231 if (current_state < GST_STATE_PAUSED) {
8232 result = MM_ERROR_PLAYER_INVALID_STATE;
8233 LOGW("Pipeline not in porper state");
8237 result = __mmplayer_change_selector_pad(player, type, index);
8238 if (result != MM_ERROR_NONE) {
8239 LOGE("change selector pad error");
8243 player->selector[type].active_pad_index = index;
8245 if (current_state == GST_STATE_PLAYING) {
8246 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8247 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8248 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8250 __mmplayer_gst_send_event_to_sink(player, event);
8252 result = MM_ERROR_PLAYER_INTERNAL;
8262 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8264 mmplayer_t *player = (mmplayer_t *)hplayer;
8268 /* check player handle */
8269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8271 *silent = player->set_mode.subtitle_off;
8273 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8277 return MM_ERROR_NONE;
8281 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8283 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8284 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8286 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8287 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8291 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8292 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8293 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8294 mmplayer_dump_t *dump_s;
8295 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8296 if (dump_s == NULL) {
8297 LOGE("malloc fail");
8301 dump_s->dump_element_file = NULL;
8302 dump_s->dump_pad = NULL;
8303 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8305 if (dump_s->dump_pad) {
8306 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8307 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]);
8308 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8309 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);
8310 /* add list for removed buffer probe and close FILE */
8311 player->dump_list = g_list_append(player->dump_list, dump_s);
8312 LOGD("%s sink pad added buffer probe for dump", factory_name);
8315 MMPLAYER_FREEIF(dump_s);
8316 LOGE("failed to get %s sink pad added", factory_name);
8323 static GstPadProbeReturn
8324 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8326 FILE *dump_data = (FILE *)u_data;
8328 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8329 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8331 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8333 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8335 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8337 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8339 return GST_PAD_PROBE_OK;
8343 __mmplayer_release_dump_list(GList *dump_list)
8345 GList *d_list = dump_list;
8350 for (; d_list; d_list = g_list_next(d_list)) {
8351 mmplayer_dump_t *dump_s = d_list->data;
8352 if (dump_s->dump_pad) {
8353 if (dump_s->probe_handle_id)
8354 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8355 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8357 if (dump_s->dump_element_file) {
8358 fclose(dump_s->dump_element_file);
8359 dump_s->dump_element_file = NULL;
8361 MMPLAYER_FREEIF(dump_s);
8363 g_list_free(dump_list);
8368 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8370 mmplayer_t *player = (mmplayer_t *)hplayer;
8374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8375 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8377 *exist = (bool)player->has_closed_caption;
8381 return MM_ERROR_NONE;
8385 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8389 // LOGD("unref internal gst buffer %p", buffer);
8390 gst_buffer_unref((GstBuffer *)buffer);
8397 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8399 mmplayer_t *player = (mmplayer_t *)hplayer;
8403 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8404 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8406 if (MMPLAYER_IS_STREAMING(player))
8407 *timeout = (int)player->ini.live_state_change_timeout;
8409 *timeout = (int)player->ini.localplayback_state_change_timeout;
8411 LOGD("timeout = %d", *timeout);
8414 return MM_ERROR_NONE;
8418 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8420 mmplayer_t *player = (mmplayer_t *)hplayer;
8424 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8425 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8427 *num = player->video_num_buffers;
8428 *extra_num = player->video_extra_num_buffers;
8430 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8433 return MM_ERROR_NONE;
8437 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8441 MMPLAYER_RETURN_IF_FAIL(player);
8443 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8445 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8446 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8447 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8448 player->storage_info[i].id = -1;
8449 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8451 if (path_type != MMPLAYER_PATH_MAX)
8460 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8462 int ret = MM_ERROR_NONE;
8463 mmplayer_t *player = (mmplayer_t *)hplayer;
8464 MMMessageParamType msg_param = {0, };
8467 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8469 LOGW("state changed storage %d:%d", id, state);
8471 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8472 return MM_ERROR_NONE;
8474 /* FIXME: text path should be handled seperately. */
8475 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8476 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8477 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8478 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8479 LOGW("external storage is removed");
8481 if (player->msg_posted == FALSE) {
8482 memset(&msg_param, 0, sizeof(MMMessageParamType));
8483 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8484 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8485 player->msg_posted = TRUE;
8488 /* unrealize the player */
8489 ret = _mmplayer_unrealize(hplayer);
8490 if (ret != MM_ERROR_NONE)
8491 LOGE("failed to unrealize");
8499 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8501 int ret = MM_ERROR_NONE;
8502 mmplayer_t *player = (mmplayer_t *)hplayer;
8503 int idx = 0, total = 0;
8504 gchar *result = NULL, *tmp = NULL;
8507 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8508 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8510 total = *num = g_list_length(player->adaptive_info.var_list);
8512 LOGW("There is no stream variant info.");
8516 result = g_strdup("");
8517 for (idx = 0 ; idx < total ; idx++) {
8518 stream_variant_t *v_data = NULL;
8519 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8522 gchar data[64] = {0};
8523 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8525 tmp = g_strconcat(result, data, NULL);
8529 LOGW("There is no variant data in %d", idx);
8534 *var_info = (char *)result;
8536 LOGD("variant info %d:%s", *num, *var_info);
8542 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8544 int ret = MM_ERROR_NONE;
8545 mmplayer_t *player = (mmplayer_t *)hplayer;
8548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8550 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8552 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8553 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8554 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8556 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8557 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8558 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8559 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8561 /* FIXME: seek to current position for applying new variant limitation */
8570 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8572 int ret = MM_ERROR_NONE;
8573 mmplayer_t *player = (mmplayer_t *)hplayer;
8576 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8577 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8579 *bandwidth = player->adaptive_info.limit.bandwidth;
8580 *width = player->adaptive_info.limit.width;
8581 *height = player->adaptive_info.limit.height;
8583 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8590 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8592 int ret = MM_ERROR_NONE;
8593 mmplayer_t *player = (mmplayer_t *)hplayer;
8596 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8597 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8598 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8600 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8602 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8603 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8604 else /* live case */
8605 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8607 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8614 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8616 #define IDX_FIRST_SW_CODEC 0
8617 mmplayer_t *player = (mmplayer_t *)hplayer;
8618 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8619 MMHandleType attrs = 0;
8622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8624 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8625 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8626 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8628 switch (stream_type) {
8629 case MM_PLAYER_STREAM_TYPE_AUDIO:
8630 /* to support audio codec selection, codec info have to be added in ini file as below.
8631 audio codec element hw = xxxx
8632 audio codec element sw = avdec */
8633 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8634 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8635 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8636 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8637 LOGE("There is no audio codec info for codec_type %d", codec_type);
8638 return MM_ERROR_PLAYER_NO_OP;
8641 case MM_PLAYER_STREAM_TYPE_VIDEO:
8642 /* to support video codec selection, codec info have to be added in ini file as below.
8643 video codec element hw = omx
8644 video codec element sw = avdec */
8645 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8646 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8647 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8648 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8649 LOGE("There is no video codec info for codec_type %d", codec_type);
8650 return MM_ERROR_PLAYER_NO_OP;
8654 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8655 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8659 LOGD("update %s codec_type to %d", attr_name, codec_type);
8661 attrs = MMPLAYER_GET_ATTRS(player);
8662 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8664 if (mm_attrs_commit_all(player->attrs)) {
8665 LOGE("failed to commit codec_type attributes");
8666 return MM_ERROR_PLAYER_INTERNAL;
8670 return MM_ERROR_NONE;
8674 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8676 mmplayer_t *player = (mmplayer_t *)hplayer;
8677 GstElement *rg_vol_element = NULL;
8681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8683 player->sound.rg_enable = enabled;
8685 /* just hold rgvolume enable value if pipeline is not ready */
8686 if (!player->pipeline || !player->pipeline->audiobin) {
8687 LOGD("pipeline is not ready. holding rgvolume enable value");
8688 return MM_ERROR_NONE;
8691 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8693 if (!rg_vol_element) {
8694 LOGD("rgvolume element is not created");
8695 return MM_ERROR_PLAYER_INTERNAL;
8699 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8701 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8705 return MM_ERROR_NONE;
8709 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8711 mmplayer_t *player = (mmplayer_t *)hplayer;
8712 GstElement *rg_vol_element = NULL;
8713 gboolean enable = FALSE;
8717 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8718 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8720 /* just hold enable_rg value if pipeline is not ready */
8721 if (!player->pipeline || !player->pipeline->audiobin) {
8722 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8723 *enabled = player->sound.rg_enable;
8724 return MM_ERROR_NONE;
8727 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8729 if (!rg_vol_element) {
8730 LOGD("rgvolume element is not created");
8731 return MM_ERROR_PLAYER_INTERNAL;
8734 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8735 *enabled = (bool)enable;
8739 return MM_ERROR_NONE;
8743 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8745 mmplayer_t *player = (mmplayer_t *)hplayer;
8746 MMHandleType attrs = 0;
8747 void *handle = NULL;
8748 int ret = MM_ERROR_NONE;
8752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8754 attrs = MMPLAYER_GET_ATTRS(player);
8755 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8757 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8759 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8760 return MM_ERROR_PLAYER_INTERNAL;
8763 player->video_roi.scale_x = scale_x;
8764 player->video_roi.scale_y = scale_y;
8765 player->video_roi.scale_width = scale_width;
8766 player->video_roi.scale_height = scale_height;
8768 /* check video sinkbin is created */
8769 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8770 return MM_ERROR_NONE;
8772 if (!gst_video_overlay_set_video_roi_area(
8773 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8774 scale_x, scale_y, scale_width, scale_height))
8775 ret = MM_ERROR_PLAYER_INTERNAL;
8777 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8778 scale_x, scale_y, scale_width, scale_height);
8786 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8788 mmplayer_t *player = (mmplayer_t *)hplayer;
8789 int ret = MM_ERROR_NONE;
8793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8794 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8796 *scale_x = player->video_roi.scale_x;
8797 *scale_y = player->video_roi.scale_y;
8798 *scale_width = player->video_roi.scale_width;
8799 *scale_height = player->video_roi.scale_height;
8801 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8802 *scale_x, *scale_y, *scale_width, *scale_height);
8808 __mmplayer_update_duration_value(mmplayer_t *player)
8810 gboolean ret = FALSE;
8811 gint64 dur_nsec = 0;
8812 LOGD("try to update duration");
8814 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8815 player->duration = dur_nsec;
8816 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8820 if (player->duration < 0) {
8821 LOGW("duration is Non-Initialized !!!");
8822 player->duration = 0;
8825 /* update streaming service type */
8826 player->streaming_type = __mmplayer_get_stream_service_type(player);
8828 /* check duration is OK */
8829 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8830 /* FIXIT : find another way to get duration here. */
8831 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8837 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8839 /* update audio params
8840 NOTE : We need original audio params and it can be only obtained from src pad of audio
8841 decoder. Below code only valid when we are not using 'resampler' just before
8842 'audioconverter'. */
8843 GstCaps *caps_a = NULL;
8845 gint samplerate = 0, channels = 0;
8846 GstStructure *p = NULL;
8848 LOGD("try to update audio attrs");
8850 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8851 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8853 pad = gst_element_get_static_pad(
8854 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8857 LOGW("failed to get pad from audiosink");
8861 caps_a = gst_pad_get_current_caps(pad);
8863 LOGW("not ready to get audio caps");
8864 gst_object_unref(pad);
8868 p = gst_caps_get_structure(caps_a, 0);
8870 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8872 gst_structure_get_int(p, "rate", &samplerate);
8873 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8875 gst_structure_get_int(p, "channels", &channels);
8876 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8878 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8880 gst_caps_unref(caps_a);
8881 gst_object_unref(pad);
8887 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8889 LOGD("try to update video attrs");
8891 GstCaps *caps_v = NULL;
8895 GstStructure *p = NULL;
8897 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8898 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8900 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8902 LOGD("no videosink sink pad");
8906 caps_v = gst_pad_get_current_caps(pad);
8907 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8908 if (!caps_v && player->v_stream_caps) {
8909 caps_v = player->v_stream_caps;
8910 gst_caps_ref(caps_v);
8914 LOGD("no negitiated caps from videosink");
8915 gst_object_unref(pad);
8919 p = gst_caps_get_structure(caps_v, 0);
8920 gst_structure_get_int(p, "width", &width);
8921 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8923 gst_structure_get_int(p, "height", &height);
8924 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8926 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8928 SECURE_LOGD("width : %d height : %d", width, height);
8930 gst_caps_unref(caps_v);
8931 gst_object_unref(pad);
8934 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8935 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8942 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8944 gboolean ret = FALSE;
8945 guint64 data_size = 0;
8949 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8950 if (!player->duration)
8953 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8954 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8955 if (stat(path, &sb) == 0)
8956 data_size = (guint64)sb.st_size;
8958 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8959 data_size = player->http_content_size;
8962 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8965 guint64 bitrate = 0;
8966 guint64 msec_dur = 0;
8968 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8970 bitrate = data_size * 8 * 1000 / msec_dur;
8971 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8972 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8976 LOGD("player duration is less than 0");
8980 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8981 if (player->total_bitrate) {
8982 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8991 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8993 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8994 data->uri_type = uri_type;
8998 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9000 int ret = MM_ERROR_PLAYER_INVALID_URI;
9002 char *buffer = NULL;
9003 char *seperator = strchr(path, ',');
9004 char ext[100] = {0,}, size[100] = {0,};
9007 if ((buffer = strstr(path, "ext="))) {
9008 buffer += strlen("ext=");
9010 if (strlen(buffer)) {
9011 strncpy(ext, buffer, 99);
9013 if ((seperator = strchr(ext, ','))
9014 || (seperator = strchr(ext, ' '))
9015 || (seperator = strchr(ext, '\0'))) {
9016 seperator[0] = '\0';
9021 if ((buffer = strstr(path, "size="))) {
9022 buffer += strlen("size=");
9024 if (strlen(buffer) > 0) {
9025 strncpy(size, buffer, 99);
9027 if ((seperator = strchr(size, ','))
9028 || (seperator = strchr(size, ' '))
9029 || (seperator = strchr(size, '\0'))) {
9030 seperator[0] = '\0';
9033 mem_size = atoi(size);
9038 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9040 if (mem_size && param) {
9041 if (data->input_mem.buf)
9042 free(data->input_mem.buf);
9043 data->input_mem.buf = malloc(mem_size);
9045 if (data->input_mem.buf) {
9046 memcpy(data->input_mem.buf, param, mem_size);
9047 data->input_mem.len = mem_size;
9048 ret = MM_ERROR_NONE;
9050 LOGE("failed to alloc mem %d", mem_size);
9051 ret = MM_ERROR_PLAYER_INTERNAL;
9054 data->input_mem.offset = 0;
9055 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9062 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9064 gchar *location = NULL;
9067 int ret = MM_ERROR_NONE;
9069 if ((path = strstr(uri, "file://"))) {
9070 location = g_filename_from_uri(uri, NULL, &err);
9071 if (!location || (err != NULL)) {
9072 LOGE("Invalid URI '%s' for filesrc: %s", path,
9073 (err != NULL) ? err->message : "unknown error");
9077 MMPLAYER_FREEIF(location);
9079 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9080 return MM_ERROR_PLAYER_INVALID_URI;
9082 LOGD("path from uri: %s", location);
9085 path = (location != NULL) ? (location) : ((char *)uri);
9088 ret = util_exist_file_path(path);
9090 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9091 if (ret == MM_ERROR_NONE) {
9092 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9093 if (util_is_sdp_file(path)) {
9094 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9095 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9097 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9099 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9100 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9102 LOGE("invalid uri, could not play..");
9103 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9106 MMPLAYER_FREEIF(location);
9111 static mmplayer_video_decoded_data_info_t *
9112 __mmplayer_create_stream_from_pad(GstPad *pad)
9114 GstCaps *caps = NULL;
9115 GstStructure *structure = NULL;
9116 unsigned int fourcc = 0;
9117 const gchar *string_format = NULL;
9118 mmplayer_video_decoded_data_info_t *stream = NULL;
9120 MMPixelFormatType format;
9123 caps = gst_pad_get_current_caps(pad);
9125 LOGE("Caps is NULL.");
9129 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9130 structure = gst_caps_get_structure(caps, 0);
9131 gst_structure_get_int(structure, "width", &width);
9132 gst_structure_get_int(structure, "height", &height);
9133 string_format = gst_structure_get_string(structure, "format");
9136 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9137 format = util_get_pixtype(fourcc);
9138 gst_video_info_from_caps(&info, caps);
9139 gst_caps_unref(caps);
9142 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9143 LOGE("Wrong condition!!");
9147 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9149 LOGE("failed to alloc mem for video data");
9153 stream->width = width;
9154 stream->height = height;
9155 stream->format = format;
9156 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9162 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9164 unsigned int pitch = 0;
9166 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9169 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9170 bo = gst_tizen_memory_get_bos(mem, index);
9172 stream->bo[index] = tbm_bo_ref(bo);
9174 LOGE("failed to get bo for index %d", index);
9177 for (index = 0; index < stream->plane_num; index++) {
9178 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9179 stream->stride[index] = pitch;
9180 stream->elevation[index] = stream->height;
9185 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9187 if (stream->format == MM_PIXEL_FORMAT_I420) {
9188 int ret = TBM_SURFACE_ERROR_NONE;
9189 tbm_surface_h surface;
9190 tbm_surface_info_s info;
9192 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9194 ret = tbm_surface_get_info(surface, &info);
9195 if (ret != TBM_SURFACE_ERROR_NONE) {
9196 tbm_surface_destroy(surface);
9200 tbm_surface_destroy(surface);
9201 stream->stride[0] = info.planes[0].stride;
9202 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9203 stream->stride[1] = info.planes[1].stride;
9204 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9205 stream->stride[2] = info.planes[2].stride;
9206 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9207 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9208 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9209 stream->stride[0] = stream->width * 4;
9210 stream->elevation[0] = stream->height;
9211 stream->bo_size = stream->stride[0] * stream->height;
9213 LOGE("Not support format %d", stream->format);
9221 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9223 tbm_bo_handle thandle;
9225 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9226 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9227 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9231 unsigned char *src = NULL;
9232 unsigned char *dest = NULL;
9233 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9235 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9237 LOGE("fail to gst_memory_map");
9241 if (!mapinfo.data) {
9242 LOGE("data pointer is wrong");
9246 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9247 if (!stream->bo[0]) {
9248 LOGE("Fail to tbm_bo_alloc!!");
9252 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9254 LOGE("thandle pointer is wrong");
9258 if (stream->format == MM_PIXEL_FORMAT_I420) {
9259 src_stride[0] = GST_ROUND_UP_4(stream->width);
9260 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9261 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9262 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9265 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9266 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9268 for (i = 0; i < 3; i++) {
9269 src = mapinfo.data + src_offset[i];
9270 dest = thandle.ptr + dest_offset[i];
9275 for (j = 0; j < stream->height >> k; j++) {
9276 memcpy(dest, src, stream->width>>k);
9277 src += src_stride[i];
9278 dest += stream->stride[i];
9281 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9282 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9284 LOGE("Not support format %d", stream->format);
9288 tbm_bo_unmap(stream->bo[0]);
9289 gst_memory_unmap(mem, &mapinfo);
9295 tbm_bo_unmap(stream->bo[0]);
9298 gst_memory_unmap(mem, &mapinfo);
9304 __mmplayer_set_pause_state(mmplayer_t *player)
9306 if (player->sent_bos)
9309 /* rtsp case, get content attrs by GstMessage */
9310 if (MMPLAYER_IS_RTSP_STREAMING(player))
9313 /* it's first time to update all content attrs. */
9314 __mmplayer_update_content_attrs(player, ATTR_ALL);
9318 __mmplayer_set_playing_state(mmplayer_t *player)
9320 gchar *audio_codec = NULL;
9322 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9323 /* initialize because auto resume is done well. */
9324 player->resumed_by_rewind = FALSE;
9325 player->playback_rate = 1.0;
9328 if (player->sent_bos)
9331 /* try to get content metadata */
9333 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9334 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9335 * legacy mmfw-player api
9337 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9339 if ((player->cmd == MMPLAYER_COMMAND_START)
9340 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9341 __mmplayer_handle_missed_plugin(player);
9344 /* check audio codec field is set or not
9345 * we can get it from typefinder or codec's caps.
9347 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9349 /* The codec format can't be sent for audio only case like amr, mid etc.
9350 * Because, parser don't make related TAG.
9351 * So, if it's not set yet, fill it with found data.
9354 if (g_strrstr(player->type, "audio/midi"))
9355 audio_codec = "MIDI";
9356 else if (g_strrstr(player->type, "audio/x-amr"))
9357 audio_codec = "AMR";
9358 else if (g_strrstr(player->type, "audio/mpeg")
9359 && !g_strrstr(player->type, "mpegversion=(int)1"))
9360 audio_codec = "AAC";
9362 audio_codec = "unknown";
9364 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9366 if (mm_attrs_commit_all(player->attrs))
9367 LOGE("failed to update attributes");
9369 LOGD("set audio codec type with caps");