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 if (player->sound.focus_id)
2508 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2509 stream_type, stream_id, player->sound.focus_id);
2511 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2512 stream_type, stream_id);
2513 props = gst_structure_from_string(stream_props, NULL);
2514 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2515 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2516 stream_type, stream_id, player->sound.focus_id, stream_props);
2517 gst_structure_free(props);
2520 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2522 switch (latency_mode) {
2523 case AUDIO_LATENCY_MODE_LOW:
2524 latency = g_strndup("low", 3);
2526 case AUDIO_LATENCY_MODE_MID:
2527 latency = g_strndup("mid", 3);
2529 case AUDIO_LATENCY_MODE_HIGH:
2530 latency = g_strndup("high", 4);
2534 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2538 LOGD("audiosink property - latency=%s", latency);
2540 MMPLAYER_FREEIF(latency);
2546 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2548 mmplayer_gst_element_t *audiobin = NULL;
2551 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2553 audiobin = player->pipeline->audiobin;
2555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2556 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2557 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2559 if (player->video360_yaw_radians <= M_PI &&
2560 player->video360_yaw_radians >= -M_PI &&
2561 player->video360_pitch_radians <= M_PI_2 &&
2562 player->video360_pitch_radians >= -M_PI_2) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2565 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2566 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2567 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2568 "source-orientation-y", player->video360_metadata.init_view_heading,
2569 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2576 __mmplayer_gst_fill_audio_bucket(mmplayer_t *player, GList **bucket)
2578 mmplayer_gst_element_t *audiobin = NULL;
2579 MMHandleType attrs = 0;
2580 GList *element_bucket = NULL;
2581 GstCaps *acaps = NULL;
2582 GstPad *sink_pad = NULL;
2583 int pitch_control = 0;
2584 double pitch_value = 1.0;
2587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2588 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2590 audiobin = player->pipeline->audiobin;
2591 attrs = MMPLAYER_GET_ATTRS(player);
2593 if (player->build_audio_offload) { /* skip all the audio filters */
2594 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2596 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2597 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2602 mm_attrs_multiple_get(player->attrs, NULL,
2603 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2604 MM_PLAYER_PITCH_VALUE, &pitch_value,
2607 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2608 if (pitch_control && (player->videodec_linked == 0)) {
2609 GstElementFactory *factory;
2611 factory = gst_element_factory_find("pitch");
2613 gst_object_unref(factory);
2616 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2619 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2620 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2622 LOGW("there is no pitch element");
2627 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2629 /* replaygain volume */
2630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2631 if (player->sound.rg_enable)
2632 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2637 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2639 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2640 gchar *dst_format = NULL;
2642 int dst_samplerate = 0;
2643 int dst_channels = 0;
2644 GstCaps *caps = NULL;
2645 char *caps_str = NULL;
2647 /* get conf. values */
2648 mm_attrs_multiple_get(player->attrs, NULL,
2649 "pcm_audioformat", &dst_format, &dst_len,
2650 "pcm_extraction_samplerate", &dst_samplerate,
2651 "pcm_extraction_channels", &dst_channels,
2654 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2657 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2658 caps = gst_caps_new_simple("audio/x-raw",
2659 "format", G_TYPE_STRING, dst_format,
2660 "rate", G_TYPE_INT, dst_samplerate,
2661 "channels", G_TYPE_INT, dst_channels,
2664 caps_str = gst_caps_to_string(caps);
2665 LOGD("new caps : %s", caps_str);
2667 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2670 gst_caps_unref(caps);
2671 MMPLAYER_FREEIF(caps_str);
2673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2677 /* raw pad handling signal, audiosink will be added after getting signal */
2678 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2679 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2683 /* normal playback */
2686 /* for logical volume control */
2687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2690 if (player->sound.mute) {
2691 LOGD("mute enabled");
2692 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2695 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2697 /* audio effect element. if audio effect is enabled */
2698 if ((strcmp(player->ini.audioeffect_element, ""))
2700 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2701 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2703 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2705 if ((!player->bypass_audio_effect)
2706 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2707 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2708 if (!_mmplayer_audio_effect_custom_apply(player))
2709 LOGI("apply audio effect(custom) setting success");
2713 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2714 && (player->set_mode.rich_audio))
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2718 /* create audio sink */
2719 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2720 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2721 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2723 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2724 if (player->is_360_feature_enabled &&
2725 player->is_content_spherical &&
2727 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2728 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2729 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2731 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2735 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2736 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2738 gst_caps_unref(acaps);
2740 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2742 player->is_openal_plugin_used = TRUE;
2744 if (player->is_360_feature_enabled && player->is_content_spherical)
2745 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2749 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2750 (player->videodec_linked && player->ini.use_system_clock)) {
2751 LOGD("system clock will be used.");
2752 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2755 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2756 __mmplayer_gst_set_pulsesink_property(player, attrs);
2757 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2758 __mmplayer_gst_set_openalsink_property(player);
2761 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2762 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2764 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2765 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2766 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2767 gst_object_unref(GST_OBJECT(sink_pad));
2769 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2773 *bucket = element_bucket;
2776 return MM_ERROR_NONE;
2779 g_list_free(element_bucket);
2783 return MM_ERROR_PLAYER_INTERNAL;
2787 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2789 mmplayer_gst_element_t *first_element = NULL;
2790 mmplayer_gst_element_t *audiobin = NULL;
2792 GstPad *ghostpad = NULL;
2793 GList *element_bucket = NULL;
2797 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2800 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2802 LOGE("failed to allocate memory for audiobin");
2803 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2807 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2808 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2809 if (!audiobin[MMPLAYER_A_BIN].gst) {
2810 LOGE("failed to create audiobin");
2815 player->pipeline->audiobin = audiobin;
2817 /* create audio filters and audiosink */
2818 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2821 /* adding created elements to bin */
2822 LOGD("adding created elements to bin");
2823 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2826 /* linking elements in the bucket by added order. */
2827 LOGD("Linking elements in the bucket by added order.");
2828 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2831 /* get first element's sinkpad for creating ghostpad */
2832 first_element = (mmplayer_gst_element_t *)element_bucket->data;
2833 if (!first_element) {
2834 LOGE("failed to get first elem");
2838 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2840 LOGE("failed to get pad from first element of audiobin");
2844 ghostpad = gst_ghost_pad_new("sink", pad);
2846 LOGE("failed to create ghostpad");
2850 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2851 LOGE("failed to add ghostpad to audiobin");
2855 gst_object_unref(pad);
2857 g_list_free(element_bucket);
2860 return MM_ERROR_NONE;
2863 LOGD("ERROR : releasing audiobin");
2866 gst_object_unref(GST_OBJECT(pad));
2869 gst_object_unref(GST_OBJECT(ghostpad));
2872 g_list_free(element_bucket);
2874 /* release element which are not added to bin */
2875 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2876 /* NOTE : skip bin */
2877 if (audiobin[i].gst) {
2878 GstObject *parent = NULL;
2879 parent = gst_element_get_parent(audiobin[i].gst);
2882 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2883 audiobin[i].gst = NULL;
2885 gst_object_unref(GST_OBJECT(parent));
2889 /* release audiobin with it's childs */
2890 if (audiobin[MMPLAYER_A_BIN].gst)
2891 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2893 MMPLAYER_FREEIF(audiobin);
2895 player->pipeline->audiobin = NULL;
2897 return MM_ERROR_PLAYER_INTERNAL;
2901 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2903 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2907 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
2909 int ret = MM_ERROR_NONE;
2911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2912 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2914 MMPLAYER_VIDEO_BO_LOCK(player);
2916 if (player->video_bo_list) {
2917 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2918 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
2919 if (tmp && tmp->bo == bo) {
2921 LOGD("release bo %p", bo);
2922 tbm_bo_unref(tmp->bo);
2923 MMPLAYER_VIDEO_BO_UNLOCK(player);
2924 MMPLAYER_VIDEO_BO_SIGNAL(player);
2929 /* hw codec is running or the list was reset for DRC. */
2930 LOGW("there is no bo list.");
2932 MMPLAYER_VIDEO_BO_UNLOCK(player);
2934 LOGW("failed to find bo %p", bo);
2939 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
2944 MMPLAYER_RETURN_IF_FAIL(player);
2946 MMPLAYER_VIDEO_BO_LOCK(player);
2947 if (player->video_bo_list) {
2948 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2949 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2950 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
2953 tbm_bo_unref(tmp->bo);
2957 g_list_free(player->video_bo_list);
2958 player->video_bo_list = NULL;
2960 player->video_bo_size = 0;
2961 MMPLAYER_VIDEO_BO_UNLOCK(player);
2968 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
2971 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2972 gboolean ret = TRUE;
2974 /* check DRC, if it is, destroy the prev bo list to create again */
2975 if (player->video_bo_size != size) {
2976 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2977 __mmplayer_video_stream_destroy_bo_list(player);
2978 player->video_bo_size = size;
2981 MMPLAYER_VIDEO_BO_LOCK(player);
2983 if ((!player->video_bo_list) ||
2984 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2986 /* create bo list */
2988 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2990 if (player->video_bo_list) {
2991 /* if bo list did not created all, try it again. */
2992 idx = g_list_length(player->video_bo_list);
2993 LOGD("bo list exist(len: %d)", idx);
2996 for (; idx < player->ini.num_of_video_bo; idx++) {
2997 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
2999 LOGE("Fail to alloc bo_info.");
3002 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3004 LOGE("Fail to tbm_bo_alloc.");
3005 MMPLAYER_FREEIF(bo_info);
3008 bo_info->used = FALSE;
3009 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3012 /* update video num buffers */
3013 player->video_num_buffers = idx;
3014 if (idx == player->ini.num_of_video_bo)
3015 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3018 MMPLAYER_VIDEO_BO_UNLOCK(player);
3022 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3026 /* get bo from list*/
3027 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3028 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3029 if (tmp && (tmp->used == FALSE)) {
3030 LOGD("found bo %p to use", tmp->bo);
3032 MMPLAYER_VIDEO_BO_UNLOCK(player);
3033 return tbm_bo_ref(tmp->bo);
3037 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3038 MMPLAYER_VIDEO_BO_UNLOCK(player);
3042 if (player->ini.video_bo_timeout <= 0) {
3043 MMPLAYER_VIDEO_BO_WAIT(player);
3045 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3046 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3053 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3055 mmplayer_t *player = (mmplayer_t *)data;
3057 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3059 /* send prerolled pkt */
3060 player->video_stream_prerolled = false;
3062 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3064 /* not to send prerolled pkt again */
3065 player->video_stream_prerolled = true;
3069 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3071 mmplayer_t *player = (mmplayer_t *)data;
3072 mmplayer_video_decoded_data_info_t *stream = NULL;
3073 GstMemory *mem = NULL;
3076 MMPLAYER_RETURN_IF_FAIL(player);
3077 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3079 if (player->video_stream_prerolled) {
3080 player->video_stream_prerolled = false;
3081 LOGD("skip the prerolled pkt not to send it again");
3085 /* clear stream data structure */
3086 stream = __mmplayer_create_stream_from_pad(pad);
3088 LOGE("failed to alloc stream");
3092 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3094 /* set size and timestamp */
3095 mem = gst_buffer_peek_memory(buffer, 0);
3096 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3097 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3099 /* check zero-copy */
3100 if (player->set_mode.video_zc &&
3101 player->set_mode.media_packet_video_stream &&
3102 gst_is_tizen_memory(mem)) {
3103 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3104 stream->internal_buffer = gst_buffer_ref(buffer);
3105 } else { /* sw codec */
3106 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3109 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3113 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3114 LOGE("failed to send video stream data.");
3121 LOGE("release video stream resource.");
3122 if (gst_is_tizen_memory(mem)) {
3124 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3126 tbm_bo_unref(stream->bo[i]);
3129 /* unref gst buffer */
3130 if (stream->internal_buffer)
3131 gst_buffer_unref(stream->internal_buffer);
3134 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3136 MMPLAYER_FREEIF(stream);
3141 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3143 mmplayer_gst_element_t *videobin = NULL;
3146 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3148 videobin = player->pipeline->videobin;
3150 /* Set spatial media metadata and/or user settings to the element.
3152 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3153 "projection-type", player->video360_metadata.projection_type, NULL);
3155 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3156 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3158 if (player->video360_metadata.full_pano_width_pixels &&
3159 player->video360_metadata.full_pano_height_pixels &&
3160 player->video360_metadata.cropped_area_image_width &&
3161 player->video360_metadata.cropped_area_image_height) {
3162 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3163 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3164 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3165 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3166 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3167 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3168 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3172 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3173 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3174 "horizontal-fov", player->video360_horizontal_fov,
3175 "vertical-fov", player->video360_vertical_fov, NULL);
3178 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3179 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3180 "zoom", 1.0f / player->video360_zoom, NULL);
3183 if (player->video360_yaw_radians <= M_PI &&
3184 player->video360_yaw_radians >= -M_PI &&
3185 player->video360_pitch_radians <= M_PI_2 &&
3186 player->video360_pitch_radians >= -M_PI_2) {
3187 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3189 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3190 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3191 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3192 "pose-yaw", player->video360_metadata.init_view_heading,
3193 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3196 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3197 "passthrough", !player->is_video360_enabled, NULL);
3204 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3206 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3207 GList *element_bucket = NULL;
3210 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3212 /* create video360 filter */
3213 if (player->is_360_feature_enabled && player->is_content_spherical) {
3214 LOGD("create video360 element");
3215 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3216 __mmplayer_gst_set_video360_property(player);
3220 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3221 LOGD("skip creating the videoconv and rotator");
3222 return MM_ERROR_NONE;
3225 /* in case of sw codec & overlay surface type, except 360 playback.
3226 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3227 LOGD("create video converter: %s", video_csc);
3228 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3231 *bucket = element_bucket;
3233 return MM_ERROR_NONE;
3235 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3236 g_list_free(element_bucket);
3240 return MM_ERROR_PLAYER_INTERNAL;
3244 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3246 gchar *factory_name = NULL;
3248 switch (surface_type) {
3249 case MM_DISPLAY_SURFACE_OVERLAY:
3250 if (strlen(player->ini.videosink_element_overlay) > 0)
3251 factory_name = player->ini.videosink_element_overlay;
3253 case MM_DISPLAY_SURFACE_REMOTE:
3254 case MM_DISPLAY_SURFACE_NULL:
3255 if (strlen(player->ini.videosink_element_fake) > 0)
3256 factory_name = player->ini.videosink_element_fake;
3259 LOGE("unidentified surface type");
3263 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3264 return factory_name;
3268 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3270 gchar *factory_name = NULL;
3271 mmplayer_gst_element_t *videobin = NULL;
3276 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3278 videobin = player->pipeline->videobin;
3279 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3281 attrs = MMPLAYER_GET_ATTRS(player);
3283 LOGE("cannot get content attribute");
3284 return MM_ERROR_PLAYER_INTERNAL;
3287 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3288 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3289 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3291 /* support shard memory with S/W codec on HawkP */
3292 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3293 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3294 "use-tbm", use_tbm, NULL);
3298 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3299 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3302 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3304 LOGD("disable last-sample");
3305 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3308 if (player->set_mode.media_packet_video_stream) {
3310 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3311 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3312 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3314 __mmplayer_add_signal_connection(player,
3315 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3316 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3318 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3321 __mmplayer_add_signal_connection(player,
3322 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3323 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3325 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3329 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3330 return MM_ERROR_PLAYER_INTERNAL;
3332 if (videobin[MMPLAYER_V_SINK].gst) {
3333 GstPad *sink_pad = NULL;
3334 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3336 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3337 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3338 gst_object_unref(GST_OBJECT(sink_pad));
3340 LOGE("failed to get sink pad from videosink");
3344 return MM_ERROR_NONE;
3349 * - video overlay surface(arm/x86) : tizenwlsink
3352 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3355 GList *element_bucket = NULL;
3356 mmplayer_gst_element_t *first_element = NULL;
3357 mmplayer_gst_element_t *videobin = NULL;
3358 gchar *videosink_factory_name = NULL;
3361 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3364 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3366 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3368 player->pipeline->videobin = videobin;
3371 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3372 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3373 if (!videobin[MMPLAYER_V_BIN].gst) {
3374 LOGE("failed to create videobin");
3378 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3381 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3382 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3384 /* additional setting for sink plug-in */
3385 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3386 LOGE("failed to set video property");
3390 /* store it as it's sink element */
3391 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3393 /* adding created elements to bin */
3394 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3395 LOGE("failed to add elements");
3399 /* Linking elements in the bucket by added order */
3400 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3401 LOGE("failed to link elements");
3405 /* get first element's sinkpad for creating ghostpad */
3406 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3407 if (!first_element) {
3408 LOGE("failed to get first element from bucket");
3412 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3414 LOGE("failed to get pad from first element");
3418 /* create ghostpad */
3419 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3420 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3421 LOGE("failed to add ghostpad to videobin");
3424 gst_object_unref(pad);
3426 /* done. free allocated variables */
3427 g_list_free(element_bucket);
3431 return MM_ERROR_NONE;
3434 LOGE("ERROR : releasing videobin");
3435 g_list_free(element_bucket);
3438 gst_object_unref(GST_OBJECT(pad));
3440 /* release videobin with it's childs */
3441 if (videobin[MMPLAYER_V_BIN].gst)
3442 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3444 MMPLAYER_FREEIF(videobin);
3445 player->pipeline->videobin = NULL;
3447 return MM_ERROR_PLAYER_INTERNAL;
3451 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3453 GList *element_bucket = NULL;
3454 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3456 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3457 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3458 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3459 "signal-handoffs", FALSE,
3462 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3463 __mmplayer_add_signal_connection(player,
3464 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3465 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3467 G_CALLBACK(__mmplayer_update_subtitle),
3470 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3471 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3473 if (!player->play_subtitle) {
3474 LOGD("add textbin sink as sink element of whole pipeline.");
3475 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3478 /* adding created elements to bin */
3479 LOGD("adding created elements to bin");
3480 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3481 LOGE("failed to add elements");
3485 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3486 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3487 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3489 /* linking elements in the bucket by added order. */
3490 LOGD("Linking elements in the bucket by added order.");
3491 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3492 LOGE("failed to link elements");
3496 /* done. free allocated variables */
3497 g_list_free(element_bucket);
3499 if (textbin[MMPLAYER_T_QUEUE].gst) {
3501 GstPad *ghostpad = NULL;
3503 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3505 LOGE("failed to get sink pad of text queue");
3509 ghostpad = gst_ghost_pad_new("text_sink", pad);
3510 gst_object_unref(pad);
3513 LOGE("failed to create ghostpad of textbin");
3517 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3518 LOGE("failed to add ghostpad to textbin");
3519 gst_object_unref(ghostpad);
3524 return MM_ERROR_NONE;
3527 g_list_free(element_bucket);
3529 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3530 LOGE("remove textbin sink from sink list");
3531 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3534 /* release element at __mmplayer_gst_create_text_sink_bin */
3535 return MM_ERROR_PLAYER_INTERNAL;
3539 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3541 mmplayer_gst_element_t *textbin = NULL;
3542 GList *element_bucket = NULL;
3543 int surface_type = 0;
3548 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3551 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3553 LOGE("failed to allocate memory for textbin");
3554 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3558 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3559 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3560 if (!textbin[MMPLAYER_T_BIN].gst) {
3561 LOGE("failed to create textbin");
3566 player->pipeline->textbin = textbin;
3569 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3570 LOGD("surface type for subtitle : %d", surface_type);
3571 switch (surface_type) {
3572 case MM_DISPLAY_SURFACE_OVERLAY:
3573 case MM_DISPLAY_SURFACE_NULL:
3574 case MM_DISPLAY_SURFACE_REMOTE:
3575 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3576 LOGE("failed to make plain text elements");
3587 return MM_ERROR_NONE;
3591 LOGD("ERROR : releasing textbin");
3593 g_list_free(element_bucket);
3595 /* release signal */
3596 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3598 /* release element which are not added to bin */
3599 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3600 /* NOTE : skip bin */
3601 if (textbin[i].gst) {
3602 GstObject *parent = NULL;
3603 parent = gst_element_get_parent(textbin[i].gst);
3606 gst_object_unref(GST_OBJECT(textbin[i].gst));
3607 textbin[i].gst = NULL;
3609 gst_object_unref(GST_OBJECT(parent));
3614 /* release textbin with it's childs */
3615 if (textbin[MMPLAYER_T_BIN].gst)
3616 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3618 MMPLAYER_FREEIF(player->pipeline->textbin);
3619 player->pipeline->textbin = NULL;
3622 return MM_ERROR_PLAYER_INTERNAL;
3626 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3628 mmplayer_gst_element_t *mainbin = NULL;
3629 mmplayer_gst_element_t *textbin = NULL;
3630 MMHandleType attrs = 0;
3631 GstElement *subsrc = NULL;
3632 GstElement *subparse = NULL;
3633 gchar *subtitle_uri = NULL;
3634 const gchar *charset = NULL;
3640 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3642 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3644 mainbin = player->pipeline->mainbin;
3646 attrs = MMPLAYER_GET_ATTRS(player);
3648 LOGE("cannot get content attribute");
3649 return MM_ERROR_PLAYER_INTERNAL;
3652 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3653 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3654 LOGE("subtitle uri is not proper filepath.");
3655 return MM_ERROR_PLAYER_INVALID_URI;
3658 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3659 LOGE("failed to get storage info of subtitle path");
3660 return MM_ERROR_PLAYER_INVALID_URI;
3663 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3665 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3666 player->subtitle_language_list = NULL;
3667 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3669 /* create the subtitle source */
3670 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3672 LOGE("failed to create filesrc element");
3675 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3677 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3678 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3680 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3681 LOGW("failed to add queue");
3682 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3683 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3684 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3689 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3691 LOGE("failed to create subparse element");
3695 charset = util_get_charset(subtitle_uri);
3697 LOGD("detected charset is %s", charset);
3698 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3701 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3702 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3704 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3705 LOGW("failed to add subparse");
3706 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3707 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3708 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3712 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3713 LOGW("failed to link subsrc and subparse");
3717 player->play_subtitle = TRUE;
3718 player->adjust_subtitle_pos = 0;
3720 LOGD("play subtitle using subtitle file");
3722 if (player->pipeline->textbin == NULL) {
3723 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3724 LOGE("failed to create text sink bin. continuing without text");
3728 textbin = player->pipeline->textbin;
3730 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3731 LOGW("failed to add textbin");
3733 /* release signal */
3734 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3736 /* release textbin with it's childs */
3737 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3738 MMPLAYER_FREEIF(player->pipeline->textbin);
3739 player->pipeline->textbin = textbin = NULL;
3743 LOGD("link text input selector and textbin ghost pad");
3745 player->textsink_linked = 1;
3746 player->external_text_idx = 0;
3747 LOGI("textsink is linked");
3749 textbin = player->pipeline->textbin;
3750 LOGD("text bin has been created. reuse it.");
3751 player->external_text_idx = 1;
3754 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3755 LOGW("failed to link subparse and textbin");
3759 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3761 LOGE("failed to get sink pad from textsink to probe data");
3765 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3766 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3768 gst_object_unref(pad);
3771 /* create dot. for debugging */
3772 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3775 return MM_ERROR_NONE;
3778 /* release text pipeline resource */
3779 player->textsink_linked = 0;
3781 /* release signal */
3782 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3784 if (player->pipeline->textbin) {
3785 LOGE("remove textbin");
3787 /* release textbin with it's childs */
3788 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3789 MMPLAYER_FREEIF(player->pipeline->textbin);
3790 player->pipeline->textbin = NULL;
3794 /* release subtitle elem */
3795 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3796 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3798 return MM_ERROR_PLAYER_INTERNAL;
3802 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3804 mmplayer_t *player = (mmplayer_t *)data;
3805 MMMessageParamType msg = {0, };
3806 GstClockTime duration = 0;
3807 gpointer text = NULL;
3808 guint text_size = 0;
3809 gboolean ret = TRUE;
3810 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3814 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3815 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3817 if (player->is_subtitle_force_drop) {
3818 LOGW("subtitle is dropped forcedly.");
3822 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3823 text = mapinfo.data;
3824 text_size = mapinfo.size;
3826 if (player->set_mode.subtitle_off) {
3827 LOGD("subtitle is OFF.");
3831 if (!text || (text_size == 0)) {
3832 LOGD("There is no subtitle to be displayed.");
3836 msg.data = (void *)text;
3838 duration = GST_BUFFER_DURATION(buffer);
3840 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3841 if (player->duration > GST_BUFFER_PTS(buffer))
3842 duration = player->duration - GST_BUFFER_PTS(buffer);
3845 LOGI("subtitle duration is invalid, subtitle duration change "
3846 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3848 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3850 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3852 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3853 gst_buffer_unmap(buffer, &mapinfo);
3860 static GstPadProbeReturn
3861 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3863 mmplayer_t *player = (mmplayer_t *)u_data;
3864 GstClockTime cur_timestamp = 0;
3865 gint64 adjusted_timestamp = 0;
3866 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3868 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3870 if (player->set_mode.subtitle_off) {
3871 LOGD("subtitle is OFF.");
3875 if (player->adjust_subtitle_pos == 0) {
3876 LOGD("nothing to do");
3880 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3881 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3883 if (adjusted_timestamp < 0) {
3884 LOGD("adjusted_timestamp under zero");
3889 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3890 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3891 GST_TIME_ARGS(cur_timestamp),
3892 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3894 return GST_PAD_PROBE_OK;
3898 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
3902 /* check player and subtitlebin are created */
3903 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3904 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3906 if (position == 0) {
3907 LOGD("nothing to do");
3909 return MM_ERROR_NONE;
3912 /* check current postion */
3913 player->adjust_subtitle_pos = position;
3915 LOGD("save adjust_subtitle_pos in player");
3919 return MM_ERROR_NONE;
3923 * This function is to create audio or video pipeline for playing.
3925 * @param player [in] handle of player
3927 * @return This function returns zero on success.
3932 __mmplayer_gst_create_pipeline(mmplayer_t *player)
3934 int ret = MM_ERROR_NONE;
3935 mmplayer_gst_element_t *mainbin = NULL;
3936 MMHandleType attrs = 0;
3939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3941 /* get profile attribute */
3942 attrs = MMPLAYER_GET_ATTRS(player);
3944 LOGE("failed to get content attribute");
3948 /* create pipeline handles */
3949 if (player->pipeline) {
3950 LOGE("pipeline should be released before create new one");
3954 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
3955 if (player->pipeline == NULL)
3958 /* create mainbin */
3959 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
3960 if (mainbin == NULL)
3963 /* create pipeline */
3964 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3965 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3966 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3967 LOGE("failed to create pipeline");
3972 player->pipeline->mainbin = mainbin;
3974 /* create the source and decoder elements */
3975 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3976 ret = __mmplayer_gst_build_es_pipeline(player);
3978 ret = __mmplayer_gst_build_pipeline(player);
3980 if (ret != MM_ERROR_NONE) {
3981 LOGE("failed to create some elements");
3985 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3986 if (__mmplayer_check_subtitle(player)
3987 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3988 LOGE("failed to create text pipeline");
3991 ret = __mmplayer_gst_add_bus_watch(player);
3992 if (ret != MM_ERROR_NONE) {
3993 LOGE("failed to add bus watch");
3998 return MM_ERROR_NONE;
4001 __mmplayer_gst_destroy_pipeline(player);
4002 return MM_ERROR_PLAYER_INTERNAL;
4006 __mmplayer_reset_gapless_state(mmplayer_t *player)
4009 MMPLAYER_RETURN_IF_FAIL(player
4011 && player->pipeline->audiobin
4012 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4014 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4021 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4024 int ret = MM_ERROR_NONE;
4028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4030 /* cleanup stuffs */
4031 MMPLAYER_FREEIF(player->type);
4032 player->no_more_pad = FALSE;
4033 player->num_dynamic_pad = 0;
4034 player->demux_pad_index = 0;
4036 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4037 player->subtitle_language_list = NULL;
4038 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4040 __mmplayer_reset_gapless_state(player);
4042 if (player->streamer) {
4043 __mm_player_streaming_initialize(player->streamer, FALSE);
4044 __mm_player_streaming_destroy(player->streamer);
4045 player->streamer = NULL;
4048 /* cleanup unlinked mime type */
4049 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4050 MMPLAYER_FREEIF(player->unlinked_video_mime);
4051 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4053 /* cleanup running stuffs */
4054 __mmplayer_cancel_eos_timer(player);
4056 /* cleanup gst stuffs */
4057 if (player->pipeline) {
4058 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4059 GstTagList *tag_list = player->pipeline->tag_list;
4061 /* first we need to disconnect all signal hander */
4062 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4065 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4066 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4067 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4068 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4069 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4070 gst_object_unref(bus);
4072 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4073 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4074 if (ret != MM_ERROR_NONE) {
4075 LOGE("fail to change state to NULL");
4076 return MM_ERROR_PLAYER_INTERNAL;
4079 LOGW("succeeded in changing state to NULL");
4081 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4084 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4085 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4087 /* free avsysaudiosink
4088 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4089 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4091 MMPLAYER_FREEIF(audiobin);
4092 MMPLAYER_FREEIF(videobin);
4093 MMPLAYER_FREEIF(textbin);
4094 MMPLAYER_FREEIF(mainbin);
4098 gst_tag_list_unref(tag_list);
4100 MMPLAYER_FREEIF(player->pipeline);
4102 MMPLAYER_FREEIF(player->album_art);
4104 if (player->v_stream_caps) {
4105 gst_caps_unref(player->v_stream_caps);
4106 player->v_stream_caps = NULL;
4109 if (player->a_stream_caps) {
4110 gst_caps_unref(player->a_stream_caps);
4111 player->a_stream_caps = NULL;
4114 if (player->s_stream_caps) {
4115 gst_caps_unref(player->s_stream_caps);
4116 player->s_stream_caps = NULL;
4118 __mmplayer_track_destroy(player);
4120 if (player->sink_elements)
4121 g_list_free(player->sink_elements);
4122 player->sink_elements = NULL;
4124 if (player->bufmgr) {
4125 tbm_bufmgr_deinit(player->bufmgr);
4126 player->bufmgr = NULL;
4129 LOGW("finished destroy pipeline");
4137 __mmplayer_gst_realize(mmplayer_t *player)
4140 int ret = MM_ERROR_NONE;
4144 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4146 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4148 ret = __mmplayer_gst_create_pipeline(player);
4150 LOGE("failed to create pipeline");
4154 /* set pipeline state to READY */
4155 /* NOTE : state change to READY must be performed sync. */
4156 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4157 ret = __mmplayer_gst_set_state(player,
4158 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4160 if (ret != MM_ERROR_NONE) {
4161 /* return error if failed to set state */
4162 LOGE("failed to set READY state");
4166 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4168 /* create dot before error-return. for debugging */
4169 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4177 __mmplayer_gst_unrealize(mmplayer_t *player)
4179 int ret = MM_ERROR_NONE;
4183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4185 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4186 MMPLAYER_PRINT_STATE(player);
4188 /* release miscellaneous information */
4189 __mmplayer_release_misc(player);
4191 /* destroy pipeline */
4192 ret = __mmplayer_gst_destroy_pipeline(player);
4193 if (ret != MM_ERROR_NONE) {
4194 LOGE("failed to destory pipeline");
4198 /* release miscellaneous information.
4199 these info needs to be released after pipeline is destroyed. */
4200 __mmplayer_release_misc_post(player);
4202 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4210 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4215 LOGW("set_message_callback is called with invalid player handle");
4216 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4219 player->msg_cb = callback;
4220 player->msg_cb_param = user_param;
4222 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4226 return MM_ERROR_NONE;
4230 __mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4232 int ret = MM_ERROR_NONE;
4237 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4238 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4239 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4241 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4243 if (strstr(uri, "es_buff://")) {
4244 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4245 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4246 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4247 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4249 tmp = g_ascii_strdown(uri, strlen(uri));
4250 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4251 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4253 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4255 } else if (strstr(uri, "mms://")) {
4256 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4257 } else if ((path = strstr(uri, "mem://"))) {
4258 ret = __mmplayer_set_mem_uri(data, path, param);
4260 ret = __mmplayer_set_file_uri(data, uri);
4263 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4264 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4265 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4266 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4268 /* dump parse result */
4269 SECURE_LOGW("incoming uri : %s", uri);
4270 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4271 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4279 __mmplayer_can_do_interrupt(mmplayer_t *player)
4281 if (!player || !player->pipeline || !player->attrs) {
4282 LOGW("not initialized");
4286 if (player->audio_stream_render_cb) {
4287 LOGW("not support in pcm extraction mode");
4291 /* check if seeking */
4292 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4293 MMMessageParamType msg_param;
4294 memset(&msg_param, 0, sizeof(MMMessageParamType));
4295 msg_param.code = MM_ERROR_PLAYER_SEEK;
4296 player->seek_state = MMPLAYER_SEEK_NONE;
4297 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4301 /* check other thread */
4302 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4303 LOGW("locked already, cmd state : %d", player->cmd);
4305 /* check application command */
4306 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4307 LOGW("playing.. should wait cmd lock then, will be interrupted");
4309 /* lock will be released at mrp_resource_release_cb() */
4310 MMPLAYER_CMD_LOCK(player);
4313 LOGW("nothing to do");
4316 LOGW("can interrupt immediately");
4320 FAILED: /* with CMD UNLOCKED */
4323 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4328 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4331 mmplayer_t *player = NULL;
4335 if (user_data == NULL) {
4336 LOGE("- user_data is null");
4339 player = (mmplayer_t *)user_data;
4341 /* do something to release resource here.
4342 * player stop and interrupt forwarding */
4343 if (!__mmplayer_can_do_interrupt(player)) {
4344 LOGW("no need to interrupt, so leave");
4346 MMMessageParamType msg = {0, };
4349 player->interrupted_by_resource = TRUE;
4351 /* get last play position */
4352 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4353 LOGW("failed to get play position.");
4355 msg.union_type = MM_MSG_UNION_TIME;
4356 msg.time.elapsed = pos;
4357 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4359 LOGD("video resource conflict so, resource will be freed by unrealizing");
4360 if (_mmplayer_unrealize((MMHandleType)player))
4361 LOGW("failed to unrealize");
4363 /* lock is called in __mmplayer_can_do_interrupt() */
4364 MMPLAYER_CMD_UNLOCK(player);
4367 if (res == player->video_overlay_resource)
4368 player->video_overlay_resource = FALSE;
4370 player->video_decoder_resource = FALSE;
4378 __mmplayer_initialize_video_roi(mmplayer_t *player)
4380 player->video_roi.scale_x = 0.0;
4381 player->video_roi.scale_y = 0.0;
4382 player->video_roi.scale_width = 1.0;
4383 player->video_roi.scale_height = 1.0;
4387 _mmplayer_create_player(MMHandleType handle)
4389 int ret = MM_ERROR_PLAYER_INTERNAL;
4390 bool enabled = false;
4392 mmplayer_t *player = MM_PLAYER_CAST(handle);
4396 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4398 /* initialize player state */
4399 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4400 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4401 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4402 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4404 /* check current state */
4405 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4407 /* construct attributes */
4408 player->attrs = _mmplayer_construct_attribute(handle);
4410 if (!player->attrs) {
4411 LOGE("Failed to construct attributes");
4415 /* initialize gstreamer with configured parameter */
4416 if (!__mmplayer_init_gstreamer(player)) {
4417 LOGE("Initializing gstreamer failed");
4418 _mmplayer_deconstruct_attribute(handle);
4422 /* create lock. note that g_tread_init() has already called in gst_init() */
4423 g_mutex_init(&player->fsink_lock);
4425 /* create update tag lock */
4426 g_mutex_init(&player->update_tag_lock);
4428 /* create gapless play mutex */
4429 g_mutex_init(&player->gapless_play_thread_mutex);
4431 /* create gapless play cond */
4432 g_cond_init(&player->gapless_play_thread_cond);
4434 /* create gapless play thread */
4435 player->gapless_play_thread =
4436 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4437 if (!player->gapless_play_thread) {
4438 LOGE("failed to create gapless play thread");
4439 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4440 g_mutex_clear(&player->gapless_play_thread_mutex);
4441 g_cond_clear(&player->gapless_play_thread_cond);
4445 player->bus_msg_q = g_queue_new();
4446 if (!player->bus_msg_q) {
4447 LOGE("failed to create queue for bus_msg");
4448 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4452 ret = _mmplayer_initialize_video_capture(player);
4453 if (ret != MM_ERROR_NONE) {
4454 LOGE("failed to initialize video capture");
4458 /* initialize resource manager */
4459 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4460 __resource_release_cb, player, &player->resource_manager)
4461 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4462 LOGE("failed to initialize resource manager");
4463 ret = MM_ERROR_PLAYER_INTERNAL;
4467 /* create video bo lock and cond */
4468 g_mutex_init(&player->video_bo_mutex);
4469 g_cond_init(&player->video_bo_cond);
4471 /* create media stream callback mutex */
4472 g_mutex_init(&player->media_stream_cb_lock);
4474 /* create subtitle info lock and cond */
4475 g_mutex_init(&player->subtitle_info_mutex);
4476 g_cond_init(&player->subtitle_info_cond);
4478 player->streaming_type = STREAMING_SERVICE_NONE;
4480 /* give default value of audio effect setting */
4481 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4482 player->sound.rg_enable = false;
4483 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4485 player->play_subtitle = FALSE;
4486 player->has_closed_caption = FALSE;
4487 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4488 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4489 player->pending_resume = FALSE;
4490 if (player->ini.dump_element_keyword[0][0] == '\0')
4491 player->ini.set_dump_element_flag = FALSE;
4493 player->ini.set_dump_element_flag = TRUE;
4495 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4496 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4497 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4499 /* Set video360 settings to their defaults for just-created player.
4502 player->is_360_feature_enabled = FALSE;
4503 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4504 LOGI("spherical feature info: %d", enabled);
4506 player->is_360_feature_enabled = TRUE;
4508 LOGE("failed to get spherical feature info");
4511 player->is_content_spherical = FALSE;
4512 player->is_video360_enabled = TRUE;
4513 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4514 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4515 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4516 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4517 player->video360_zoom = 1.0f;
4518 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4519 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4521 __mmplayer_initialize_video_roi(player);
4523 /* set player state to null */
4524 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4525 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4529 return MM_ERROR_NONE;
4533 g_mutex_clear(&player->fsink_lock);
4534 /* free update tag lock */
4535 g_mutex_clear(&player->update_tag_lock);
4536 g_queue_free(player->bus_msg_q);
4537 /* free gapless play thread */
4538 if (player->gapless_play_thread) {
4539 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4540 player->gapless_play_thread_exit = TRUE;
4541 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4542 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4544 g_thread_join(player->gapless_play_thread);
4545 player->gapless_play_thread = NULL;
4547 g_mutex_clear(&player->gapless_play_thread_mutex);
4548 g_cond_clear(&player->gapless_play_thread_cond);
4551 /* release attributes */
4552 _mmplayer_deconstruct_attribute(handle);
4560 __mmplayer_init_gstreamer(mmplayer_t *player)
4562 static gboolean initialized = FALSE;
4563 static const int max_argc = 50;
4565 gchar **argv = NULL;
4566 gchar **argv2 = NULL;
4572 LOGD("gstreamer already initialized.");
4577 argc = malloc(sizeof(int));
4578 argv = malloc(sizeof(gchar *) * max_argc);
4579 argv2 = malloc(sizeof(gchar *) * max_argc);
4581 if (!argc || !argv || !argv2)
4584 memset(argv, 0, sizeof(gchar *) * max_argc);
4585 memset(argv2, 0, sizeof(gchar *) * max_argc);
4589 argv[0] = g_strdup("mmplayer");
4592 for (i = 0; i < 5; i++) {
4593 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4594 if (strlen(player->ini.gst_param[i]) > 0) {
4595 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4600 /* we would not do fork for scanning plugins */
4601 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4604 /* check disable registry scan */
4605 if (player->ini.skip_rescan) {
4606 argv[*argc] = g_strdup("--gst-disable-registry-update");
4610 /* check disable segtrap */
4611 if (player->ini.disable_segtrap) {
4612 argv[*argc] = g_strdup("--gst-disable-segtrap");
4616 LOGD("initializing gstreamer with following parameter");
4617 LOGD("argc : %d", *argc);
4620 for (i = 0; i < arg_count; i++) {
4622 LOGD("argv[%d] : %s", i, argv2[i]);
4625 /* initializing gstreamer */
4626 if (!gst_init_check(argc, &argv, &err)) {
4627 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4634 for (i = 0; i < arg_count; i++) {
4635 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4636 MMPLAYER_FREEIF(argv2[i]);
4639 MMPLAYER_FREEIF(argv);
4640 MMPLAYER_FREEIF(argv2);
4641 MMPLAYER_FREEIF(argc);
4651 for (i = 0; i < arg_count; i++) {
4652 LOGD("free[%d] : %s", i, argv2[i]);
4653 MMPLAYER_FREEIF(argv2[i]);
4656 MMPLAYER_FREEIF(argv);
4657 MMPLAYER_FREEIF(argv2);
4658 MMPLAYER_FREEIF(argc);
4664 __mmplayer_check_async_state_transition(mmplayer_t *player)
4666 GstState element_state = GST_STATE_VOID_PENDING;
4667 GstState element_pending_state = GST_STATE_VOID_PENDING;
4668 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4669 GstElement *element = NULL;
4670 gboolean async = FALSE;
4672 /* check player handle */
4673 MMPLAYER_RETURN_IF_FAIL(player &&
4675 player->pipeline->mainbin &&
4676 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4679 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4681 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4682 LOGD("don't need to check the pipeline state");
4686 MMPLAYER_PRINT_STATE(player);
4688 /* wait for state transition */
4689 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4690 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4692 if (ret == GST_STATE_CHANGE_FAILURE) {
4693 LOGE(" [%s] state : %s pending : %s",
4694 GST_ELEMENT_NAME(element),
4695 gst_element_state_get_name(element_state),
4696 gst_element_state_get_name(element_pending_state));
4698 /* dump state of all element */
4699 __mmplayer_dump_pipeline_state(player);
4704 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4709 _mmplayer_destroy(MMHandleType handle)
4711 mmplayer_t *player = MM_PLAYER_CAST(handle);
4715 /* check player handle */
4716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4718 /* destroy can called at anytime */
4719 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4721 /* check async state transition */
4722 __mmplayer_check_async_state_transition(player);
4724 /* release gapless play thread */
4725 if (player->gapless_play_thread) {
4726 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4727 player->gapless_play_thread_exit = TRUE;
4728 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4729 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4731 LOGD("waitting for gapless play thread exit");
4732 g_thread_join(player->gapless_play_thread);
4733 g_mutex_clear(&player->gapless_play_thread_mutex);
4734 g_cond_clear(&player->gapless_play_thread_cond);
4735 LOGD("gapless play thread released");
4738 _mmplayer_release_video_capture(player);
4740 /* de-initialize resource manager */
4741 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4742 player->resource_manager))
4743 LOGE("failed to deinitialize resource manager");
4745 /* release pipeline */
4746 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4747 LOGE("failed to destory pipeline");
4748 return MM_ERROR_PLAYER_INTERNAL;
4751 g_queue_free(player->bus_msg_q);
4753 /* release subtitle info lock and cond */
4754 g_mutex_clear(&player->subtitle_info_mutex);
4755 g_cond_clear(&player->subtitle_info_cond);
4757 __mmplayer_release_dump_list(player->dump_list);
4759 /* release miscellaneous information */
4760 __mmplayer_release_misc(player);
4762 /* release miscellaneous information.
4763 these info needs to be released after pipeline is destroyed. */
4764 __mmplayer_release_misc_post(player);
4766 /* release attributes */
4767 _mmplayer_deconstruct_attribute(handle);
4770 g_mutex_clear(&player->fsink_lock);
4773 g_mutex_clear(&player->update_tag_lock);
4775 /* release video bo lock and cond */
4776 g_mutex_clear(&player->video_bo_mutex);
4777 g_cond_clear(&player->video_bo_cond);
4779 /* release media stream callback lock */
4780 g_mutex_clear(&player->media_stream_cb_lock);
4784 return MM_ERROR_NONE;
4788 _mmplayer_realize(MMHandleType hplayer)
4790 mmplayer_t *player = (mmplayer_t *)hplayer;
4793 MMHandleType attrs = 0;
4794 int ret = MM_ERROR_NONE;
4798 /* check player handle */
4799 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4801 /* check current state */
4802 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4804 attrs = MMPLAYER_GET_ATTRS(player);
4806 LOGE("fail to get attributes.");
4807 return MM_ERROR_PLAYER_INTERNAL;
4809 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4810 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4812 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4813 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4815 if (ret != MM_ERROR_NONE) {
4816 LOGE("failed to parse profile");
4821 if (uri && (strstr(uri, "es_buff://"))) {
4822 if (strstr(uri, "es_buff://push_mode"))
4823 player->es_player_push_mode = TRUE;
4825 player->es_player_push_mode = FALSE;
4828 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4829 LOGW("mms protocol is not supported format.");
4830 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4833 if (MMPLAYER_IS_STREAMING(player))
4834 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4836 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4838 player->smooth_streaming = FALSE;
4839 player->videodec_linked = 0;
4840 player->audiodec_linked = 0;
4841 player->textsink_linked = 0;
4842 player->is_external_subtitle_present = FALSE;
4843 player->is_external_subtitle_added_now = FALSE;
4844 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4845 player->video360_metadata.is_spherical = -1;
4846 player->is_openal_plugin_used = FALSE;
4847 player->demux_pad_index = 0;
4848 player->subtitle_language_list = NULL;
4849 player->is_subtitle_force_drop = FALSE;
4851 __mmplayer_track_initialize(player);
4852 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4854 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4855 gint prebuffer_ms = 0, rebuffer_ms = 0;
4857 player->streamer = __mm_player_streaming_create();
4858 __mm_player_streaming_initialize(player->streamer, TRUE);
4860 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4861 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4863 if (prebuffer_ms > 0) {
4864 prebuffer_ms = MAX(prebuffer_ms, 1000);
4865 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4868 if (rebuffer_ms > 0) {
4869 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4870 rebuffer_ms = MAX(rebuffer_ms, 1000);
4871 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4874 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4875 player->streamer->buffering_req.rebuffer_time);
4878 /* realize pipeline */
4879 ret = __mmplayer_gst_realize(player);
4880 if (ret != MM_ERROR_NONE)
4881 LOGE("fail to realize the player.");
4883 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4891 _mmplayer_unrealize(MMHandleType hplayer)
4893 mmplayer_t *player = (mmplayer_t *)hplayer;
4894 int ret = MM_ERROR_NONE;
4898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4900 MMPLAYER_CMD_UNLOCK(player);
4901 /* destroy the gst bus msg thread which is created during realize.
4902 this funct have to be called before getting cmd lock. */
4903 __mmplayer_bus_msg_thread_destroy(player);
4904 MMPLAYER_CMD_LOCK(player);
4906 /* check current state */
4907 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4909 /* check async state transition */
4910 __mmplayer_check_async_state_transition(player);
4912 /* unrealize pipeline */
4913 ret = __mmplayer_gst_unrealize(player);
4915 /* set asm stop if success */
4916 if (MM_ERROR_NONE == ret) {
4917 if (!player->interrupted_by_resource) {
4918 if (player->video_decoder_resource != NULL) {
4919 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4920 player->video_decoder_resource);
4921 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4922 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4924 player->video_decoder_resource = NULL;
4927 if (player->video_overlay_resource != NULL) {
4928 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4929 player->video_overlay_resource);
4930 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4931 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4933 player->video_overlay_resource = NULL;
4936 ret = mm_resource_manager_commit(player->resource_manager);
4937 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4938 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4941 LOGE("failed and don't change asm state to stop");
4949 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4951 mmplayer_t *player = (mmplayer_t *)hplayer;
4953 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4955 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4959 _mmplayer_get_state(MMHandleType hplayer, int *state)
4961 mmplayer_t *player = (mmplayer_t *)hplayer;
4963 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4965 *state = MMPLAYER_CURRENT_STATE(player);
4967 return MM_ERROR_NONE;
4972 _mmplayer_set_volume(MMHandleType hplayer, mmplayer_volume_type_t volume)
4974 mmplayer_t *player = (mmplayer_t *)hplayer;
4975 GstElement *vol_element = NULL;
4980 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4982 LOGD("volume [L]=%f:[R]=%f",
4983 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4985 /* invalid factor range or not */
4986 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4987 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4988 LOGE("Invalid factor!(valid factor:0~1.0)");
4989 return MM_ERROR_INVALID_ARGUMENT;
4993 /* not support to set other value into each channel */
4994 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4995 return MM_ERROR_INVALID_ARGUMENT;
4997 /* Save volume to handle. Currently the first array element will be saved. */
4998 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5000 /* check pipeline handle */
5001 if (!player->pipeline || !player->pipeline->audiobin) {
5002 LOGD("audiobin is not created yet");
5003 LOGD("but, current stored volume will be set when it's created.");
5005 /* NOTE : stored volume will be used in create_audiobin
5006 * returning MM_ERROR_NONE here makes application to able to
5007 * set volume at anytime.
5009 return MM_ERROR_NONE;
5012 /* setting volume to volume element */
5013 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5016 LOGD("volume is set [%f]", player->sound.volume);
5017 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5022 return MM_ERROR_NONE;
5026 _mmplayer_get_volume(MMHandleType hplayer, mmplayer_volume_type_t *volume)
5028 mmplayer_t *player = (mmplayer_t *)hplayer;
5033 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5034 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5036 /* returning stored volume */
5037 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5038 volume->level[i] = player->sound.volume;
5042 return MM_ERROR_NONE;
5046 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5048 mmplayer_t *player = (mmplayer_t *)hplayer;
5049 GstElement *vol_element = NULL;
5053 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5055 /* mute value shoud 0 or 1 */
5056 if (mute != 0 && mute != 1) {
5057 LOGE("bad mute value");
5059 /* FIXIT : definitly, we need _BAD_PARAM error code */
5060 return MM_ERROR_INVALID_ARGUMENT;
5063 player->sound.mute = mute;
5065 /* just hold mute value if pipeline is not ready */
5066 if (!player->pipeline || !player->pipeline->audiobin) {
5067 LOGD("pipeline is not ready. holding mute value");
5068 return MM_ERROR_NONE;
5071 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5073 /* NOTE : volume will only created when the bt is enabled */
5075 LOGD("mute : %d", mute);
5076 g_object_set(vol_element, "mute", mute, NULL);
5078 LOGD("volume elemnet is not created. using volume in audiosink");
5082 return MM_ERROR_NONE;
5086 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5088 mmplayer_t *player = (mmplayer_t *)hplayer;
5092 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5093 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5095 /* just hold mute value if pipeline is not ready */
5096 if (!player->pipeline || !player->pipeline->audiobin) {
5097 LOGD("pipeline is not ready. returning stored value");
5098 *pmute = player->sound.mute;
5099 return MM_ERROR_NONE;
5102 *pmute = player->sound.mute;
5106 return MM_ERROR_NONE;
5110 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5112 mmplayer_t *player = (mmplayer_t *)hplayer;
5116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5118 player->video_stream_changed_cb = callback;
5119 player->video_stream_changed_cb_user_param = user_param;
5120 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5124 return MM_ERROR_NONE;
5128 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5130 mmplayer_t *player = (mmplayer_t *)hplayer;
5134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5136 player->audio_stream_changed_cb = callback;
5137 player->audio_stream_changed_cb_user_param = user_param;
5138 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5142 return MM_ERROR_NONE;
5146 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5148 mmplayer_t *player = (mmplayer_t *)hplayer;
5152 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5154 player->audio_stream_render_cb = callback;
5155 player->audio_stream_cb_user_param = user_param;
5156 player->audio_stream_sink_sync = sync;
5157 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5161 return MM_ERROR_NONE;
5165 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5167 mmplayer_t *player = (mmplayer_t *)hplayer;
5171 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5173 if (callback && !player->bufmgr)
5174 player->bufmgr = tbm_bufmgr_init(-1);
5176 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5177 player->video_stream_cb = callback;
5178 player->video_stream_cb_user_param = user_param;
5180 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5184 return MM_ERROR_NONE;
5188 _mmplayer_start(MMHandleType hplayer)
5190 mmplayer_t *player = (mmplayer_t *)hplayer;
5191 gint ret = MM_ERROR_NONE;
5195 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5197 /* check current state */
5198 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5200 /* start pipeline */
5201 ret = __mmplayer_gst_start(player);
5202 if (ret != MM_ERROR_NONE)
5203 LOGE("failed to start player.");
5205 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5206 LOGD("force playing start even during buffering");
5207 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5215 /* NOTE: post "not supported codec message" to application
5216 * when one codec is not found during AUTOPLUGGING in MSL.
5217 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5218 * And, if any codec is not found, don't send message here.
5219 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5222 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5224 MMMessageParamType msg_param;
5225 memset(&msg_param, 0, sizeof(MMMessageParamType));
5226 gboolean post_msg_direct = FALSE;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5232 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5233 player->not_supported_codec, player->can_support_codec);
5235 if (player->not_found_demuxer) {
5236 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5237 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5239 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5240 MMPLAYER_FREEIF(msg_param.data);
5242 return MM_ERROR_NONE;
5245 if (player->not_supported_codec) {
5246 if (player->can_support_codec) {
5247 // There is one codec to play
5248 post_msg_direct = TRUE;
5250 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5251 post_msg_direct = TRUE;
5254 if (post_msg_direct) {
5255 MMMessageParamType msg_param;
5256 memset(&msg_param, 0, sizeof(MMMessageParamType));
5258 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5259 LOGW("not found AUDIO codec, posting error code to application.");
5261 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5262 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5263 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5264 LOGW("not found VIDEO codec, posting error code to application.");
5266 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5267 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5270 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5272 MMPLAYER_FREEIF(msg_param.data);
5274 return MM_ERROR_NONE;
5276 // no any supported codec case
5277 LOGW("not found any codec, posting error code to application.");
5279 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5280 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5281 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5283 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5284 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5287 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5289 MMPLAYER_FREEIF(msg_param.data);
5295 return MM_ERROR_NONE;
5299 __mmplayer_check_pipeline(mmplayer_t *player)
5301 GstState element_state = GST_STATE_VOID_PENDING;
5302 GstState element_pending_state = GST_STATE_VOID_PENDING;
5304 int ret = MM_ERROR_NONE;
5306 if (!player->gapless.reconfigure)
5309 LOGW("pipeline is under construction.");
5311 MMPLAYER_PLAYBACK_LOCK(player);
5312 MMPLAYER_PLAYBACK_UNLOCK(player);
5314 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5316 /* wait for state transition */
5317 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5318 if (ret == GST_STATE_CHANGE_FAILURE)
5319 LOGE("failed to change pipeline state within %d sec", timeout);
5322 /* NOTE : it should be able to call 'stop' anytime*/
5324 _mmplayer_stop(MMHandleType hplayer)
5326 mmplayer_t *player = (mmplayer_t *)hplayer;
5327 int ret = MM_ERROR_NONE;
5331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5333 /* check current state */
5334 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5336 /* check pipline building state */
5337 __mmplayer_check_pipeline(player);
5338 __mmplayer_reset_gapless_state(player);
5340 /* NOTE : application should not wait for EOS after calling STOP */
5341 __mmplayer_cancel_eos_timer(player);
5344 player->seek_state = MMPLAYER_SEEK_NONE;
5347 ret = __mmplayer_gst_stop(player);
5349 if (ret != MM_ERROR_NONE)
5350 LOGE("failed to stop player.");
5358 _mmplayer_pause(MMHandleType hplayer)
5360 mmplayer_t *player = (mmplayer_t *)hplayer;
5361 gint64 pos_nsec = 0;
5362 gboolean async = FALSE;
5363 gint ret = MM_ERROR_NONE;
5367 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5369 /* check current state */
5370 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5372 /* check pipline building state */
5373 __mmplayer_check_pipeline(player);
5375 switch (MMPLAYER_CURRENT_STATE(player)) {
5376 case MM_PLAYER_STATE_READY:
5378 /* check prepare async or not.
5379 * In the case of streaming playback, it's recommned to avoid blocking wait.
5381 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5382 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5384 /* Changing back sync of rtspsrc to async */
5385 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5386 LOGD("async prepare working mode for rtsp");
5392 case MM_PLAYER_STATE_PLAYING:
5394 /* NOTE : store current point to overcome some bad operation
5395 *(returning zero when getting current position in paused state) of some
5398 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5399 LOGW("getting current position failed in paused");
5401 player->last_position = pos_nsec;
5403 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5404 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5405 This causes problem is position calculation during normal pause resume scenarios also.
5406 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5407 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5408 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5409 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5415 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5416 LOGD("doing async pause in case of ms buff src");
5420 /* pause pipeline */
5421 ret = __mmplayer_gst_pause(player, async);
5423 if (ret != MM_ERROR_NONE)
5424 LOGE("failed to pause player. ret : 0x%x", ret);
5426 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5427 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5428 LOGE("failed to update display_rotation");
5436 /* in case of streaming, pause could take long time.*/
5438 _mmplayer_abort_pause(MMHandleType hplayer)
5440 mmplayer_t *player = (mmplayer_t *)hplayer;
5441 int ret = MM_ERROR_NONE;
5445 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5447 player->pipeline->mainbin,
5448 MM_ERROR_PLAYER_NOT_INITIALIZED);
5450 LOGD("set the pipeline state to READY");
5452 /* set state to READY */
5453 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5454 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5455 if (ret != MM_ERROR_NONE) {
5456 LOGE("fail to change state to READY");
5457 return MM_ERROR_PLAYER_INTERNAL;
5460 LOGD("succeeded in changing state to READY");
5465 _mmplayer_resume(MMHandleType hplayer)
5467 mmplayer_t *player = (mmplayer_t *)hplayer;
5468 int ret = MM_ERROR_NONE;
5469 gboolean async = FALSE;
5473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5475 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5476 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5477 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5481 /* Changing back sync mode rtspsrc to async */
5482 LOGD("async resume for rtsp case");
5486 /* check current state */
5487 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5489 ret = __mmplayer_gst_resume(player, async);
5490 if (ret != MM_ERROR_NONE)
5491 LOGE("failed to resume player.");
5493 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5494 LOGD("force resume even during buffering");
5495 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5504 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5506 mmplayer_t *player = (mmplayer_t *)hplayer;
5507 gint64 pos_nsec = 0;
5508 int ret = MM_ERROR_NONE;
5510 signed long long start = 0, stop = 0;
5511 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5514 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5515 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5517 /* The sound of video is not supported under 0.0 and over 2.0. */
5518 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5519 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5522 _mmplayer_set_mute(hplayer, mute);
5524 if (player->playback_rate == rate)
5525 return MM_ERROR_NONE;
5527 /* If the position is reached at start potion during fast backward, EOS is posted.
5528 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5530 player->playback_rate = rate;
5532 current_state = MMPLAYER_CURRENT_STATE(player);
5534 if (current_state != MM_PLAYER_STATE_PAUSED)
5535 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5537 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5539 if ((current_state == MM_PLAYER_STATE_PAUSED)
5540 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5541 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5542 pos_nsec = player->last_position;
5547 stop = GST_CLOCK_TIME_NONE;
5549 start = GST_CLOCK_TIME_NONE;
5553 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5554 player->playback_rate,
5556 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5557 GST_SEEK_TYPE_SET, start,
5558 GST_SEEK_TYPE_SET, stop)) {
5559 LOGE("failed to set speed playback");
5560 return MM_ERROR_PLAYER_SEEK;
5563 LOGD("succeeded to set speed playback as %0.1f", rate);
5567 return MM_ERROR_NONE;;
5571 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5573 mmplayer_t *player = (mmplayer_t *)hplayer;
5574 int ret = MM_ERROR_NONE;
5578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5580 /* check pipline building state */
5581 __mmplayer_check_pipeline(player);
5583 ret = __mmplayer_gst_set_position(player, position, FALSE);
5591 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5593 mmplayer_t *player = (mmplayer_t *)hplayer;
5594 int ret = MM_ERROR_NONE;
5596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5598 ret = __mmplayer_gst_get_position(player, position);
5604 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5606 mmplayer_t *player = (mmplayer_t *)hplayer;
5607 int ret = MM_ERROR_NONE;
5609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5610 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5612 if (g_strrstr(player->type, "video/mpegts"))
5613 __mmplayer_update_duration_value(player);
5615 *duration = player->duration;
5620 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5622 mmplayer_t *player = (mmplayer_t *)hplayer;
5623 int ret = MM_ERROR_NONE;
5625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5627 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5633 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5635 mmplayer_t *player = (mmplayer_t *)hplayer;
5636 int ret = MM_ERROR_NONE;
5640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5642 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5650 __mmplayer_is_midi_type(gchar *str_caps)
5652 if ((g_strrstr(str_caps, "audio/midi")) ||
5653 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5654 (g_strrstr(str_caps, "application/x-smaf")) ||
5655 (g_strrstr(str_caps, "audio/x-imelody")) ||
5656 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5657 (g_strrstr(str_caps, "audio/xmf")) ||
5658 (g_strrstr(str_caps, "audio/mxmf"))) {
5667 __mmplayer_is_only_mp3_type(gchar *str_caps)
5669 if (g_strrstr(str_caps, "application/x-id3") ||
5670 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5676 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5678 GstStructure *caps_structure = NULL;
5679 gint samplerate = 0;
5683 MMPLAYER_RETURN_IF_FAIL(player && caps);
5685 caps_structure = gst_caps_get_structure(caps, 0);
5687 /* set stream information */
5688 gst_structure_get_int(caps_structure, "rate", &samplerate);
5689 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5691 gst_structure_get_int(caps_structure, "channels", &channels);
5692 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5694 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5698 __mmplayer_update_content_type_info(mmplayer_t *player)
5701 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5703 if (__mmplayer_is_midi_type(player->type)) {
5704 player->bypass_audio_effect = TRUE;
5708 if (!player->streamer) {
5709 LOGD("no need to check streaming type");
5713 if (g_strrstr(player->type, "application/x-hls")) {
5714 /* If it can't know exact type when it parses uri because of redirection case,
5715 * it will be fixed by typefinder or when doing autoplugging.
5717 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5718 player->streamer->is_adaptive_streaming = TRUE;
5719 } else if (g_strrstr(player->type, "application/dash+xml")) {
5720 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5721 player->streamer->is_adaptive_streaming = TRUE;
5724 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5725 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5726 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5728 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5729 if (player->streamer->is_adaptive_streaming)
5730 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5732 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5736 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5741 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5742 GstCaps *caps, gpointer data)
5744 mmplayer_t *player = (mmplayer_t *)data;
5749 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5751 /* store type string */
5752 MMPLAYER_FREEIF(player->type);
5753 player->type = gst_caps_to_string(caps);
5755 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5756 player, player->type, probability, gst_caps_get_size(caps));
5758 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5759 (g_strrstr(player->type, "audio/x-raw-int"))) {
5760 LOGE("not support media format");
5762 if (player->msg_posted == FALSE) {
5763 MMMessageParamType msg_param;
5764 memset(&msg_param, 0, sizeof(MMMessageParamType));
5766 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5767 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5769 /* don't post more if one was sent already */
5770 player->msg_posted = TRUE;
5775 __mmplayer_update_content_type_info(player);
5777 pad = gst_element_get_static_pad(tf, "src");
5779 LOGE("fail to get typefind src pad.");
5783 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5784 gboolean async = FALSE;
5785 LOGE("failed to autoplug %s", player->type);
5787 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5789 if (async && player->msg_posted == FALSE)
5790 __mmplayer_handle_missed_plugin(player);
5794 gst_object_unref(GST_OBJECT(pad));
5802 __mmplayer_gst_make_decodebin(mmplayer_t *player)
5804 GstElement *decodebin = NULL;
5808 /* create decodebin */
5809 decodebin = gst_element_factory_make("decodebin", NULL);
5812 LOGE("fail to create decodebin");
5816 /* raw pad handling signal */
5817 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5818 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5820 /* no-more-pad pad handling signal */
5821 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5822 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5824 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5825 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5827 /* This signal is emitted when a pad for which there is no further possible
5828 decoding is added to the decodebin.*/
5829 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5830 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (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-continue",
5835 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5837 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5838 before looking for any elements that can handle that stream.*/
5839 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5840 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5842 /* This signal is emitted once decodebin has finished decoding all the data.*/
5843 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5844 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5846 /* This signal is emitted when a element is added to the bin.*/
5847 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5848 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5855 __mmplayer_gst_make_queue2(mmplayer_t *player)
5857 GstElement *queue2 = NULL;
5858 gint64 dur_bytes = 0L;
5859 mmplayer_gst_element_t *mainbin = NULL;
5860 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5863 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5865 mainbin = player->pipeline->mainbin;
5867 queue2 = gst_element_factory_make("queue2", "queue2");
5869 LOGE("failed to create buffering queue element");
5873 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5874 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5876 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5878 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5879 * skip the pull mode(file or ring buffering) setting. */
5880 if (dur_bytes > 0) {
5881 if (!g_strrstr(player->type, "video/mpegts")) {
5882 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5883 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5889 __mm_player_streaming_set_queue2(player->streamer,
5893 (guint64)dur_bytes); /* no meaning at the moment */
5899 __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
5901 mmplayer_gst_element_t *mainbin = NULL;
5902 GstElement *decodebin = NULL;
5903 GstElement *queue2 = NULL;
5904 GstPad *sinkpad = NULL;
5905 GstPad *qsrcpad = NULL;
5908 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5910 mainbin = player->pipeline->mainbin;
5912 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5914 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5915 LOGW("need to check: muxed buffer is not null");
5918 queue2 = __mmplayer_gst_make_queue2(player);
5920 LOGE("failed to make queue2");
5924 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5925 LOGE("failed to add buffering queue");
5929 sinkpad = gst_element_get_static_pad(queue2, "sink");
5930 qsrcpad = gst_element_get_static_pad(queue2, "src");
5932 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5933 LOGE("failed to link [%s:%s]-[%s:%s]",
5934 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5938 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5939 LOGE("failed to sync queue2 state with parent");
5943 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5944 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5948 gst_object_unref(GST_OBJECT(sinkpad));
5952 /* create decodebin */
5953 decodebin = __mmplayer_gst_make_decodebin(player);
5955 LOGE("failed to make decodebin");
5959 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5960 LOGE("failed to add decodebin");
5964 /* to force caps on the decodebin element and avoid reparsing stuff by
5965 * typefind. It also avoids a deadlock in the way typefind activates pads in
5966 * the state change */
5967 g_object_set(decodebin, "sink-caps", caps, NULL);
5969 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5971 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5972 LOGE("failed to link [%s:%s]-[%s:%s]",
5973 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5977 gst_object_unref(GST_OBJECT(sinkpad));
5979 gst_object_unref(GST_OBJECT(qsrcpad));
5982 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5983 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5985 /* set decodebin property about buffer in streaming playback. *
5986 * in case of HLS/DASH, it does not need to have big buffer *
5987 * because it is kind of adaptive streaming. */
5988 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5989 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5990 gint high_percent = 0;
5992 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5993 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5995 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5997 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5999 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6000 "high-percent", high_percent,
6001 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6002 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6003 "max-size-buffers", 0, NULL); // disable or automatic
6006 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6007 LOGE("failed to sync decodebin state with parent");
6018 gst_object_unref(GST_OBJECT(sinkpad));
6021 gst_object_unref(GST_OBJECT(qsrcpad));
6024 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6025 * You need to explicitly set elements to the NULL state before
6026 * dropping the final reference, to allow them to clean up.
6028 gst_element_set_state(queue2, GST_STATE_NULL);
6030 /* And, it still has a parent "player".
6031 * You need to let the parent manage the object instead of unreffing the object directly.
6033 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6034 gst_object_unref(queue2);
6039 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6040 * You need to explicitly set elements to the NULL state before
6041 * dropping the final reference, to allow them to clean up.
6043 gst_element_set_state(decodebin, GST_STATE_NULL);
6045 /* And, it still has a parent "player".
6046 * You need to let the parent manage the object instead of unreffing the object directly.
6049 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6050 gst_object_unref(decodebin);
6058 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6062 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6063 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6065 LOGD("class : %s, mime : %s", factory_class, mime);
6067 /* add missing plugin */
6068 /* NOTE : msl should check missing plugin for image mime type.
6069 * Some motion jpeg clips can have playable audio track.
6070 * So, msl have to play audio after displaying popup written video format not supported.
6072 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6073 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6074 LOGD("not found demuxer");
6075 player->not_found_demuxer = TRUE;
6076 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6082 if (!g_strrstr(factory_class, "Demuxer")) {
6083 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6084 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6085 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6087 /* check that clip have multi tracks or not */
6088 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6089 LOGD("video plugin is already linked");
6091 LOGW("add VIDEO to missing plugin");
6092 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6093 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6095 } else if (g_str_has_prefix(mime, "audio")) {
6096 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6097 LOGD("audio plugin is already linked");
6099 LOGW("add AUDIO to missing plugin");
6100 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6101 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6109 return MM_ERROR_NONE;
6113 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6115 mmplayer_t *player = (mmplayer_t *)data;
6119 MMPLAYER_RETURN_IF_FAIL(player);
6121 /* remove fakesink. */
6122 if (!__mmplayer_gst_remove_fakesink(player,
6123 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6124 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6125 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6126 * source element are not same. To overcome this situation, this function will called
6127 * several places and several times. Therefore, this is not an error case.
6132 LOGD("[handle: %p] pipeline has completely constructed", player);
6134 if ((player->ini.async_start) &&
6135 (player->msg_posted == FALSE) &&
6136 (player->cmd >= MMPLAYER_COMMAND_START))
6137 __mmplayer_handle_missed_plugin(player);
6139 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6143 __mmplayer_check_profile(void)
6146 static int profile_tv = -1;
6148 if (__builtin_expect(profile_tv != -1, 1))
6151 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6152 switch (*profileName) {
6167 __mmplayer_get_next_uri(mmplayer_t *player)
6169 mmplayer_parse_profile_t profile;
6171 guint num_of_list = 0;
6174 num_of_list = g_list_length(player->uri_info.uri_list);
6175 uri_idx = player->uri_info.uri_idx;
6177 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6178 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6179 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6181 LOGW("next uri does not exist");
6185 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6186 LOGE("failed to parse profile");
6190 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6191 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6192 LOGW("uri type is not supported(%d)", profile.uri_type);
6196 LOGD("success to find next uri %d", uri_idx);
6200 if (uri_idx == num_of_list) {
6201 LOGE("failed to find next uri");
6205 player->uri_info.uri_idx = uri_idx;
6206 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6208 if (mm_attrs_commit_all(player->attrs)) {
6209 LOGE("failed to commit");
6213 SECURE_LOGD("next playback uri: %s", uri);
6218 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6220 #define REPEAT_COUNT_INFINITELY -1
6221 #define REPEAT_COUNT_MIN 2
6223 MMHandleType attrs = 0;
6227 guint num_of_list = 0;
6228 int profile_tv = -1;
6232 LOGD("checking for gapless play option");
6234 if (player->pipeline->textbin) {
6235 LOGE("subtitle path is enabled. gapless play is not supported.");
6239 attrs = MMPLAYER_GET_ATTRS(player);
6241 LOGE("fail to get attributes.");
6245 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6247 /* gapless playback is not supported in case of video at TV profile. */
6248 profile_tv = __mmplayer_check_profile();
6249 if (profile_tv && video) {
6250 LOGW("not support video gapless playback");
6254 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6255 LOGE("failed to get play count");
6257 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6258 LOGE("failed to get gapless mode");
6260 /* check repeat count in case of audio */
6262 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6263 LOGW("gapless is disabled");
6267 num_of_list = g_list_length(player->uri_info.uri_list);
6269 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6271 if (num_of_list == 0) {
6272 /* audio looping path */
6273 if (count >= REPEAT_COUNT_MIN) {
6274 /* decrease play count */
6275 /* we succeeded to rewind. update play count and then wait for next EOS */
6277 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6278 /* commit attribute */
6279 if (mm_attrs_commit_all(attrs))
6280 LOGE("failed to commit attribute");
6282 } else if (count != REPEAT_COUNT_INFINITELY) {
6283 LOGD("there is no next uri and no repeat");
6286 LOGD("looping cnt %d", count);
6288 /* gapless playback path */
6289 if (!__mmplayer_get_next_uri(player)) {
6290 LOGE("failed to get next uri");
6297 LOGE("unable to play gapless path. EOS will be posted soon");
6302 __mmplayer_initialize_gapless_play(mmplayer_t *player)
6308 player->smooth_streaming = FALSE;
6309 player->videodec_linked = 0;
6310 player->audiodec_linked = 0;
6311 player->textsink_linked = 0;
6312 player->is_external_subtitle_present = FALSE;
6313 player->is_external_subtitle_added_now = FALSE;
6314 player->not_supported_codec = MISSING_PLUGIN_NONE;
6315 player->can_support_codec = FOUND_PLUGIN_NONE;
6316 player->pending_seek.is_pending = false;
6317 player->pending_seek.pos = 0;
6318 player->msg_posted = FALSE;
6319 player->has_many_types = FALSE;
6320 player->no_more_pad = FALSE;
6321 player->not_found_demuxer = 0;
6322 player->seek_state = MMPLAYER_SEEK_NONE;
6323 player->is_subtitle_force_drop = FALSE;
6324 player->play_subtitle = FALSE;
6325 player->adjust_subtitle_pos = 0;
6327 player->total_bitrate = 0;
6328 player->total_maximum_bitrate = 0;
6330 __mmplayer_track_initialize(player);
6331 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6333 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6334 player->bitrate[i] = 0;
6335 player->maximum_bitrate[i] = 0;
6338 if (player->v_stream_caps) {
6339 gst_caps_unref(player->v_stream_caps);
6340 player->v_stream_caps = NULL;
6343 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6345 /* clean found audio decoders */
6346 if (player->audio_decoders) {
6347 GList *a_dec = player->audio_decoders;
6348 for (; a_dec; a_dec = g_list_next(a_dec)) {
6349 gchar *name = a_dec->data;
6350 MMPLAYER_FREEIF(name);
6352 g_list_free(player->audio_decoders);
6353 player->audio_decoders = NULL;
6360 __mmplayer_activate_next_source(mmplayer_t *player, GstState target)
6362 mmplayer_gst_element_t *mainbin = NULL;
6363 MMMessageParamType msg_param = {0,};
6364 GstElement *element = NULL;
6365 MMHandleType attrs = 0;
6367 main_element_id_e elem_idx = MMPLAYER_M_NUM;
6371 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6372 LOGE("player is not initialized");
6376 mainbin = player->pipeline->mainbin;
6377 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6379 attrs = MMPLAYER_GET_ATTRS(player);
6381 LOGE("fail to get attributes");
6385 /* Initialize Player values */
6386 __mmplayer_initialize_gapless_play(player);
6388 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6390 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6391 LOGE("failed to parse profile");
6392 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6396 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6397 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6398 LOGE("dash or hls is not supportable");
6399 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6403 element = __mmplayer_gst_create_source(player);
6405 LOGE("no source element was created");
6409 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6410 LOGE("failed to add source element to pipeline");
6411 gst_object_unref(GST_OBJECT(element));
6416 /* take source element */
6417 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6418 mainbin[MMPLAYER_M_SRC].gst = element;
6422 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6423 if (player->streamer == NULL) {
6424 player->streamer = __mm_player_streaming_create();
6425 __mm_player_streaming_initialize(player->streamer, TRUE);
6428 elem_idx = MMPLAYER_M_TYPEFIND;
6429 element = gst_element_factory_make("typefind", "typefinder");
6430 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6431 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6433 elem_idx = MMPLAYER_M_AUTOPLUG;
6434 element = __mmplayer_gst_make_decodebin(player);
6437 /* check autoplug element is OK */
6439 LOGE("can not create element(%d)", elem_idx);
6443 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6444 LOGE("failed to add sinkbin to pipeline");
6445 gst_object_unref(GST_OBJECT(element));
6450 mainbin[elem_idx].id = elem_idx;
6451 mainbin[elem_idx].gst = element;
6453 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6454 LOGE("Failed to link src - autoplug(or typefind)");
6458 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6459 LOGE("Failed to change state of src element");
6463 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6464 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6465 LOGE("Failed to change state of decodebin");
6469 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6470 LOGE("Failed to change state of src element");
6475 player->gapless.stream_changed = TRUE;
6476 player->gapless.running = TRUE;
6482 MMPLAYER_PLAYBACK_UNLOCK(player);
6484 if (!player->msg_posted) {
6485 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6486 player->msg_posted = TRUE;
6493 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6495 mmplayer_selector_t *selector = &player->selector[type];
6496 mmplayer_gst_element_t *sinkbin = NULL;
6497 main_element_id_e selectorId = MMPLAYER_M_NUM;
6498 main_element_id_e sinkId = MMPLAYER_M_NUM;
6499 GstPad *srcpad = NULL;
6500 GstPad *sinkpad = NULL;
6501 gboolean send_notice = FALSE;
6504 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6506 LOGD("type %d", type);
6509 case MM_PLAYER_TRACK_TYPE_AUDIO:
6510 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6511 sinkId = MMPLAYER_A_BIN;
6512 sinkbin = player->pipeline->audiobin;
6514 case MM_PLAYER_TRACK_TYPE_VIDEO:
6515 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6516 sinkId = MMPLAYER_V_BIN;
6517 sinkbin = player->pipeline->videobin;
6520 case MM_PLAYER_TRACK_TYPE_TEXT:
6521 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6522 sinkId = MMPLAYER_T_BIN;
6523 sinkbin = player->pipeline->textbin;
6526 LOGE("requested type is not supportable");
6531 if (player->pipeline->mainbin[selectorId].gst) {
6534 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6536 if (selector->event_probe_id != 0)
6537 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6538 selector->event_probe_id = 0;
6540 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6541 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6543 if (srcpad && sinkpad) {
6544 /* after getting drained signal there is no data flows, so no need to do pad_block */
6545 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6546 gst_pad_unlink(srcpad, sinkpad);
6548 /* send custom event to sink pad to handle it at video sink */
6550 LOGD("send custom event to sinkpad");
6551 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6552 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6553 gst_pad_send_event(sinkpad, event);
6557 gst_object_unref(sinkpad);
6560 gst_object_unref(srcpad);
6563 LOGD("selector release");
6565 /* release and unref requests pad from the selector */
6566 for (n = 0; n < selector->channels->len; n++) {
6567 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6568 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6570 g_ptr_array_set_size(selector->channels, 0);
6572 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6573 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6575 player->pipeline->mainbin[selectorId].gst = NULL;
6583 __mmplayer_deactivate_old_path(mmplayer_t *player)
6586 MMPLAYER_RETURN_IF_FAIL(player);
6588 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6589 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6590 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6591 LOGE("deactivate selector error");
6595 __mmplayer_track_destroy(player);
6596 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6598 if (player->streamer) {
6599 __mm_player_streaming_initialize(player->streamer, FALSE);
6600 __mm_player_streaming_destroy(player->streamer);
6601 player->streamer = NULL;
6604 MMPLAYER_PLAYBACK_LOCK(player);
6605 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6612 if (!player->msg_posted) {
6613 MMMessageParamType msg = {0,};
6616 msg.code = MM_ERROR_PLAYER_INTERNAL;
6617 LOGE("gapless_uri_play> deactivate error");
6619 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6620 player->msg_posted = TRUE;
6626 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6628 int result = MM_ERROR_NONE;
6629 mmplayer_t *player = (mmplayer_t *)hplayer;
6632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6634 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6635 if (mm_attrs_commit_all(player->attrs)) {
6636 LOGE("failed to commit the original uri.");
6637 result = MM_ERROR_PLAYER_INTERNAL;
6639 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6640 LOGE("failed to add the original uri in the uri list.");
6648 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6650 mmplayer_t *player = (mmplayer_t *)hplayer;
6651 guint num_of_list = 0;
6655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6656 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6658 if (player->pipeline && player->pipeline->textbin) {
6659 LOGE("subtitle path is enabled.");
6660 return MM_ERROR_PLAYER_INVALID_STATE;
6663 num_of_list = g_list_length(player->uri_info.uri_list);
6665 if (is_first_path) {
6666 if (num_of_list == 0) {
6667 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6668 SECURE_LOGD("add original path : %s", uri);
6670 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6671 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6673 SECURE_LOGD("change original path : %s", uri);
6676 MMHandleType attrs = 0;
6677 attrs = MMPLAYER_GET_ATTRS(player);
6679 if (num_of_list == 0) {
6680 char *original_uri = NULL;
6683 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6685 if (!original_uri) {
6686 LOGE("there is no original uri.");
6687 return MM_ERROR_PLAYER_INVALID_STATE;
6690 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6691 player->uri_info.uri_idx = 0;
6693 SECURE_LOGD("add original path at first : %s", original_uri);
6697 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6698 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6702 return MM_ERROR_NONE;
6706 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6708 mmplayer_t *player = (mmplayer_t *)hplayer;
6709 char *next_uri = NULL;
6710 guint num_of_list = 0;
6713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6715 num_of_list = g_list_length(player->uri_info.uri_list);
6717 if (num_of_list > 0) {
6718 gint uri_idx = player->uri_info.uri_idx;
6720 if (uri_idx < num_of_list-1)
6725 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6726 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6728 *uri = g_strdup(next_uri);
6732 return MM_ERROR_NONE;
6736 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6737 GstCaps *caps, gpointer data)
6739 mmplayer_t *player = (mmplayer_t *)data;
6740 const gchar *klass = NULL;
6741 const gchar *mime = NULL;
6742 gchar *caps_str = NULL;
6744 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6745 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6746 caps_str = gst_caps_to_string(caps);
6748 LOGW("unknown type of caps : %s from %s",
6749 caps_str, GST_ELEMENT_NAME(elem));
6751 MMPLAYER_FREEIF(caps_str);
6753 /* There is no available codec. */
6754 __mmplayer_check_not_supported_codec(player, klass, mime);
6758 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6759 GstCaps *caps, gpointer data)
6761 mmplayer_t *player = (mmplayer_t *)data;
6762 const char *mime = NULL;
6763 gboolean ret = TRUE;
6765 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6766 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6768 if (g_str_has_prefix(mime, "audio")) {
6769 GstStructure *caps_structure = NULL;
6770 gint samplerate = 0;
6772 gchar *caps_str = NULL;
6774 caps_structure = gst_caps_get_structure(caps, 0);
6775 gst_structure_get_int(caps_structure, "rate", &samplerate);
6776 gst_structure_get_int(caps_structure, "channels", &channels);
6778 if ((channels > 0 && samplerate == 0)) {
6779 LOGD("exclude audio...");
6783 caps_str = gst_caps_to_string(caps);
6784 /* set it directly because not sent by TAG */
6785 if (g_strrstr(caps_str, "mobile-xmf"))
6786 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6787 MMPLAYER_FREEIF(caps_str);
6788 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6789 MMMessageParamType msg_param;
6790 memset(&msg_param, 0, sizeof(MMMessageParamType));
6791 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6792 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6793 LOGD("video file is not supported on this device");
6795 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6796 LOGD("already video linked");
6799 LOGD("found new stream");
6806 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6808 gboolean ret = TRUE;
6809 GDBusConnection *conn = NULL;
6811 GVariant *result = NULL;
6812 const gchar *dbus_device_type = NULL;
6813 const gchar *dbus_ret = NULL;
6816 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6818 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6824 result = g_dbus_connection_call_sync(conn,
6825 "org.pulseaudio.Server",
6826 "/org/pulseaudio/StreamManager",
6827 "org.pulseaudio.StreamManager",
6828 "GetCurrentMediaRoutingPath",
6829 g_variant_new("(s)", "out"),
6830 G_VARIANT_TYPE("(ss)"),
6831 G_DBUS_CALL_FLAGS_NONE,
6835 if (!result || err) {
6836 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6842 /* device type is listed in stream-map.json at mmfw-sysconf */
6843 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6845 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6846 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6851 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6852 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6853 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6854 LOGD("audio offload is supportable");
6860 LOGD("audio offload is not supportable");
6864 g_variant_unref(result);
6865 g_object_unref(conn);
6870 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6872 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6873 gint64 position = 0;
6875 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6876 player->pipeline && player->pipeline->mainbin);
6878 MMPLAYER_CMD_LOCK(player);
6879 current_state = MMPLAYER_CURRENT_STATE(player);
6881 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6882 LOGW("getting current position failed in paused");
6884 _mmplayer_unrealize((MMHandleType)player);
6885 _mmplayer_realize((MMHandleType)player);
6887 _mmplayer_set_position((MMHandleType)player, position);
6889 /* async not to be blocked in streaming case */
6890 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6891 if (mm_attrs_commit_all(player->attrs))
6892 LOGE("failed to commit");
6894 _mmplayer_pause((MMHandleType)player);
6896 if (current_state == MM_PLAYER_STATE_PLAYING)
6897 _mmplayer_start((MMHandleType)player);
6898 MMPLAYER_CMD_UNLOCK(player);
6900 LOGD("rebuilding audio pipeline is completed.");
6903 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6905 mmplayer_t *player = (mmplayer_t *)user_data;
6906 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6907 gboolean is_supportable = FALSE;
6909 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6910 LOGW("failed to get device type");
6912 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6914 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6915 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6916 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6917 LOGD("ignore this dev connected info");
6921 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6922 if (player->build_audio_offload == is_supportable) {
6923 LOGD("keep current pipeline without re-building");
6927 /* rebuild pipeline */
6928 LOGD("re-build pipeline - offload: %d", is_supportable);
6929 player->build_audio_offload = FALSE;
6930 __mmplayer_rebuild_audio_pipeline(player);
6936 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6938 unsigned int id = 0;
6940 if (player->audio_device_cb_id != 0) {
6941 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6945 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6946 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6947 LOGD("added device connected cb (%u)", id);
6948 player->audio_device_cb_id = id;
6950 LOGW("failed to add device connected cb");
6958 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6960 gboolean ret = FALSE;
6961 GstElementFactory *factory = NULL;
6964 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6966 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6967 if (!__mmplayer_is_only_mp3_type(player->type))
6970 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6971 LOGD("there is no audio offload sink");
6975 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6976 LOGW("there is no audio device type to support offload");
6980 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6982 LOGW("there is no installed audio offload sink element");
6985 gst_object_unref(factory);
6987 if (!__mmplayer_add_audio_device_connected_cb(player))
6990 if (!__mmplayer_is_audio_offload_device_type(player))
6993 LOGD("audio offload can be built");
7001 static GstAutoplugSelectResult
7002 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7004 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7006 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7007 int audio_offload = 0;
7009 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7010 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7012 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7013 LOGD("expose audio path to build offload output path");
7014 player->build_audio_offload = TRUE;
7015 /* update codec info */
7016 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7017 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7018 player->audiodec_linked = 1;
7020 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7024 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7026 LOGD("audio codec type: %d", codec_type);
7027 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7028 /* sw codec will be skipped */
7029 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7030 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7031 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7032 ret = GST_AUTOPLUG_SELECT_SKIP;
7036 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7037 /* hw codec will be skipped */
7038 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7039 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7040 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7041 ret = GST_AUTOPLUG_SELECT_SKIP;
7046 /* set stream information */
7047 if (!player->audiodec_linked)
7048 __mmplayer_set_audio_attrs(player, caps);
7050 /* update codec info */
7051 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7052 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7053 player->audiodec_linked = 1;
7055 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7057 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7059 LOGD("video codec type: %d", codec_type);
7060 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7061 /* sw codec is skipped */
7062 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7063 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7064 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7065 ret = GST_AUTOPLUG_SELECT_SKIP;
7069 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7070 /* hw codec is skipped */
7071 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7072 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7073 ret = GST_AUTOPLUG_SELECT_SKIP;
7078 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7079 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7081 /* mark video decoder for acquire */
7082 if (player->video_decoder_resource == NULL) {
7083 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7084 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7085 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7086 &player->video_decoder_resource)
7087 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7088 LOGE("could not mark video_decoder resource for acquire");
7089 ret = GST_AUTOPLUG_SELECT_SKIP;
7093 LOGW("video decoder resource is already acquired, skip it.");
7094 ret = GST_AUTOPLUG_SELECT_SKIP;
7098 player->interrupted_by_resource = FALSE;
7099 /* acquire resources for video playing */
7100 if (mm_resource_manager_commit(player->resource_manager)
7101 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7102 LOGE("could not acquire resources for video decoding");
7103 ret = GST_AUTOPLUG_SELECT_SKIP;
7108 /* update codec info */
7109 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7110 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7111 player->videodec_linked = 1;
7119 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7120 GstCaps *caps, GstElementFactory *factory, gpointer data)
7122 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7123 mmplayer_t *player = (mmplayer_t *)data;
7125 gchar *factory_name = NULL;
7126 gchar *caps_str = NULL;
7127 const gchar *klass = NULL;
7130 factory_name = GST_OBJECT_NAME(factory);
7131 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7132 caps_str = gst_caps_to_string(caps);
7134 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7136 /* store type string */
7137 if (player->type == NULL) {
7138 player->type = gst_caps_to_string(caps);
7139 __mmplayer_update_content_type_info(player);
7142 /* filtering exclude keyword */
7143 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7144 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7145 LOGW("skipping [%s] by exculde keyword [%s]",
7146 factory_name, player->ini.exclude_element_keyword[idx]);
7148 result = GST_AUTOPLUG_SELECT_SKIP;
7153 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7154 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7155 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7156 factory_name, player->ini.unsupported_codec_keyword[idx]);
7157 result = GST_AUTOPLUG_SELECT_SKIP;
7162 /* exclude webm format */
7163 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7164 * because webm format is not supportable.
7165 * If webm is disabled in "autoplug-continue", there is no state change
7166 * failure or error because the decodebin will expose the pad directly.
7167 * It make MSL invoke _prepare_async_callback.
7168 * So, we need to disable webm format in "autoplug-select" */
7169 if (caps_str && strstr(caps_str, "webm")) {
7170 LOGW("webm is not supported");
7171 result = GST_AUTOPLUG_SELECT_SKIP;
7175 /* check factory class for filtering */
7176 /* NOTE : msl don't need to use image plugins.
7177 * So, those plugins should be skipped for error handling.
7179 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7180 LOGD("skipping [%s] by not required", factory_name);
7181 result = GST_AUTOPLUG_SELECT_SKIP;
7185 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7186 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7187 // TO CHECK : subtitle if needed, add subparse exception.
7188 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7189 result = GST_AUTOPLUG_SELECT_SKIP;
7193 if (g_strrstr(factory_name, "mpegpsdemux")) {
7194 LOGD("skipping PS container - not support");
7195 result = GST_AUTOPLUG_SELECT_SKIP;
7199 if (g_strrstr(factory_name, "mssdemux"))
7200 player->smooth_streaming = TRUE;
7202 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7203 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7206 GstStructure *str = NULL;
7207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7209 /* don't make video because of not required */
7210 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7211 (!player->set_mode.media_packet_video_stream)) {
7212 LOGD("no need video decoding, expose pad");
7213 result = GST_AUTOPLUG_SELECT_EXPOSE;
7217 /* get w/h for omx state-tune */
7218 /* FIXME: deprecated? */
7219 str = gst_caps_get_structure(caps, 0);
7220 gst_structure_get_int(str, "width", &width);
7223 if (player->v_stream_caps) {
7224 gst_caps_unref(player->v_stream_caps);
7225 player->v_stream_caps = NULL;
7228 player->v_stream_caps = gst_caps_copy(caps);
7229 LOGD("take caps for video state tune");
7230 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7234 if (g_strrstr(klass, "Codec/Decoder")) {
7235 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7236 if (result != GST_AUTOPLUG_SELECT_TRY) {
7237 LOGW("skip add decoder");
7243 MMPLAYER_FREEIF(caps_str);
7249 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7252 //mmplayer_t *player = (mmplayer_t *)data;
7253 GstCaps *caps = NULL;
7255 LOGD("[Decodebin2] pad-removed signal");
7257 caps = gst_pad_query_caps(new_pad, NULL);
7259 LOGW("query caps is NULL");
7263 gchar *caps_str = NULL;
7264 caps_str = gst_caps_to_string(caps);
7266 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7268 MMPLAYER_FREEIF(caps_str);
7269 gst_caps_unref(caps);
7273 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7275 mmplayer_t *player = (mmplayer_t *)data;
7276 GstIterator *iter = NULL;
7277 GValue item = { 0, };
7279 gboolean done = FALSE;
7280 gboolean is_all_drained = TRUE;
7283 MMPLAYER_RETURN_IF_FAIL(player);
7285 LOGD("__mmplayer_gst_decode_drained");
7287 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7288 LOGW("Fail to get cmd lock");
7292 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7293 !__mmplayer_verify_gapless_play_path(player)) {
7294 LOGD("decoding is finished.");
7295 __mmplayer_reset_gapless_state(player);
7296 MMPLAYER_CMD_UNLOCK(player);
7300 player->gapless.reconfigure = TRUE;
7302 /* check decodebin src pads whether they received EOS or not */
7303 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7306 switch (gst_iterator_next(iter, &item)) {
7307 case GST_ITERATOR_OK:
7308 pad = g_value_get_object(&item);
7309 if (pad && !GST_PAD_IS_EOS(pad)) {
7310 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7311 is_all_drained = FALSE;
7314 g_value_reset(&item);
7316 case GST_ITERATOR_RESYNC:
7317 gst_iterator_resync(iter);
7319 case GST_ITERATOR_ERROR:
7320 case GST_ITERATOR_DONE:
7325 g_value_unset(&item);
7326 gst_iterator_free(iter);
7328 if (!is_all_drained) {
7329 LOGD("Wait util the all pads get EOS.");
7330 MMPLAYER_CMD_UNLOCK(player);
7335 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7336 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7338 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7339 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7340 __mmplayer_deactivate_old_path(player);
7341 MMPLAYER_CMD_UNLOCK(player);
7347 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7349 mmplayer_t *player = (mmplayer_t *)data;
7350 const gchar *klass = NULL;
7351 gchar *factory_name = NULL;
7353 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7354 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7356 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7358 if (__mmplayer_add_dump_buffer_probe(player, element))
7359 LOGD("add buffer probe");
7361 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7362 gchar *selected = NULL;
7363 selected = g_strdup(GST_ELEMENT_NAME(element));
7364 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7367 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7368 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7369 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7371 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7372 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7374 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7375 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7376 "max-video-width", player->adaptive_info.limit.width,
7377 "max-video-height", player->adaptive_info.limit.height, NULL);
7379 } else if (g_strrstr(klass, "Demuxer")) {
7380 //LOGD("plugged element is demuxer. take it");
7381 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7382 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7385 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7386 int surface_type = 0;
7388 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7391 // to support trust-zone only
7392 if (g_strrstr(factory_name, "asfdemux")) {
7393 LOGD("set file-location %s", player->profile.uri);
7394 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7395 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7396 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7397 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7398 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7399 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7400 (__mmplayer_is_only_mp3_type(player->type))) {
7401 LOGD("[mpegaudioparse] set streaming pull mode.");
7402 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7404 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7405 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7408 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7409 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7410 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7412 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7413 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7415 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7416 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7417 (MMPLAYER_IS_DASH_STREAMING(player))) {
7418 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7419 __mm_player_streaming_set_multiqueue(player->streamer, element);
7420 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7429 __mmplayer_release_misc(mmplayer_t *player)
7432 bool cur_mode = player->set_mode.rich_audio;
7435 MMPLAYER_RETURN_IF_FAIL(player);
7437 player->video_stream_cb = NULL;
7438 player->video_stream_cb_user_param = NULL;
7439 player->video_stream_prerolled = false;
7441 player->audio_stream_render_cb = NULL;
7442 player->audio_stream_cb_user_param = NULL;
7443 player->audio_stream_sink_sync = false;
7445 player->video_stream_changed_cb = NULL;
7446 player->video_stream_changed_cb_user_param = NULL;
7448 player->audio_stream_changed_cb = NULL;
7449 player->audio_stream_changed_cb_user_param = NULL;
7451 player->sent_bos = FALSE;
7452 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7454 player->seek_state = MMPLAYER_SEEK_NONE;
7456 player->total_bitrate = 0;
7457 player->total_maximum_bitrate = 0;
7459 player->not_found_demuxer = 0;
7461 player->last_position = 0;
7462 player->duration = 0;
7463 player->http_content_size = 0;
7464 player->not_supported_codec = MISSING_PLUGIN_NONE;
7465 player->can_support_codec = FOUND_PLUGIN_NONE;
7466 player->pending_seek.is_pending = false;
7467 player->pending_seek.pos = 0;
7468 player->msg_posted = FALSE;
7469 player->has_many_types = FALSE;
7470 player->is_subtitle_force_drop = FALSE;
7471 player->play_subtitle = FALSE;
7472 player->adjust_subtitle_pos = 0;
7473 player->has_closed_caption = FALSE;
7474 player->set_mode.media_packet_video_stream = false;
7475 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7476 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7478 player->set_mode.rich_audio = cur_mode;
7480 if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7481 LOGW("failed to remove audio device_connected_callback");
7482 player->audio_device_cb_id = 0;
7484 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7485 player->bitrate[i] = 0;
7486 player->maximum_bitrate[i] = 0;
7489 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7491 /* remove media stream cb(appsrc cb) */
7492 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7493 player->media_stream_buffer_status_cb[i] = NULL;
7494 player->media_stream_seek_data_cb[i] = NULL;
7495 player->buffer_cb_user_param[i] = NULL;
7496 player->seek_cb_user_param[i] = NULL;
7498 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7500 /* free memory related to audio effect */
7501 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7503 if (player->adaptive_info.var_list) {
7504 g_list_free_full(player->adaptive_info.var_list, g_free);
7505 player->adaptive_info.var_list = NULL;
7508 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7509 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7510 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7512 /* Reset video360 settings to their defaults in case if the pipeline is to be
7515 player->video360_metadata.is_spherical = -1;
7516 player->is_openal_plugin_used = FALSE;
7518 player->is_content_spherical = FALSE;
7519 player->is_video360_enabled = TRUE;
7520 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7521 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7522 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7523 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7524 player->video360_zoom = 1.0f;
7525 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7526 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7528 player->sound.rg_enable = false;
7530 __mmplayer_initialize_video_roi(player);
7535 __mmplayer_release_misc_post(mmplayer_t *player)
7537 char *original_uri = NULL;
7540 /* player->pipeline is already released before. */
7542 MMPLAYER_RETURN_IF_FAIL(player);
7544 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7546 /* clean found audio decoders */
7547 if (player->audio_decoders) {
7548 GList *a_dec = player->audio_decoders;
7549 for (; a_dec; a_dec = g_list_next(a_dec)) {
7550 gchar *name = a_dec->data;
7551 MMPLAYER_FREEIF(name);
7553 g_list_free(player->audio_decoders);
7554 player->audio_decoders = NULL;
7557 /* clean the uri list except original uri */
7558 if (player->uri_info.uri_list) {
7559 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7561 if (player->attrs) {
7562 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7563 LOGD("restore original uri = %s", original_uri);
7565 if (mm_attrs_commit_all(player->attrs))
7566 LOGE("failed to commit the original uri.");
7569 GList *uri_list = player->uri_info.uri_list;
7570 for (; uri_list; uri_list = g_list_next(uri_list)) {
7571 gchar *uri = uri_list->data;
7572 MMPLAYER_FREEIF(uri);
7574 g_list_free(player->uri_info.uri_list);
7575 player->uri_info.uri_list = NULL;
7578 /* clear the audio stream buffer list */
7579 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7581 /* clear the video stream bo list */
7582 __mmplayer_video_stream_destroy_bo_list(player);
7583 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7585 if (player->profile.input_mem.buf) {
7586 free(player->profile.input_mem.buf);
7587 player->profile.input_mem.buf = NULL;
7589 player->profile.input_mem.len = 0;
7590 player->profile.input_mem.offset = 0;
7592 player->uri_info.uri_idx = 0;
7597 __mmplayer_check_subtitle(mmplayer_t *player)
7599 MMHandleType attrs = 0;
7600 char *subtitle_uri = NULL;
7604 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7606 /* get subtitle attribute */
7607 attrs = MMPLAYER_GET_ATTRS(player);
7611 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7612 if (!subtitle_uri || !strlen(subtitle_uri))
7615 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7616 player->is_external_subtitle_present = TRUE;
7624 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7626 MMPLAYER_RETURN_IF_FAIL(player);
7628 if (player->eos_timer) {
7629 LOGD("cancel eos timer");
7630 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7631 player->eos_timer = 0;
7638 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7642 MMPLAYER_RETURN_IF_FAIL(player);
7643 MMPLAYER_RETURN_IF_FAIL(sink);
7645 player->sink_elements = g_list_append(player->sink_elements, sink);
7651 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7655 MMPLAYER_RETURN_IF_FAIL(player);
7656 MMPLAYER_RETURN_IF_FAIL(sink);
7658 player->sink_elements = g_list_remove(player->sink_elements, sink);
7664 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7665 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7667 mmplayer_signal_item_t *item = NULL;
7670 MMPLAYER_RETURN_IF_FAIL(player);
7672 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7673 LOGE("invalid signal type [%d]", type);
7677 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7679 LOGE("cannot connect signal [%s]", signal);
7684 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7685 player->signals[type] = g_list_append(player->signals[type], item);
7691 /* NOTE : be careful with calling this api. please refer to below glib comment
7692 * glib comment : Note that there is a bug in GObject that makes this function much
7693 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7694 * will no longer be called, but, the signal handler is not currently disconnected.
7695 * If the instance is itself being freed at the same time than this doesn't matter,
7696 * since the signal will automatically be removed, but if instance persists,
7697 * then the signal handler will leak. You should not remove the signal yourself
7698 * because in a future versions of GObject, the handler will automatically be
7701 * It's possible to work around this problem in a way that will continue to work
7702 * with future versions of GObject by checking that the signal handler is still
7703 * connected before disconnected it:
7705 * if (g_signal_handler_is_connected(instance, id))
7706 * g_signal_handler_disconnect(instance, id);
7709 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7711 GList *sig_list = NULL;
7712 mmplayer_signal_item_t *item = NULL;
7716 MMPLAYER_RETURN_IF_FAIL(player);
7718 LOGD("release signals type : %d", type);
7720 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7721 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7722 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7723 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7724 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7725 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7729 sig_list = player->signals[type];
7731 for (; sig_list; sig_list = sig_list->next) {
7732 item = sig_list->data;
7734 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7735 if (g_signal_handler_is_connected(item->obj, item->sig))
7736 g_signal_handler_disconnect(item->obj, item->sig);
7739 MMPLAYER_FREEIF(item);
7742 g_list_free(player->signals[type]);
7743 player->signals[type] = NULL;
7751 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7753 mmplayer_t *player = 0;
7754 int prev_display_surface_type = 0;
7755 void *prev_display_overlay = NULL;
7759 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7760 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7762 player = MM_PLAYER_CAST(handle);
7764 /* check video sinkbin is created */
7765 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7766 LOGE("Videosink is already created");
7767 return MM_ERROR_NONE;
7770 LOGD("videosink element is not yet ready");
7772 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7773 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7775 return MM_ERROR_INVALID_ARGUMENT;
7778 /* load previous attributes */
7779 if (player->attrs) {
7780 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7781 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7782 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7783 if (prev_display_surface_type == surface_type) {
7784 LOGD("incoming display surface type is same as previous one, do nothing..");
7786 return MM_ERROR_NONE;
7789 LOGE("failed to load attributes");
7791 return MM_ERROR_PLAYER_INTERNAL;
7794 /* videobin is not created yet, so we just set attributes related to display surface */
7795 LOGD("store display attribute for given surface type(%d)", surface_type);
7796 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7797 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7798 if (mm_attrs_commit_all(player->attrs)) {
7799 LOGE("failed to commit attribute");
7801 return MM_ERROR_PLAYER_INTERNAL;
7805 return MM_ERROR_NONE;
7808 /* Note : if silent is true, then subtitle would not be displayed. :*/
7810 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7812 mmplayer_t *player = (mmplayer_t *)hplayer;
7816 /* check player handle */
7817 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7819 player->set_mode.subtitle_off = silent;
7821 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7825 return MM_ERROR_NONE;
7829 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7831 mmplayer_gst_element_t *mainbin = NULL;
7832 mmplayer_gst_element_t *textbin = NULL;
7833 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7834 GstState current_state = GST_STATE_VOID_PENDING;
7835 GstState element_state = GST_STATE_VOID_PENDING;
7836 GstState element_pending_state = GST_STATE_VOID_PENDING;
7838 GstEvent *event = NULL;
7839 int result = MM_ERROR_NONE;
7841 GstClock *curr_clock = NULL;
7842 GstClockTime base_time, start_time, curr_time;
7847 /* check player handle */
7848 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7850 player->pipeline->mainbin &&
7851 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7853 mainbin = player->pipeline->mainbin;
7854 textbin = player->pipeline->textbin;
7856 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7858 // sync clock with current pipeline
7859 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7860 curr_time = gst_clock_get_time(curr_clock);
7862 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7863 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7865 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7866 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7868 if (current_state > GST_STATE_READY) {
7869 // sync state with current pipeline
7870 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7871 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7872 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7874 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7875 if (GST_STATE_CHANGE_FAILURE == ret) {
7876 LOGE("fail to state change.");
7877 result = MM_ERROR_PLAYER_INTERNAL;
7881 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7882 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7885 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7886 gst_object_unref(curr_clock);
7889 // seek to current position
7890 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7891 result = MM_ERROR_PLAYER_INVALID_STATE;
7892 LOGE("gst_element_query_position failed, invalid state");
7896 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7897 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);
7899 __mmplayer_gst_send_event_to_sink(player, event);
7901 result = MM_ERROR_PLAYER_INTERNAL;
7902 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7906 /* sync state with current pipeline */
7907 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7908 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7909 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7911 return MM_ERROR_NONE;
7914 /* release text pipeline resource */
7915 player->textsink_linked = 0;
7917 /* release signal */
7918 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7920 /* release textbin with it's childs */
7921 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7922 MMPLAYER_FREEIF(player->pipeline->textbin);
7923 player->pipeline->textbin = NULL;
7925 /* release subtitle elem */
7926 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7927 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7933 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7935 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7936 GstState current_state = GST_STATE_VOID_PENDING;
7938 MMHandleType attrs = 0;
7939 mmplayer_gst_element_t *mainbin = NULL;
7940 mmplayer_gst_element_t *textbin = NULL;
7942 gchar *subtitle_uri = NULL;
7943 int result = MM_ERROR_NONE;
7944 const gchar *charset = NULL;
7948 /* check player handle */
7949 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7951 player->pipeline->mainbin &&
7952 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7953 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7955 mainbin = player->pipeline->mainbin;
7956 textbin = player->pipeline->textbin;
7958 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7959 if (current_state < GST_STATE_READY) {
7960 result = MM_ERROR_PLAYER_INVALID_STATE;
7961 LOGE("Pipeline is not in proper state");
7965 attrs = MMPLAYER_GET_ATTRS(player);
7967 LOGE("cannot get content attribute");
7968 result = MM_ERROR_PLAYER_INTERNAL;
7972 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7973 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7974 LOGE("subtitle uri is not proper filepath");
7975 result = MM_ERROR_PLAYER_INVALID_URI;
7979 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7980 LOGE("failed to get storage info of subtitle path");
7981 result = MM_ERROR_PLAYER_INVALID_URI;
7985 LOGD("old subtitle file path is [%s]", subtitle_uri);
7986 LOGD("new subtitle file path is [%s]", filepath);
7988 if (!strcmp(filepath, subtitle_uri)) {
7989 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7992 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7993 if (mm_attrs_commit_all(player->attrs)) {
7994 LOGE("failed to commit.");
7999 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8000 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8001 player->subtitle_language_list = NULL;
8002 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8004 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8005 if (ret != GST_STATE_CHANGE_SUCCESS) {
8006 LOGE("failed to change state of textbin to READY");
8007 result = MM_ERROR_PLAYER_INTERNAL;
8011 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8012 if (ret != GST_STATE_CHANGE_SUCCESS) {
8013 LOGE("failed to change state of subparse to READY");
8014 result = MM_ERROR_PLAYER_INTERNAL;
8018 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8019 if (ret != GST_STATE_CHANGE_SUCCESS) {
8020 LOGE("failed to change state of filesrc to READY");
8021 result = MM_ERROR_PLAYER_INTERNAL;
8025 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8027 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8029 charset = util_get_charset(filepath);
8031 LOGD("detected charset is %s", charset);
8032 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8035 result = _mmplayer_sync_subtitle_pipeline(player);
8042 /* API to switch between external subtitles */
8044 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8046 int result = MM_ERROR_NONE;
8047 mmplayer_t *player = (mmplayer_t *)hplayer;
8052 /* check player handle */
8053 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8055 /* filepath can be null in idle state */
8057 /* check file path */
8058 if ((path = strstr(filepath, "file://")))
8059 result = util_exist_file_path(path + 7);
8061 result = util_exist_file_path(filepath);
8063 if (result != MM_ERROR_NONE) {
8064 LOGE("invalid subtitle path 0x%X", result);
8065 return result; /* file not found or permission denied */
8069 if (!player->pipeline) {
8071 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8072 if (mm_attrs_commit_all(player->attrs)) {
8073 LOGE("failed to commit"); /* subtitle path will not be created */
8074 return MM_ERROR_PLAYER_INTERNAL;
8077 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8078 /* check filepath */
8079 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8081 if (!__mmplayer_check_subtitle(player)) {
8082 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8083 if (mm_attrs_commit_all(player->attrs)) {
8084 LOGE("failed to commit");
8085 return MM_ERROR_PLAYER_INTERNAL;
8088 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8089 LOGE("fail to create text pipeline");
8090 return MM_ERROR_PLAYER_INTERNAL;
8093 result = _mmplayer_sync_subtitle_pipeline(player);
8095 result = __mmplayer_change_external_subtitle_language(player, filepath);
8098 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8099 player->is_external_subtitle_added_now = TRUE;
8101 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8102 if (!player->subtitle_language_list) {
8103 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8104 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8105 LOGW("subtitle language list is not updated yet");
8107 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8115 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8117 int result = MM_ERROR_NONE;
8118 gchar *change_pad_name = NULL;
8119 GstPad *sinkpad = NULL;
8120 mmplayer_gst_element_t *mainbin = NULL;
8121 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8122 GstCaps *caps = NULL;
8123 gint total_track_num = 0;
8127 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8128 MM_ERROR_PLAYER_NOT_INITIALIZED);
8130 LOGD("Change Track(%d) to %d", type, index);
8132 mainbin = player->pipeline->mainbin;
8134 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8135 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8136 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8137 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8139 /* Changing Video Track is not supported. */
8140 LOGE("Track Type Error");
8144 if (mainbin[elem_idx].gst == NULL) {
8145 result = MM_ERROR_PLAYER_NO_OP;
8146 LOGD("Req track doesn't exist");
8150 total_track_num = player->selector[type].total_track_num;
8151 if (total_track_num <= 0) {
8152 result = MM_ERROR_PLAYER_NO_OP;
8153 LOGD("Language list is not available");
8157 if ((index < 0) || (index >= total_track_num)) {
8158 result = MM_ERROR_INVALID_ARGUMENT;
8159 LOGD("Not a proper index : %d", index);
8163 /*To get the new pad from the selector*/
8164 change_pad_name = g_strdup_printf("sink_%u", index);
8165 if (change_pad_name == NULL) {
8166 result = MM_ERROR_PLAYER_INTERNAL;
8167 LOGD("Pad does not exists");
8171 LOGD("new active pad name: %s", change_pad_name);
8173 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8174 if (sinkpad == NULL) {
8175 LOGD("sinkpad is NULL");
8176 result = MM_ERROR_PLAYER_INTERNAL;
8180 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8181 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8183 caps = gst_pad_get_current_caps(sinkpad);
8184 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8187 gst_object_unref(sinkpad);
8189 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8190 __mmplayer_set_audio_attrs(player, caps);
8193 MMPLAYER_FREEIF(change_pad_name);
8198 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8200 int result = MM_ERROR_NONE;
8201 mmplayer_t *player = NULL;
8202 mmplayer_gst_element_t *mainbin = NULL;
8204 gint current_active_index = 0;
8206 GstState current_state = GST_STATE_VOID_PENDING;
8207 GstEvent *event = NULL;
8212 player = (mmplayer_t *)hplayer;
8213 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8215 if (!player->pipeline) {
8216 LOGE("Track %d pre setting -> %d", type, index);
8218 player->selector[type].active_pad_index = index;
8222 mainbin = player->pipeline->mainbin;
8224 current_active_index = player->selector[type].active_pad_index;
8226 /*If index is same as running index no need to change the pad*/
8227 if (current_active_index == index)
8230 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8231 result = MM_ERROR_PLAYER_INVALID_STATE;
8235 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8236 if (current_state < GST_STATE_PAUSED) {
8237 result = MM_ERROR_PLAYER_INVALID_STATE;
8238 LOGW("Pipeline not in porper state");
8242 result = __mmplayer_change_selector_pad(player, type, index);
8243 if (result != MM_ERROR_NONE) {
8244 LOGE("change selector pad error");
8248 player->selector[type].active_pad_index = index;
8250 if (current_state == GST_STATE_PLAYING) {
8251 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8252 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8253 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8255 __mmplayer_gst_send_event_to_sink(player, event);
8257 result = MM_ERROR_PLAYER_INTERNAL;
8267 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8269 mmplayer_t *player = (mmplayer_t *)hplayer;
8273 /* check player handle */
8274 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8276 *silent = player->set_mode.subtitle_off;
8278 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8282 return MM_ERROR_NONE;
8286 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8288 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8289 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8291 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8292 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8296 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8297 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8298 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8299 mmplayer_dump_t *dump_s;
8300 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8301 if (dump_s == NULL) {
8302 LOGE("malloc fail");
8306 dump_s->dump_element_file = NULL;
8307 dump_s->dump_pad = NULL;
8308 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8310 if (dump_s->dump_pad) {
8311 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8312 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]);
8313 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8314 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);
8315 /* add list for removed buffer probe and close FILE */
8316 player->dump_list = g_list_append(player->dump_list, dump_s);
8317 LOGD("%s sink pad added buffer probe for dump", factory_name);
8320 MMPLAYER_FREEIF(dump_s);
8321 LOGE("failed to get %s sink pad added", factory_name);
8328 static GstPadProbeReturn
8329 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8331 FILE *dump_data = (FILE *)u_data;
8333 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8334 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8336 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8338 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8340 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8342 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8344 return GST_PAD_PROBE_OK;
8348 __mmplayer_release_dump_list(GList *dump_list)
8350 GList *d_list = dump_list;
8355 for (; d_list; d_list = g_list_next(d_list)) {
8356 mmplayer_dump_t *dump_s = d_list->data;
8357 if (dump_s->dump_pad) {
8358 if (dump_s->probe_handle_id)
8359 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8360 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8362 if (dump_s->dump_element_file) {
8363 fclose(dump_s->dump_element_file);
8364 dump_s->dump_element_file = NULL;
8366 MMPLAYER_FREEIF(dump_s);
8368 g_list_free(dump_list);
8373 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8375 mmplayer_t *player = (mmplayer_t *)hplayer;
8379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8380 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8382 *exist = (bool)player->has_closed_caption;
8386 return MM_ERROR_NONE;
8390 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8394 // LOGD("unref internal gst buffer %p", buffer);
8395 gst_buffer_unref((GstBuffer *)buffer);
8402 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8404 mmplayer_t *player = (mmplayer_t *)hplayer;
8408 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8409 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8411 if (MMPLAYER_IS_STREAMING(player))
8412 *timeout = (int)player->ini.live_state_change_timeout;
8414 *timeout = (int)player->ini.localplayback_state_change_timeout;
8416 LOGD("timeout = %d", *timeout);
8419 return MM_ERROR_NONE;
8423 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8425 mmplayer_t *player = (mmplayer_t *)hplayer;
8429 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8430 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8432 *num = player->video_num_buffers;
8433 *extra_num = player->video_extra_num_buffers;
8435 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8438 return MM_ERROR_NONE;
8442 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8446 MMPLAYER_RETURN_IF_FAIL(player);
8448 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8450 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8451 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8452 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8453 player->storage_info[i].id = -1;
8454 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8456 if (path_type != MMPLAYER_PATH_MAX)
8465 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8467 int ret = MM_ERROR_NONE;
8468 mmplayer_t *player = (mmplayer_t *)hplayer;
8469 MMMessageParamType msg_param = {0, };
8472 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474 LOGW("state changed storage %d:%d", id, state);
8476 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8477 return MM_ERROR_NONE;
8479 /* FIXME: text path should be handled seperately. */
8480 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8481 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8482 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8483 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8484 LOGW("external storage is removed");
8486 if (player->msg_posted == FALSE) {
8487 memset(&msg_param, 0, sizeof(MMMessageParamType));
8488 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8489 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8490 player->msg_posted = TRUE;
8493 /* unrealize the player */
8494 ret = _mmplayer_unrealize(hplayer);
8495 if (ret != MM_ERROR_NONE)
8496 LOGE("failed to unrealize");
8504 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8506 int ret = MM_ERROR_NONE;
8507 mmplayer_t *player = (mmplayer_t *)hplayer;
8508 int idx = 0, total = 0;
8509 gchar *result = NULL, *tmp = NULL;
8512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8513 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8515 total = *num = g_list_length(player->adaptive_info.var_list);
8517 LOGW("There is no stream variant info.");
8521 result = g_strdup("");
8522 for (idx = 0 ; idx < total ; idx++) {
8523 stream_variant_t *v_data = NULL;
8524 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8527 gchar data[64] = {0};
8528 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8530 tmp = g_strconcat(result, data, NULL);
8534 LOGW("There is no variant data in %d", idx);
8539 *var_info = (char *)result;
8541 LOGD("variant info %d:%s", *num, *var_info);
8547 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8549 int ret = MM_ERROR_NONE;
8550 mmplayer_t *player = (mmplayer_t *)hplayer;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8555 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8557 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8558 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8559 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8561 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8562 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8563 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8564 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8566 /* FIXME: seek to current position for applying new variant limitation */
8575 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8577 int ret = MM_ERROR_NONE;
8578 mmplayer_t *player = (mmplayer_t *)hplayer;
8581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8582 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8584 *bandwidth = player->adaptive_info.limit.bandwidth;
8585 *width = player->adaptive_info.limit.width;
8586 *height = player->adaptive_info.limit.height;
8588 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8595 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8597 int ret = MM_ERROR_NONE;
8598 mmplayer_t *player = (mmplayer_t *)hplayer;
8601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8602 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8603 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8605 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8607 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8608 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8609 else /* live case */
8610 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8612 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8619 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8621 #define IDX_FIRST_SW_CODEC 0
8622 mmplayer_t *player = (mmplayer_t *)hplayer;
8623 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8624 MMHandleType attrs = 0;
8627 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8629 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8630 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8631 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8633 switch (stream_type) {
8634 case MM_PLAYER_STREAM_TYPE_AUDIO:
8635 /* to support audio codec selection, codec info have to be added in ini file as below.
8636 audio codec element hw = xxxx
8637 audio codec element sw = avdec */
8638 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8639 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8640 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8641 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8642 LOGE("There is no audio codec info for codec_type %d", codec_type);
8643 return MM_ERROR_PLAYER_NO_OP;
8646 case MM_PLAYER_STREAM_TYPE_VIDEO:
8647 /* to support video codec selection, codec info have to be added in ini file as below.
8648 video codec element hw = omx
8649 video codec element sw = avdec */
8650 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8651 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8652 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8653 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8654 LOGE("There is no video codec info for codec_type %d", codec_type);
8655 return MM_ERROR_PLAYER_NO_OP;
8659 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8660 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8664 LOGD("update %s codec_type to %d", attr_name, codec_type);
8666 attrs = MMPLAYER_GET_ATTRS(player);
8667 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8669 if (mm_attrs_commit_all(player->attrs)) {
8670 LOGE("failed to commit codec_type attributes");
8671 return MM_ERROR_PLAYER_INTERNAL;
8675 return MM_ERROR_NONE;
8679 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8681 mmplayer_t *player = (mmplayer_t *)hplayer;
8682 GstElement *rg_vol_element = NULL;
8686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8688 player->sound.rg_enable = enabled;
8690 /* just hold rgvolume enable value if pipeline is not ready */
8691 if (!player->pipeline || !player->pipeline->audiobin) {
8692 LOGD("pipeline is not ready. holding rgvolume enable value");
8693 return MM_ERROR_NONE;
8696 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8698 if (!rg_vol_element) {
8699 LOGD("rgvolume element is not created");
8700 return MM_ERROR_PLAYER_INTERNAL;
8704 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8706 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8710 return MM_ERROR_NONE;
8714 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8716 mmplayer_t *player = (mmplayer_t *)hplayer;
8717 GstElement *rg_vol_element = NULL;
8718 gboolean enable = FALSE;
8722 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8723 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8725 /* just hold enable_rg value if pipeline is not ready */
8726 if (!player->pipeline || !player->pipeline->audiobin) {
8727 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8728 *enabled = player->sound.rg_enable;
8729 return MM_ERROR_NONE;
8732 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8734 if (!rg_vol_element) {
8735 LOGD("rgvolume element is not created");
8736 return MM_ERROR_PLAYER_INTERNAL;
8739 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8740 *enabled = (bool)enable;
8744 return MM_ERROR_NONE;
8748 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8750 mmplayer_t *player = (mmplayer_t *)hplayer;
8751 MMHandleType attrs = 0;
8752 void *handle = NULL;
8753 int ret = MM_ERROR_NONE;
8757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8759 attrs = MMPLAYER_GET_ATTRS(player);
8760 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8762 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8764 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8765 return MM_ERROR_PLAYER_INTERNAL;
8768 player->video_roi.scale_x = scale_x;
8769 player->video_roi.scale_y = scale_y;
8770 player->video_roi.scale_width = scale_width;
8771 player->video_roi.scale_height = scale_height;
8773 /* check video sinkbin is created */
8774 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8775 return MM_ERROR_NONE;
8777 if (!gst_video_overlay_set_video_roi_area(
8778 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8779 scale_x, scale_y, scale_width, scale_height))
8780 ret = MM_ERROR_PLAYER_INTERNAL;
8782 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8783 scale_x, scale_y, scale_width, scale_height);
8791 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8793 mmplayer_t *player = (mmplayer_t *)hplayer;
8794 int ret = MM_ERROR_NONE;
8798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8799 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8801 *scale_x = player->video_roi.scale_x;
8802 *scale_y = player->video_roi.scale_y;
8803 *scale_width = player->video_roi.scale_width;
8804 *scale_height = player->video_roi.scale_height;
8806 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8807 *scale_x, *scale_y, *scale_width, *scale_height);
8813 __mmplayer_update_duration_value(mmplayer_t *player)
8815 gboolean ret = FALSE;
8816 gint64 dur_nsec = 0;
8817 LOGD("try to update duration");
8819 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8820 player->duration = dur_nsec;
8821 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8825 if (player->duration < 0) {
8826 LOGW("duration is Non-Initialized !!!");
8827 player->duration = 0;
8830 /* update streaming service type */
8831 player->streaming_type = __mmplayer_get_stream_service_type(player);
8833 /* check duration is OK */
8834 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8835 /* FIXIT : find another way to get duration here. */
8836 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8842 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8844 /* update audio params
8845 NOTE : We need original audio params and it can be only obtained from src pad of audio
8846 decoder. Below code only valid when we are not using 'resampler' just before
8847 'audioconverter'. */
8848 GstCaps *caps_a = NULL;
8850 gint samplerate = 0, channels = 0;
8851 GstStructure *p = NULL;
8853 LOGD("try to update audio attrs");
8855 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8856 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8858 pad = gst_element_get_static_pad(
8859 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8862 LOGW("failed to get pad from audiosink");
8866 caps_a = gst_pad_get_current_caps(pad);
8868 LOGW("not ready to get audio caps");
8869 gst_object_unref(pad);
8873 p = gst_caps_get_structure(caps_a, 0);
8875 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8877 gst_structure_get_int(p, "rate", &samplerate);
8878 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8880 gst_structure_get_int(p, "channels", &channels);
8881 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8883 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8885 gst_caps_unref(caps_a);
8886 gst_object_unref(pad);
8892 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8894 LOGD("try to update video attrs");
8896 GstCaps *caps_v = NULL;
8900 GstStructure *p = NULL;
8902 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8903 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8905 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8907 LOGD("no videosink sink pad");
8911 caps_v = gst_pad_get_current_caps(pad);
8912 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8913 if (!caps_v && player->v_stream_caps) {
8914 caps_v = player->v_stream_caps;
8915 gst_caps_ref(caps_v);
8919 LOGD("no negitiated caps from videosink");
8920 gst_object_unref(pad);
8924 p = gst_caps_get_structure(caps_v, 0);
8925 gst_structure_get_int(p, "width", &width);
8926 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8928 gst_structure_get_int(p, "height", &height);
8929 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8931 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8933 SECURE_LOGD("width : %d height : %d", width, height);
8935 gst_caps_unref(caps_v);
8936 gst_object_unref(pad);
8939 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8940 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8947 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8949 gboolean ret = FALSE;
8950 guint64 data_size = 0;
8954 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8955 if (!player->duration)
8958 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8959 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8960 if (stat(path, &sb) == 0)
8961 data_size = (guint64)sb.st_size;
8963 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8964 data_size = player->http_content_size;
8967 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8970 guint64 bitrate = 0;
8971 guint64 msec_dur = 0;
8973 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8975 bitrate = data_size * 8 * 1000 / msec_dur;
8976 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8977 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8981 LOGD("player duration is less than 0");
8985 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8986 if (player->total_bitrate) {
8987 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8996 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8998 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8999 data->uri_type = uri_type;
9003 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9005 int ret = MM_ERROR_PLAYER_INVALID_URI;
9007 char *buffer = NULL;
9008 char *seperator = strchr(path, ',');
9009 char ext[100] = {0,}, size[100] = {0,};
9012 if ((buffer = strstr(path, "ext="))) {
9013 buffer += strlen("ext=");
9015 if (strlen(buffer)) {
9016 strncpy(ext, buffer, 99);
9018 if ((seperator = strchr(ext, ','))
9019 || (seperator = strchr(ext, ' '))
9020 || (seperator = strchr(ext, '\0'))) {
9021 seperator[0] = '\0';
9026 if ((buffer = strstr(path, "size="))) {
9027 buffer += strlen("size=");
9029 if (strlen(buffer) > 0) {
9030 strncpy(size, buffer, 99);
9032 if ((seperator = strchr(size, ','))
9033 || (seperator = strchr(size, ' '))
9034 || (seperator = strchr(size, '\0'))) {
9035 seperator[0] = '\0';
9038 mem_size = atoi(size);
9043 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9045 if (mem_size && param) {
9046 if (data->input_mem.buf)
9047 free(data->input_mem.buf);
9048 data->input_mem.buf = malloc(mem_size);
9050 if (data->input_mem.buf) {
9051 memcpy(data->input_mem.buf, param, mem_size);
9052 data->input_mem.len = mem_size;
9053 ret = MM_ERROR_NONE;
9055 LOGE("failed to alloc mem %d", mem_size);
9056 ret = MM_ERROR_PLAYER_INTERNAL;
9059 data->input_mem.offset = 0;
9060 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9067 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9069 gchar *location = NULL;
9072 int ret = MM_ERROR_NONE;
9074 if ((path = strstr(uri, "file://"))) {
9075 location = g_filename_from_uri(uri, NULL, &err);
9076 if (!location || (err != NULL)) {
9077 LOGE("Invalid URI '%s' for filesrc: %s", path,
9078 (err != NULL) ? err->message : "unknown error");
9082 MMPLAYER_FREEIF(location);
9084 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9085 return MM_ERROR_PLAYER_INVALID_URI;
9087 LOGD("path from uri: %s", location);
9090 path = (location != NULL) ? (location) : ((char *)uri);
9093 ret = util_exist_file_path(path);
9095 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9096 if (ret == MM_ERROR_NONE) {
9097 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9098 if (util_is_sdp_file(path)) {
9099 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9100 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9102 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9104 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9105 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9107 LOGE("invalid uri, could not play..");
9108 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9111 MMPLAYER_FREEIF(location);
9116 static mmplayer_video_decoded_data_info_t *
9117 __mmplayer_create_stream_from_pad(GstPad *pad)
9119 GstCaps *caps = NULL;
9120 GstStructure *structure = NULL;
9121 unsigned int fourcc = 0;
9122 const gchar *string_format = NULL;
9123 mmplayer_video_decoded_data_info_t *stream = NULL;
9125 MMPixelFormatType format;
9127 caps = gst_pad_get_current_caps(pad);
9129 LOGE("Caps is NULL.");
9133 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9134 structure = gst_caps_get_structure(caps, 0);
9135 gst_structure_get_int(structure, "width", &width);
9136 gst_structure_get_int(structure, "height", &height);
9137 string_format = gst_structure_get_string(structure, "format");
9139 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9140 format = util_get_pixtype(fourcc);
9141 gst_caps_unref(caps);
9144 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9145 LOGE("Wrong condition!!");
9149 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9151 LOGE("failed to alloc mem for video data");
9155 stream->width = width;
9156 stream->height = height;
9157 stream->format = format;
9163 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9165 unsigned int pitch = 0;
9167 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9169 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9170 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9171 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9172 stream->stride[index] = pitch;
9173 stream->elevation[index] = stream->height;
9178 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9180 if (stream->format == MM_PIXEL_FORMAT_I420) {
9181 int ret = TBM_SURFACE_ERROR_NONE;
9182 tbm_surface_h surface;
9183 tbm_surface_info_s info;
9185 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9187 ret = tbm_surface_get_info(surface, &info);
9188 if (ret != TBM_SURFACE_ERROR_NONE) {
9189 tbm_surface_destroy(surface);
9193 tbm_surface_destroy(surface);
9194 stream->stride[0] = info.planes[0].stride;
9195 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9196 stream->stride[1] = info.planes[1].stride;
9197 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9198 stream->stride[2] = info.planes[2].stride;
9199 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9200 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9201 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9202 stream->stride[0] = stream->width * 4;
9203 stream->elevation[0] = stream->height;
9204 stream->bo_size = stream->stride[0] * stream->height;
9206 LOGE("Not support format %d", stream->format);
9214 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9216 tbm_bo_handle thandle;
9218 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9219 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9220 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9224 unsigned char *src = NULL;
9225 unsigned char *dest = NULL;
9226 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9228 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9230 LOGE("fail to gst_memory_map");
9234 if (!mapinfo.data) {
9235 LOGE("data pointer is wrong");
9239 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9240 if (!stream->bo[0]) {
9241 LOGE("Fail to tbm_bo_alloc!!");
9245 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9247 LOGE("thandle pointer is wrong");
9251 if (stream->format == MM_PIXEL_FORMAT_I420) {
9252 src_stride[0] = GST_ROUND_UP_4(stream->width);
9253 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9254 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9255 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9258 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9259 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9261 for (i = 0; i < 3; i++) {
9262 src = mapinfo.data + src_offset[i];
9263 dest = thandle.ptr + dest_offset[i];
9268 for (j = 0; j < stream->height >> k; j++) {
9269 memcpy(dest, src, stream->width>>k);
9270 src += src_stride[i];
9271 dest += stream->stride[i];
9274 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9275 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9277 LOGE("Not support format %d", stream->format);
9281 tbm_bo_unmap(stream->bo[0]);
9282 gst_memory_unmap(mem, &mapinfo);
9288 tbm_bo_unmap(stream->bo[0]);
9291 gst_memory_unmap(mem, &mapinfo);
9297 __mmplayer_set_pause_state(mmplayer_t *player)
9299 if (player->sent_bos)
9302 /* rtsp case, get content attrs by GstMessage */
9303 if (MMPLAYER_IS_RTSP_STREAMING(player))
9306 /* it's first time to update all content attrs. */
9307 __mmplayer_update_content_attrs(player, ATTR_ALL);
9311 __mmplayer_set_playing_state(mmplayer_t *player)
9313 gchar *audio_codec = NULL;
9315 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9316 /* initialize because auto resume is done well. */
9317 player->resumed_by_rewind = FALSE;
9318 player->playback_rate = 1.0;
9321 if (player->sent_bos)
9324 /* try to get content metadata */
9326 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9327 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9328 * legacy mmfw-player api
9330 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9332 if ((player->cmd == MMPLAYER_COMMAND_START)
9333 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9334 __mmplayer_handle_missed_plugin(player);
9337 /* check audio codec field is set or not
9338 * we can get it from typefinder or codec's caps.
9340 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9342 /* The codec format can't be sent for audio only case like amr, mid etc.
9343 * Because, parser don't make related TAG.
9344 * So, if it's not set yet, fill it with found data.
9347 if (g_strrstr(player->type, "audio/midi"))
9348 audio_codec = "MIDI";
9349 else if (g_strrstr(player->type, "audio/x-amr"))
9350 audio_codec = "AMR";
9351 else if (g_strrstr(player->type, "audio/mpeg")
9352 && !g_strrstr(player->type, "mpegversion=(int)1"))
9353 audio_codec = "AAC";
9355 audio_codec = "unknown";
9357 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9359 if (mm_attrs_commit_all(player->attrs))
9360 LOGE("failed to update attributes");
9362 LOGD("set audio codec type with caps");