4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | GLOBAL VARIABLE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
118 /*---------------------------------------------------------------------------
119 | LOCAL VARIABLE DEFINITIONS: |
120 ---------------------------------------------------------------------------*/
121 static sound_stream_info_h stream_info;
123 /*---------------------------------------------------------------------------
124 | LOCAL FUNCTION PROTOTYPES: |
125 ---------------------------------------------------------------------------*/
126 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
127 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
128 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
129 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
130 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
131 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
133 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
134 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
135 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
136 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
137 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
138 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
139 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
140 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
141 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
142 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
143 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
145 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
146 static void __mmplayer_release_misc(mm_player_t *player);
147 static void __mmplayer_release_misc_post(mm_player_t *player);
148 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
149 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
150 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
152 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
154 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
155 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
156 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
157 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
158 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
159 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
160 static gpointer __mmplayer_gapless_play_thread(gpointer data);
161 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
162 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static void __mmplayer_release_dump_list(GList *dump_list);
164 static int __mmplayer_gst_realize(mm_player_t *player);
165 static int __mmplayer_gst_unrealize(mm_player_t *player);
166 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
167 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
170 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
171 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
172 static void __mmplayer_check_pipeline(mm_player_t *player);
173 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
174 static void __mmplayer_deactivate_old_path(mm_player_t *player);
175 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
176 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
177 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
178 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
179 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
180 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
181 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
182 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
183 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
186 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
187 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
188 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
190 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
191 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
192 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
193 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
195 static void __mmplayer_set_pause_state(mm_player_t *player);
196 static void __mmplayer_set_playing_state(mm_player_t *player);
197 /*===========================================================================================
199 | FUNCTION DEFINITIONS |
201 ========================================================================================== */
205 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
209 count = gst_tag_list_get_tag_size(list, tag);
211 LOGD("count = %d", count);
213 for (i = 0; i < count; i++) {
216 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
217 if (!gst_tag_list_get_string_index(list, tag, i, &str))
218 g_assert_not_reached();
220 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
224 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
226 g_print(" : %s", str);
233 /* This function should be called after the pipeline goes PAUSED or higher
236 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
238 static gboolean has_duration = FALSE;
239 static gboolean has_video_attrs = FALSE;
240 static gboolean has_audio_attrs = FALSE;
241 static gboolean has_bitrate = FALSE;
242 gboolean missing_only = FALSE;
243 gboolean all = FALSE;
244 MMHandleType attrs = 0;
248 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
250 /* check player state here */
251 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
252 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
253 /* give warning now only */
254 LOGW("be careful. content attributes may not available in this state ");
257 /* get content attribute first */
258 attrs = MMPLAYER_GET_ATTRS(player);
260 LOGE("cannot get content attribute");
264 /* get update flag */
266 if (flag & ATTR_MISSING_ONLY) {
268 LOGD("updating missed attr only");
271 if (flag & ATTR_ALL) {
273 has_duration = FALSE;
274 has_video_attrs = FALSE;
275 has_audio_attrs = FALSE;
278 LOGD("updating all attrs");
281 if (missing_only && all) {
282 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
283 missing_only = FALSE;
286 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
287 has_duration = __mmplayer_update_duration_value(player);
289 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
290 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
292 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
293 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
295 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
296 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
299 if (mm_attrs_commit_all(attrs)) {
300 LOGE("failed to update attributes");
310 __mmplayer_get_stream_service_type(mm_player_t *player)
312 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
316 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
318 player->pipeline->mainbin &&
319 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
320 STREAMING_SERVICE_NONE);
322 /* streaming service type if streaming */
323 if (!MMPLAYER_IS_STREAMING(player))
324 return STREAMING_SERVICE_NONE;
326 streaming_type = (player->duration == 0) ?
327 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
329 switch (streaming_type) {
330 case STREAMING_SERVICE_LIVE:
331 LOGD("it's live streaming");
333 case STREAMING_SERVICE_VOD:
334 LOGD("it's vod streaming");
337 LOGE("should not get here");
343 return streaming_type;
346 /* this function sets the player state and also report
347 * it to applicaton by calling callback function
350 __mmplayer_set_state(mm_player_t *player, int state)
352 MMMessageParamType msg = {0, };
354 MMPLAYER_RETURN_IF_FAIL(player);
356 if (MMPLAYER_CURRENT_STATE(player) == state) {
357 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
358 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
362 /* update player states */
363 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
364 MMPLAYER_CURRENT_STATE(player) = state;
366 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
370 MMPLAYER_PRINT_STATE(player);
372 switch (MMPLAYER_CURRENT_STATE(player)) {
373 case MM_PLAYER_STATE_NULL:
374 case MM_PLAYER_STATE_READY:
376 case MM_PLAYER_STATE_PAUSED:
377 __mmplayer_set_pause_state(player);
379 case MM_PLAYER_STATE_PLAYING:
380 __mmplayer_set_playing_state(player);
382 case MM_PLAYER_STATE_NONE:
384 LOGW("invalid target state, there is nothing to do.");
389 /* post message to application */
390 if (MMPLAYER_TARGET_STATE(player) == state) {
391 /* fill the message with state of player */
392 msg.union_type = MM_MSG_UNION_STATE;
393 msg.state.previous = MMPLAYER_PREV_STATE(player);
394 msg.state.current = MMPLAYER_CURRENT_STATE(player);
396 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
398 /* state changed by resource callback */
399 if (player->interrupted_by_resource)
400 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
401 else /* state changed by usecase */
402 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
405 LOGD("intermediate state, do nothing.");
406 MMPLAYER_PRINT_STATE(player);
410 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
411 && !player->sent_bos) {
412 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
413 player->sent_bos = TRUE;
420 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
422 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
423 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
425 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
427 //LOGD("incomming command : %d ", command);
429 current_state = MMPLAYER_CURRENT_STATE(player);
430 pending_state = MMPLAYER_PENDING_STATE(player);
432 MMPLAYER_PRINT_STATE(player);
435 case MMPLAYER_COMMAND_CREATE:
437 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
439 if (current_state == MM_PLAYER_STATE_NULL ||
440 current_state == MM_PLAYER_STATE_READY ||
441 current_state == MM_PLAYER_STATE_PAUSED ||
442 current_state == MM_PLAYER_STATE_PLAYING)
447 case MMPLAYER_COMMAND_DESTROY:
449 /* destroy can called anytime */
451 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
455 case MMPLAYER_COMMAND_REALIZE:
457 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
459 if (pending_state != MM_PLAYER_STATE_NONE) {
462 /* need ready state to realize */
463 if (current_state == MM_PLAYER_STATE_READY)
466 if (current_state != MM_PLAYER_STATE_NULL)
472 case MMPLAYER_COMMAND_UNREALIZE:
474 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
476 if (current_state == MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_START:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
485 if (pending_state == MM_PLAYER_STATE_NONE) {
486 if (current_state == MM_PLAYER_STATE_PLAYING)
488 else if (current_state != MM_PLAYER_STATE_READY &&
489 current_state != MM_PLAYER_STATE_PAUSED)
491 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
493 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
494 LOGD("player is going to paused state, just change the pending state as playing");
501 case MMPLAYER_COMMAND_STOP:
503 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
505 if (current_state == MM_PLAYER_STATE_READY)
508 /* need playing/paused state to stop */
509 if (current_state != MM_PLAYER_STATE_PLAYING &&
510 current_state != MM_PLAYER_STATE_PAUSED)
515 case MMPLAYER_COMMAND_PAUSE:
517 if (MMPLAYER_IS_LIVE_STREAMING(player))
520 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
521 goto NOT_COMPLETED_SEEK;
523 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
525 if (pending_state == MM_PLAYER_STATE_NONE) {
526 if (current_state == MM_PLAYER_STATE_PAUSED)
528 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
530 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
532 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
534 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
541 case MMPLAYER_COMMAND_RESUME:
543 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
544 goto NOT_COMPLETED_SEEK;
546 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
548 if (pending_state == MM_PLAYER_STATE_NONE) {
549 if (current_state == MM_PLAYER_STATE_PLAYING)
551 else if (current_state != MM_PLAYER_STATE_PAUSED)
553 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
555 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
556 LOGD("player is going to paused state, just change the pending state as playing");
566 player->cmd = command;
568 return MM_ERROR_NONE;
571 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
572 MMPLAYER_STATE_GET_NAME(current_state), command);
573 return MM_ERROR_PLAYER_INVALID_STATE;
576 LOGW("not completed seek");
577 return MM_ERROR_PLAYER_DOING_SEEK;
580 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
581 return MM_ERROR_PLAYER_NO_OP;
584 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
585 return MM_ERROR_PLAYER_NO_OP;
589 __mmplayer_gapless_play_thread(gpointer data)
591 mm_player_t *player = (mm_player_t *)data;
592 MMPlayerGstElement *mainbin = NULL;
594 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
596 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
597 while (!player->gapless_play_thread_exit) {
598 LOGD("gapless play thread started. waiting for signal.");
599 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
601 LOGD("reconfigure pipeline for gapless play.");
603 if (player->gapless_play_thread_exit) {
604 if (player->gapless.reconfigure) {
605 player->gapless.reconfigure = false;
606 MMPLAYER_PLAYBACK_UNLOCK(player);
608 LOGD("exiting gapless play thread");
612 mainbin = player->pipeline->mainbin;
614 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
615 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
616 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
617 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
618 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
620 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
622 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
628 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
630 GSource *source = NULL;
634 source = g_main_context_find_source_by_id(context, source_id);
635 if (source != NULL) {
636 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
637 g_source_destroy(source);
644 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
646 mm_player_t *player = (mm_player_t *)hplayer;
647 GstMessage *msg = NULL;
648 GQueue *queue = NULL;
651 MMPLAYER_RETURN_IF_FAIL(player);
653 /* disconnecting bus watch */
654 if (player->bus_watcher)
655 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
656 player->bus_watcher = 0;
658 /* destroy the gst bus msg thread */
659 if (player->bus_msg_thread) {
660 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
661 player->bus_msg_thread_exit = TRUE;
662 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
663 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
665 LOGD("gst bus msg thread exit.");
666 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
667 player->bus_msg_thread = NULL;
669 g_mutex_clear(&player->bus_msg_thread_mutex);
670 g_cond_clear(&player->bus_msg_thread_cond);
673 g_mutex_lock(&player->bus_msg_q_lock);
674 queue = player->bus_msg_q;
675 while (!g_queue_is_empty(queue)) {
676 msg = (GstMessage *)g_queue_pop_head(queue);
681 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
682 gst_message_unref(msg);
684 g_mutex_unlock(&player->bus_msg_q_lock);
690 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
692 GstElement *parent = NULL;
694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
696 /* if we have no fakesink. this meas we are using decodebin which doesn'
697 t need to add extra fakesink */
698 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
701 MMPLAYER_FSINK_LOCK(player);
706 /* get parent of fakesink */
707 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
709 LOGD("fakesink already removed");
713 gst_element_set_locked_state(fakesink->gst, TRUE);
715 /* setting the state to NULL never returns async
716 * so no need to wait for completion of state transiton
718 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
719 LOGE("fakesink state change failure!");
720 /* FIXIT : should I return here? or try to proceed to next? */
723 /* remove fakesink from it's parent */
724 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
725 LOGE("failed to remove fakesink");
727 gst_object_unref(parent);
732 gst_object_unref(parent);
734 LOGD("state-holder removed");
736 gst_element_set_locked_state(fakesink->gst, FALSE);
738 MMPLAYER_FSINK_UNLOCK(player);
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
749 static GstPadProbeReturn
750 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
752 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
753 return GST_PAD_PROBE_OK;
757 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
759 gint64 stop_running_time = 0;
760 gint64 position_running_time = 0;
764 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
765 if ((player->gapless.update_segment[idx] == TRUE) ||
766 !(player->selector[idx].event_probe_id)) {
767 /* LOGW("[%d] skip", idx); */
771 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
773 gst_segment_to_running_time(&player->gapless.segment[idx],
774 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
775 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
777 gst_segment_to_running_time(&player->gapless.segment[idx],
778 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
780 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
782 gst_segment_to_running_time(&player->gapless.segment[idx],
783 GST_FORMAT_TIME, player->duration);
786 position_running_time =
787 gst_segment_to_running_time(&player->gapless.segment[idx],
788 GST_FORMAT_TIME, player->gapless.segment[idx].position);
790 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
791 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
793 GST_TIME_ARGS(stop_running_time),
794 GST_TIME_ARGS(position_running_time),
795 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
796 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
798 position_running_time = MAX(position_running_time, stop_running_time);
799 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
800 GST_FORMAT_TIME, player->gapless.segment[idx].start);
801 position_running_time = MAX(0, position_running_time);
802 position = MAX(position, position_running_time);
806 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
807 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
808 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
810 player->gapless.start_time[stream_type] += position;
816 static GstPadProbeReturn
817 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
819 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
820 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
821 mm_player_t *player = (mm_player_t *)data;
822 GstCaps *caps = NULL;
823 GstStructure *str = NULL;
824 const gchar *name = NULL;
825 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
826 gboolean caps_ret = TRUE;
828 if (GST_EVENT_IS_DOWNSTREAM(event) &&
829 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
830 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
831 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
832 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
834 } else if (GST_EVENT_IS_UPSTREAM(event) &&
835 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
839 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
843 if (strstr(name, "audio")) {
844 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
845 } else if (strstr(name, "video")) {
846 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
848 /* text track is not supportable */
849 LOGE("invalid name %s", name);
853 switch (GST_EVENT_TYPE(event)) {
856 /* in case of gapless, drop eos event not to send it to sink */
857 if (player->gapless.reconfigure && !player->msg_posted) {
858 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
859 ret = GST_PAD_PROBE_DROP;
863 case GST_EVENT_STREAM_START:
865 __mmplayer_gst_selector_update_start_time(player, stream_type);
868 case GST_EVENT_FLUSH_STOP:
870 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
871 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
872 player->gapless.start_time[stream_type] = 0;
875 case GST_EVENT_SEGMENT:
880 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
881 gst_event_copy_segment(event, &segment);
883 if (segment.format != GST_FORMAT_TIME)
886 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
887 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
888 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
889 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
890 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
891 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
893 /* keep the all the segment ev to cover the seeking */
894 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
895 player->gapless.update_segment[stream_type] = TRUE;
897 if (!player->gapless.running)
900 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
902 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
904 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
905 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
906 gst_event_unref(event);
907 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
913 gdouble proportion = 0.0;
914 GstClockTimeDiff diff = 0;
915 GstClockTime timestamp = 0;
916 gint64 running_time_diff = -1;
918 GstEvent *tmpev = NULL;
920 running_time_diff = player->gapless.segment[stream_type].base;
922 if (running_time_diff <= 0) /* don't need to adjust */
925 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
926 gst_event_unref(event);
928 if (timestamp < running_time_diff) {
929 LOGW("QOS event from previous group");
930 ret = GST_PAD_PROBE_DROP;
934 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
935 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
936 stream_type, GST_TIME_ARGS(timestamp),
937 GST_TIME_ARGS(running_time_diff),
938 GST_TIME_ARGS(timestamp - running_time_diff));
940 timestamp -= running_time_diff;
942 /* That case is invalid for QoS events */
943 if (diff < 0 && -diff > timestamp) {
944 LOGW("QOS event from previous group");
945 ret = GST_PAD_PROBE_DROP;
949 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
950 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
960 gst_caps_unref(caps);
964 /* create fakesink for audio or video path witout audiobin or videobin */
966 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
968 GstElement *pipeline = NULL;
969 GstElement *fakesink = NULL;
970 GstPad *sinkpad = NULL;
973 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
975 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
978 fakesink = gst_element_factory_make("fakesink", NULL);
979 if (fakesink == NULL) {
980 LOGE("failed to create fakesink");
984 /* store it as it's sink element */
985 __mmplayer_add_sink(player, fakesink);
987 gst_bin_add(GST_BIN(pipeline), fakesink);
990 sinkpad = gst_element_get_static_pad(fakesink, "sink");
992 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
994 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
995 LOGE("failed to link fakesink");
996 gst_object_unref(GST_OBJECT(fakesink));
1000 if (strstr(name, "video")) {
1001 if (player->v_stream_caps) {
1002 gst_caps_unref(player->v_stream_caps);
1003 player->v_stream_caps = NULL;
1005 if (player->ini.set_dump_element_flag)
1006 __mmplayer_add_dump_buffer_probe(player, fakesink);
1009 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1010 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1014 gst_object_unref(GST_OBJECT(sinkpad));
1021 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1023 GstElement *pipeline = NULL;
1024 GstElement *selector = NULL;
1025 GstPad *srcpad = NULL;
1028 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1030 selector = gst_element_factory_make("input-selector", NULL);
1032 LOGE("failed to create input-selector");
1035 g_object_set(selector, "sync-streams", TRUE, NULL);
1037 player->pipeline->mainbin[elem_idx].id = elem_idx;
1038 player->pipeline->mainbin[elem_idx].gst = selector;
1040 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1042 srcpad = gst_element_get_static_pad(selector, "src");
1044 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1045 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1046 __mmplayer_gst_selector_blocked, NULL, NULL);
1047 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1048 __mmplayer_gst_selector_event_probe, player, NULL);
1050 gst_element_set_state(selector, GST_STATE_PAUSED);
1052 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1053 gst_bin_add(GST_BIN(pipeline), selector);
1060 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1062 mm_player_t *player = (mm_player_t *)data;
1063 GstElement *selector = NULL;
1064 GstCaps *caps = NULL;
1065 GstStructure *str = NULL;
1066 const gchar *name = NULL;
1067 GstPad *sinkpad = NULL;
1068 gboolean first_track = FALSE;
1069 gboolean caps_ret = TRUE;
1071 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1072 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1075 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 LOGD("pad-added signal handling");
1080 /* get mimetype from caps */
1081 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1085 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1086 /* LOGD("detected mimetype : %s", name); */
1088 if (strstr(name, "video")) {
1090 gchar *caps_str = NULL;
1092 caps_str = gst_caps_to_string(caps);
1093 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1094 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1095 player->set_mode.video_zc = true;
1097 MMPLAYER_FREEIF(caps_str);
1099 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1100 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1102 LOGD("surface type : %d", stype);
1104 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1105 __mmplayer_gst_create_sinkbin(elem, pad, player);
1109 /* in case of exporting video frame, it requires the 360 video filter.
1110 * it will be handled in _no_more_pads(). */
1111 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1112 __mmplayer_gst_make_fakesink(player, pad, name);
1116 LOGD("video selector is required");
1117 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1118 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1119 } else if (strstr(name, "audio")) {
1120 gint samplerate = 0;
1123 gst_structure_get_int(str, "rate", &samplerate);
1124 gst_structure_get_int(str, "channels", &channels);
1126 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1127 __mmplayer_gst_create_sinkbin(elem, pad, player);
1131 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1132 __mmplayer_gst_make_fakesink(player, pad, name);
1136 LOGD("audio selector is required");
1137 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1138 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1140 } else if (strstr(name, "text")) {
1141 LOGD("text selector is required");
1142 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1143 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1145 LOGE("invalid caps info");
1149 /* check selector and create it */
1150 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1151 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1156 LOGD("input-selector is already created.");
1160 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1162 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1164 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1165 LOGE("failed to link selector");
1166 gst_object_unref(GST_OBJECT(selector));
1171 LOGD("this track will be activated");
1172 g_object_set(selector, "active-pad", sinkpad, NULL);
1175 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1181 gst_caps_unref(caps);
1184 gst_object_unref(GST_OBJECT(sinkpad));
1192 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1194 GstPad *srcpad = NULL;
1197 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1199 LOGD("type %d", type);
1202 LOGD("there is no %d track", type);
1206 srcpad = gst_element_get_static_pad(selector, "src");
1208 LOGE("failed to get srcpad from selector");
1212 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1214 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1216 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1217 if (player->selector[type].block_id) {
1218 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1219 player->selector[type].block_id = 0;
1223 gst_object_unref(GST_OBJECT(srcpad));
1232 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1234 MMHandleType attrs = 0;
1235 gint active_index = 0;
1238 MMPLAYER_RETURN_IF_FAIL(player);
1240 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1242 /* change track to active pad */
1243 active_index = player->selector[type].active_pad_index;
1244 if ((active_index != DEFAULT_TRACK) &&
1245 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1246 LOGW("failed to change %d type track to %d", type, active_index);
1247 player->selector[type].active_pad_index = DEFAULT_TRACK;
1251 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1252 attrs = MMPLAYER_GET_ATTRS(player);
1254 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1255 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1257 if (mm_attrs_commit_all(attrs))
1258 LOGW("failed to commit attrs.");
1260 LOGW("cannot get content attribute");
1269 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1274 if (!audio_selector) {
1275 LOGD("there is no audio track");
1277 /* in case the source is changed, output can be changed. */
1278 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1279 LOGD("remove previous audiobin if it exist");
1281 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1282 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1284 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1285 MMPLAYER_FREEIF(player->pipeline->audiobin);
1288 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1289 __mmplayer_pipeline_complete(NULL, player);
1294 /* apply the audio track information */
1295 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1297 /* create audio sink path */
1298 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1299 LOGE("failed to create audio sink path");
1308 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1311 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1313 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1314 LOGD("text path is not supproted");
1318 /* apply the text track information */
1319 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1321 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1322 player->has_closed_caption = TRUE;
1324 /* create text decode path */
1325 player->no_more_pad = TRUE;
1327 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1328 LOGE("failed to create text sink path");
1337 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1339 gint64 dur_bytes = 0L;
1342 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1343 player->pipeline->mainbin && player->streamer, FALSE);
1345 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1346 LOGE("fail to get duration.");
1348 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1349 * use file information was already set on Q2 when it was created. */
1350 __mm_player_streaming_set_queue2(player->streamer,
1351 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1352 TRUE, /* use_buffering */
1353 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1354 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1361 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1363 mm_player_t *player = NULL;
1364 GstElement *video_selector = NULL;
1365 GstElement *audio_selector = NULL;
1366 GstElement *text_selector = NULL;
1369 player = (mm_player_t *)data;
1371 LOGD("no-more-pad signal handling");
1373 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1374 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1375 LOGW("player is shutting down");
1379 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1380 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1381 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1382 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1383 LOGE("failed to set queue2 buffering");
1388 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1389 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1390 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1392 /* create video path followed by video-select */
1393 if (video_selector && !audio_selector && !text_selector)
1394 player->no_more_pad = TRUE;
1396 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1399 /* create audio path followed by audio-select */
1400 if (audio_selector && !text_selector)
1401 player->no_more_pad = TRUE;
1403 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1406 /* create text path followed by text-select */
1407 __mmplayer_create_text_sink_path(player, text_selector);
1410 if (player->gapless.reconfigure) {
1411 player->gapless.reconfigure = FALSE;
1412 MMPLAYER_PLAYBACK_UNLOCK(player);
1419 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1421 gboolean ret = FALSE;
1422 GstElement *pipeline = NULL;
1423 GstPad *sinkpad = NULL;
1426 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1429 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1431 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1433 LOGE("failed to get pad from sinkbin");
1439 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1440 LOGE("failed to link sinkbin for reusing");
1441 goto EXIT; /* exit either pass or fail */
1445 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1446 LOGE("failed to set state(READY) to sinkbin");
1451 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1452 LOGE("failed to add sinkbin to pipeline");
1457 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1458 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1463 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1464 LOGE("failed to set state(PAUSED) to sinkbin");
1473 gst_object_unref(GST_OBJECT(sinkpad));
1481 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1483 mm_player_t *player = NULL;
1484 GstCaps *caps = NULL;
1485 gchar *caps_str = NULL;
1486 GstStructure *str = NULL;
1487 const gchar *name = NULL;
1488 GstElement *sinkbin = NULL;
1489 gboolean reusing = FALSE;
1490 gboolean caps_ret = TRUE;
1491 gchar *sink_pad_name = "sink";
1494 player = (mm_player_t *)data;
1497 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1498 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1500 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1504 caps_str = gst_caps_to_string(caps);
1506 /* LOGD("detected mimetype : %s", name); */
1507 if (strstr(name, "audio")) {
1508 if (player->pipeline->audiobin == NULL) {
1509 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1510 LOGE("failed to create audiobin. continuing without audio");
1514 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1515 LOGD("creating audiobin success");
1518 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1519 LOGD("reusing audiobin");
1520 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1522 } else if (strstr(name, "video")) {
1523 /* 1. zero copy is updated at _decode_pad_added()
1524 * 2. NULL surface type is handled in _decode_pad_added() */
1525 LOGD("zero copy %d", player->set_mode.video_zc);
1526 if (player->pipeline->videobin == NULL) {
1527 int surface_type = 0;
1528 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1529 LOGD("display_surface_type (%d)", surface_type);
1531 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1532 LOGD("mark video overlay for acquire");
1533 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1534 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1535 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1536 &player->video_overlay_resource)
1537 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1538 LOGE("could not mark video_overlay resource for acquire");
1543 player->interrupted_by_resource = FALSE;
1545 if (mm_resource_manager_commit(player->resource_manager) !=
1546 MM_RESOURCE_MANAGER_ERROR_NONE) {
1547 LOGE("could not acquire resources for video playing");
1551 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1552 LOGE("failed to create videobin. continuing without video");
1556 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1557 LOGD("creating videosink bin success");
1560 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1561 LOGD("re-using videobin");
1562 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1564 } else if (strstr(name, "text")) {
1565 if (player->pipeline->textbin == NULL) {
1566 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1567 LOGE("failed to create text sink bin. continuing without text");
1571 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1572 player->textsink_linked = 1;
1573 LOGD("creating textsink bin success");
1575 if (!player->textsink_linked) {
1576 LOGD("re-using textbin");
1578 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1579 player->textsink_linked = 1;
1581 /* linked textbin exist which means that the external subtitle path exist already */
1582 LOGW("ignoring internal subtutle since external subtitle is available");
1585 sink_pad_name = "text_sink";
1587 LOGW("unknown mime type %s, ignoring it", name);
1591 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1594 LOGD("[handle: %p] success to create and link sink bin", player);
1596 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1597 * streaming task. if the task blocked, then buffer will not flow to the next element
1598 *(autoplugging element). so this is special hack for streaming. please try to remove it
1600 /* dec stream count. we can remove fakesink if it's zero */
1601 if (player->num_dynamic_pad)
1602 player->num_dynamic_pad--;
1604 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1606 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1607 __mmplayer_pipeline_complete(NULL, player);
1611 MMPLAYER_FREEIF(caps_str);
1614 gst_caps_unref(caps);
1620 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1622 int required_angle = 0; /* Angle required for straight view */
1623 int rotation_angle = 0;
1625 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1626 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1628 /* Counter clockwise */
1629 switch (orientation) {
1634 required_angle = 270;
1637 required_angle = 180;
1640 required_angle = 90;
1644 rotation_angle = display_angle + required_angle;
1645 if (rotation_angle >= 360)
1646 rotation_angle -= 360;
1648 /* chech if supported or not */
1649 if (rotation_angle % 90) {
1650 LOGD("not supported rotation angle = %d", rotation_angle);
1654 switch (rotation_angle) {
1656 *value = MM_DISPLAY_ROTATION_NONE;
1659 *value = MM_DISPLAY_ROTATION_90;
1662 *value = MM_DISPLAY_ROTATION_180;
1665 *value = MM_DISPLAY_ROTATION_270;
1669 LOGD("setting rotation property value : %d", *value);
1675 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1677 /* check video sinkbin is created */
1678 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1680 player->pipeline->videobin &&
1681 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1682 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1683 MM_ERROR_PLAYER_NOT_INITIALIZED);
1685 return MM_ERROR_NONE;
1689 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1691 int display_rotation = 0;
1692 gchar *org_orient = NULL;
1693 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1696 LOGE("cannot get content attribute");
1697 return MM_ERROR_PLAYER_INTERNAL;
1700 if (display_angle) {
1701 /* update user roation */
1702 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1704 /* Counter clockwise */
1705 switch (display_rotation) {
1706 case MM_DISPLAY_ROTATION_NONE:
1709 case MM_DISPLAY_ROTATION_90:
1710 *display_angle = 90;
1712 case MM_DISPLAY_ROTATION_180:
1713 *display_angle = 180;
1715 case MM_DISPLAY_ROTATION_270:
1716 *display_angle = 270;
1719 LOGW("wrong angle type : %d", display_rotation);
1722 LOGD("check user angle: %d", *display_angle);
1726 /* Counter clockwise */
1727 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1730 if (!strcmp(org_orient, "rotate-90"))
1732 else if (!strcmp(org_orient, "rotate-180"))
1734 else if (!strcmp(org_orient, "rotate-270"))
1737 LOGD("original rotation is %s", org_orient);
1739 LOGD("content_video_orientation get fail");
1742 LOGD("check orientation: %d", *orientation);
1745 return MM_ERROR_NONE;
1749 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1751 int rotation_value = 0;
1752 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1753 int display_angle = 0;
1756 /* check video sinkbin is created */
1757 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1760 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1762 /* get rotation value to set */
1763 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1764 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1765 LOGD("set video param : rotate %d", rotation_value);
1769 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1771 MMHandleType attrs = 0;
1775 /* check video sinkbin is created */
1776 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1779 attrs = MMPLAYER_GET_ATTRS(player);
1780 MMPLAYER_RETURN_IF_FAIL(attrs);
1782 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1783 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1784 LOGD("set video param : visible %d", visible);
1788 __mmplayer_video_param_set_display_method(mm_player_t *player)
1790 MMHandleType attrs = 0;
1791 int display_method = 0;
1794 /* check video sinkbin is created */
1795 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1798 attrs = MMPLAYER_GET_ATTRS(player);
1799 MMPLAYER_RETURN_IF_FAIL(attrs);
1801 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1802 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1803 LOGD("set video param : method %d", display_method);
1807 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1809 MMHandleType attrs = 0;
1810 void *handle = NULL;
1813 /* check video sinkbin is created */
1814 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1815 LOGW("There is no video sink");
1819 attrs = MMPLAYER_GET_ATTRS(player);
1820 MMPLAYER_RETURN_IF_FAIL(attrs);
1821 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1823 gst_video_overlay_set_video_roi_area(
1824 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1825 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1826 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1827 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1832 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1834 MMHandleType attrs = 0;
1835 void *handle = NULL;
1839 int win_roi_width = 0;
1840 int win_roi_height = 0;
1843 /* check video sinkbin is created */
1844 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1845 LOGW("There is no video sink");
1849 attrs = MMPLAYER_GET_ATTRS(player);
1850 MMPLAYER_RETURN_IF_FAIL(attrs);
1852 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1855 /* It should be set after setting window */
1856 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1857 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1858 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1859 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1861 /* After setting window handle, set display roi area */
1862 gst_video_overlay_set_display_roi_area(
1863 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1864 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1865 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1866 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1871 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1873 MMHandleType attrs = 0;
1874 void *handle = NULL;
1876 /* check video sinkbin is created */
1877 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1880 attrs = MMPLAYER_GET_ATTRS(player);
1881 MMPLAYER_RETURN_IF_FAIL(attrs);
1883 /* common case if using overlay surface */
1884 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1887 /* default is using wl_surface_id */
1888 unsigned int wl_surface_id = 0;
1889 wl_surface_id = *(int *)handle;
1890 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1891 gst_video_overlay_set_wl_window_wl_surface_id(
1892 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1895 /* FIXIT : is it error case? */
1896 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1901 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1903 gboolean update_all_param = FALSE;
1906 /* check video sinkbin is created */
1907 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1908 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1910 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1911 LOGE("can not find tizenwlsink");
1912 return MM_ERROR_PLAYER_INTERNAL;
1915 LOGD("param_name : %s", param_name);
1916 if (!g_strcmp0(param_name, "update_all_param"))
1917 update_all_param = TRUE;
1919 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1920 __mmplayer_video_param_set_display_overlay(player);
1921 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1922 __mmplayer_video_param_set_display_method(player);
1923 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1924 __mmplayer_video_param_set_display_visible(player);
1925 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1926 __mmplayer_video_param_set_display_rotation(player);
1927 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1928 __mmplayer_video_param_set_roi_area(player);
1929 if (update_all_param)
1930 __mmplayer_video_param_set_video_roi_area(player);
1932 return MM_ERROR_NONE;
1936 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1938 MMHandleType attrs = 0;
1939 int surface_type = 0;
1940 int ret = MM_ERROR_NONE;
1944 /* check video sinkbin is created */
1945 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1946 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1948 attrs = MMPLAYER_GET_ATTRS(player);
1950 LOGE("cannot get content attribute");
1951 return MM_ERROR_PLAYER_INTERNAL;
1953 LOGD("param_name : %s", param_name);
1955 /* update display surface */
1956 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1957 LOGD("check display surface type attribute: %d", surface_type);
1959 /* configuring display */
1960 switch (surface_type) {
1961 case MM_DISPLAY_SURFACE_OVERLAY:
1963 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1964 if (ret != MM_ERROR_NONE)
1972 return MM_ERROR_NONE;
1976 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1978 gboolean disable_overlay = FALSE;
1979 mm_player_t *player = (mm_player_t *)hplayer;
1980 int ret = MM_ERROR_NONE;
1983 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1984 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
1985 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1986 MM_ERROR_PLAYER_NO_OP); /* invalid op */
1988 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
1989 LOGW("Display control is not supported");
1990 return MM_ERROR_PLAYER_INTERNAL;
1993 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
1995 if (audio_only == (bool)disable_overlay) {
1996 LOGE("It's the same with current setting: (%d)", audio_only);
1997 return MM_ERROR_NONE;
2001 LOGE("disable overlay");
2002 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2004 /* release overlay resource */
2005 if (player->video_overlay_resource != NULL) {
2006 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2007 player->video_overlay_resource);
2008 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2009 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2012 player->video_overlay_resource = NULL;
2015 ret = mm_resource_manager_commit(player->resource_manager);
2016 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2017 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2021 /* mark video overlay for acquire */
2022 if (player->video_overlay_resource == NULL) {
2023 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2024 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2025 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2026 &player->video_overlay_resource);
2027 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2028 LOGE("could not prepare for video_overlay resource");
2033 player->interrupted_by_resource = FALSE;
2034 /* acquire resources for video overlay */
2035 ret = mm_resource_manager_commit(player->resource_manager);
2036 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2037 LOGE("could not acquire resources for video playing");
2041 LOGD("enable overlay");
2042 __mmplayer_video_param_set_display_overlay(player);
2043 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2048 return MM_ERROR_NONE;
2052 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2054 mm_player_t *player = (mm_player_t *)hplayer;
2055 gboolean disable_overlay = FALSE;
2059 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2060 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2061 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2062 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2063 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2065 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2066 LOGW("Display control is not supported");
2067 return MM_ERROR_PLAYER_INTERNAL;
2070 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2072 *paudio_only = (bool)disable_overlay;
2074 LOGD("audio_only : %d", *paudio_only);
2078 return MM_ERROR_NONE;
2082 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2084 GList *bucket = element_bucket;
2085 MMPlayerGstElement *element = NULL;
2086 MMPlayerGstElement *prv_element = NULL;
2087 gint successful_link_count = 0;
2091 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2093 prv_element = (MMPlayerGstElement *)bucket->data;
2094 bucket = bucket->next;
2096 for (; bucket; bucket = bucket->next) {
2097 element = (MMPlayerGstElement *)bucket->data;
2099 if (element && element->gst) {
2100 if (prv_element && prv_element->gst) {
2101 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2102 LOGD("linking [%s] to [%s] success",
2103 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2104 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2105 successful_link_count++;
2107 LOGD("linking [%s] to [%s] failed",
2108 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2109 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2115 prv_element = element;
2120 return successful_link_count;
2124 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2126 GList *bucket = element_bucket;
2127 MMPlayerGstElement *element = NULL;
2128 int successful_add_count = 0;
2132 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2133 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2135 for (; bucket; bucket = bucket->next) {
2136 element = (MMPlayerGstElement *)bucket->data;
2138 if (element && element->gst) {
2139 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2140 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2141 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2142 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2145 successful_add_count++;
2151 return successful_add_count;
2155 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2157 mm_player_t *player = (mm_player_t *)data;
2158 GstCaps *caps = NULL;
2159 GstStructure *str = NULL;
2161 gboolean caps_ret = TRUE;
2165 MMPLAYER_RETURN_IF_FAIL(pad);
2166 MMPLAYER_RETURN_IF_FAIL(unused);
2167 MMPLAYER_RETURN_IF_FAIL(data);
2169 caps = gst_pad_get_current_caps(pad);
2173 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2177 LOGD("name = %s", name);
2179 if (strstr(name, "audio")) {
2180 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2182 if (player->audio_stream_changed_cb) {
2183 LOGE("call the audio stream changed cb");
2184 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2186 } else if (strstr(name, "video")) {
2187 if ((name = gst_structure_get_string(str, "format")))
2188 player->set_mode.video_zc = name[0] == 'S';
2190 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2192 if (player->video_stream_changed_cb) {
2193 LOGE("call the video stream changed cb");
2194 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2197 LOGW("invalid caps info");
2202 gst_caps_unref(caps);
2210 * This function is to create audio pipeline for playing.
2212 * @param player [in] handle of player
2214 * @return This function returns zero on success.
2216 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2218 /* macro for code readability. just for sinkbin-creation functions */
2219 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2221 x_bin[x_id].id = x_id;\
2222 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2223 if (!x_bin[x_id].gst) {\
2224 LOGE("failed to create %s", x_factory);\
2227 if (x_player->ini.set_dump_element_flag)\
2228 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2231 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2235 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2240 MMPLAYER_RETURN_IF_FAIL(player);
2242 if (player->audio_stream_buff_list) {
2243 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2244 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2247 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2248 __mmplayer_audio_stream_send_data(player, tmp);
2250 MMPLAYER_FREEIF(tmp->pcm_data);
2251 MMPLAYER_FREEIF(tmp);
2254 g_list_free(player->audio_stream_buff_list);
2255 player->audio_stream_buff_list = NULL;
2262 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2264 MMPlayerAudioStreamDataType audio_stream = { 0, };
2267 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2269 audio_stream.bitrate = a_buffer->bitrate;
2270 audio_stream.channel = a_buffer->channel;
2271 audio_stream.depth = a_buffer->depth;
2272 audio_stream.is_little_endian = a_buffer->is_little_endian;
2273 audio_stream.channel_mask = a_buffer->channel_mask;
2274 audio_stream.data_size = a_buffer->data_size;
2275 audio_stream.data = a_buffer->pcm_data;
2277 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2278 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2284 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2286 mm_player_t *player = (mm_player_t *)data;
2290 gint endianness = 0;
2291 guint64 channel_mask = 0;
2292 void *a_data = NULL;
2294 mm_player_audio_stream_buff_t *a_buffer = NULL;
2295 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2299 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2301 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2302 a_data = mapinfo.data;
2303 a_size = mapinfo.size;
2305 GstCaps *caps = gst_pad_get_current_caps(pad);
2306 GstStructure *structure = gst_caps_get_structure(caps, 0);
2308 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2309 gst_structure_get_int(structure, "rate", &rate);
2310 gst_structure_get_int(structure, "channels", &channel);
2311 gst_structure_get_int(structure, "depth", &depth);
2312 gst_structure_get_int(structure, "endianness", &endianness);
2313 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2314 gst_caps_unref(GST_CAPS(caps));
2316 /* In case of the sync is false, use buffer list. *
2317 * The num of buffer list depends on the num of audio channels */
2318 if (player->audio_stream_buff_list) {
2319 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2320 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2322 if (channel_mask == tmp->channel_mask) {
2323 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2324 if (tmp->data_size + a_size < tmp->buff_size) {
2325 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2326 tmp->data_size += a_size;
2328 /* send data to client */
2329 __mmplayer_audio_stream_send_data(player, tmp);
2331 if (a_size > tmp->buff_size) {
2332 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2333 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2334 if (tmp->pcm_data == NULL) {
2335 LOGE("failed to realloc data.");
2338 tmp->buff_size = a_size;
2340 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2341 memcpy(tmp->pcm_data, a_data, a_size);
2342 tmp->data_size = a_size;
2347 LOGE("data is empty in list.");
2353 /* create new audio stream data */
2354 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2355 if (a_buffer == NULL) {
2356 LOGE("failed to alloc data.");
2359 a_buffer->bitrate = rate;
2360 a_buffer->channel = channel;
2361 a_buffer->depth = depth;
2362 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2363 a_buffer->channel_mask = channel_mask;
2364 a_buffer->data_size = a_size;
2366 if (!player->audio_stream_sink_sync) {
2367 /* If sync is FALSE, use buffer list to reduce the IPC. */
2368 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2369 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2370 if (a_buffer->pcm_data == NULL) {
2371 LOGE("failed to alloc data.");
2372 MMPLAYER_FREEIF(a_buffer);
2375 memcpy(a_buffer->pcm_data, a_data, a_size);
2376 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2377 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2379 /* If sync is TRUE, send data directly. */
2380 a_buffer->pcm_data = a_data;
2381 __mmplayer_audio_stream_send_data(player, a_buffer);
2382 MMPLAYER_FREEIF(a_buffer);
2386 gst_buffer_unmap(buffer, &mapinfo);
2391 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2393 mm_player_t *player = (mm_player_t *)data;
2394 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2395 GstPad *sinkpad = NULL;
2396 GstElement *queue = NULL, *sink = NULL;
2399 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2401 queue = gst_element_factory_make("queue", NULL);
2402 if (queue == NULL) {
2403 LOGD("fail make queue");
2407 sink = gst_element_factory_make("fakesink", NULL);
2409 LOGD("fail make fakesink");
2413 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2415 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2416 LOGW("failed to link queue & sink");
2420 sinkpad = gst_element_get_static_pad(queue, "sink");
2422 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2423 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2427 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2429 gst_object_unref(sinkpad);
2430 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2431 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2433 gst_element_set_state(sink, GST_STATE_PAUSED);
2434 gst_element_set_state(queue, GST_STATE_PAUSED);
2436 __mmplayer_add_signal_connection(player,
2438 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2440 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2447 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2449 gst_object_unref(GST_OBJECT(queue));
2453 gst_object_unref(GST_OBJECT(sink));
2457 gst_object_unref(GST_OBJECT(sinkpad));
2465 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2467 #define MAX_PROPS_LEN 128
2468 gint latency_mode = 0;
2469 gchar *stream_type = NULL;
2470 gchar *latency = NULL;
2472 gchar stream_props[MAX_PROPS_LEN] = {0,};
2473 GstStructure *props = NULL;
2476 * It should be set after player creation through attribute.
2477 * But, it can not be changed during playing.
2480 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2482 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2483 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2486 LOGE("stream_type is null.");
2488 if (player->sound.focus_id)
2489 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2490 stream_type, stream_id, player->sound.focus_id);
2492 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2493 stream_type, stream_id);
2494 props = gst_structure_from_string(stream_props, NULL);
2495 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2496 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2497 stream_type, stream_id, player->sound.focus_id, stream_props);
2498 gst_structure_free(props);
2501 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2503 switch (latency_mode) {
2504 case AUDIO_LATENCY_MODE_LOW:
2505 latency = g_strndup("low", 3);
2507 case AUDIO_LATENCY_MODE_MID:
2508 latency = g_strndup("mid", 3);
2510 case AUDIO_LATENCY_MODE_HIGH:
2511 latency = g_strndup("high", 4);
2515 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2519 LOGD("audiosink property - latency=%s", latency);
2521 MMPLAYER_FREEIF(latency);
2527 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2529 MMPlayerGstElement *audiobin = NULL;
2532 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2534 audiobin = player->pipeline->audiobin;
2536 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2537 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2538 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2540 if (player->video360_yaw_radians <= M_PI &&
2541 player->video360_yaw_radians >= -M_PI &&
2542 player->video360_pitch_radians <= M_PI_2 &&
2543 player->video360_pitch_radians >= -M_PI_2) {
2544 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2545 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2546 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2547 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2548 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2549 "source-orientation-y", player->video360_metadata.init_view_heading,
2550 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2557 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2559 MMPlayerGstElement *audiobin = NULL;
2560 MMHandleType attrs = 0;
2561 GList *element_bucket = NULL;
2562 GstCaps *acaps = NULL;
2563 GstPad *sink_pad = NULL;
2566 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2567 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2569 audiobin = player->pipeline->audiobin;
2570 attrs = MMPLAYER_GET_ATTRS(player);
2573 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2575 /* replaygain volume */
2576 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2577 if (player->sound.rg_enable)
2578 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2580 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2583 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2585 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2586 gchar *dst_format = NULL;
2588 int dst_samplerate = 0;
2589 int dst_channels = 0;
2590 GstCaps *caps = NULL;
2591 char *caps_str = NULL;
2593 /* get conf. values */
2594 mm_attrs_multiple_get(player->attrs, NULL,
2595 "pcm_audioformat", &dst_format, &dst_len,
2596 "pcm_extraction_samplerate", &dst_samplerate,
2597 "pcm_extraction_channels", &dst_channels,
2600 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2603 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2604 caps = gst_caps_new_simple("audio/x-raw",
2605 "format", G_TYPE_STRING, dst_format,
2606 "rate", G_TYPE_INT, dst_samplerate,
2607 "channels", G_TYPE_INT, dst_channels,
2610 caps_str = gst_caps_to_string(caps);
2611 LOGD("new caps : %s", caps_str);
2613 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2616 gst_caps_unref(caps);
2617 MMPLAYER_FREEIF(caps_str);
2619 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2621 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2623 /* raw pad handling signal, audiosink will be added after getting signal */
2624 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2625 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2629 /* normal playback */
2632 /* for logical volume control */
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2636 if (player->sound.mute) {
2637 LOGD("mute enabled");
2638 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2641 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2643 /* audio effect element. if audio effect is enabled */
2644 if ((strcmp(player->ini.audioeffect_element, ""))
2646 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2649 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2651 if ((!player->bypass_audio_effect)
2652 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2653 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2654 if (!_mmplayer_audio_effect_custom_apply(player))
2655 LOGI("apply audio effect(custom) setting success");
2659 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2660 && (player->set_mode.rich_audio))
2661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2664 /* create audio sink */
2665 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2666 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2667 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2669 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2670 if (player->is_360_feature_enabled &&
2671 player->is_content_spherical &&
2673 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2674 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2675 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2677 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2681 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2682 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2683 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2684 gst_caps_unref(acaps);
2686 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2688 player->is_openal_plugin_used = TRUE;
2690 if (player->is_360_feature_enabled && player->is_content_spherical)
2691 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2692 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2695 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2696 (player->videodec_linked && player->ini.use_system_clock)) {
2697 LOGD("system clock will be used.");
2698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2701 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2702 __mmplayer_gst_set_pulsesink_property(player, attrs);
2703 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2704 __mmplayer_gst_set_openalsink_property(player);
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2710 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2711 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2712 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2713 gst_object_unref(GST_OBJECT(sink_pad));
2715 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2718 *bucket = element_bucket;
2721 return MM_ERROR_NONE;
2724 g_list_free(element_bucket);
2728 return MM_ERROR_PLAYER_INTERNAL;
2732 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2734 MMPlayerGstElement *first_element = NULL;
2735 MMPlayerGstElement *audiobin = NULL;
2737 GstPad *ghostpad = NULL;
2738 GList *element_bucket = NULL;
2742 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2745 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2747 LOGE("failed to allocate memory for audiobin");
2748 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2752 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2753 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2754 if (!audiobin[MMPLAYER_A_BIN].gst) {
2755 LOGE("failed to create audiobin");
2760 player->pipeline->audiobin = audiobin;
2762 /* create audio filters and audiosink */
2763 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2766 /* adding created elements to bin */
2767 LOGD("adding created elements to bin");
2768 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2771 /* linking elements in the bucket by added order. */
2772 LOGD("Linking elements in the bucket by added order.");
2773 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2776 /* get first element's sinkpad for creating ghostpad */
2777 first_element = (MMPlayerGstElement *)element_bucket->data;
2778 if (!first_element) {
2779 LOGE("failed to get first elem");
2783 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2785 LOGE("failed to get pad from first element of audiobin");
2789 ghostpad = gst_ghost_pad_new("sink", pad);
2791 LOGE("failed to create ghostpad");
2795 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2796 LOGE("failed to add ghostpad to audiobin");
2800 gst_object_unref(pad);
2802 g_list_free(element_bucket);
2805 return MM_ERROR_NONE;
2808 LOGD("ERROR : releasing audiobin");
2811 gst_object_unref(GST_OBJECT(pad));
2814 gst_object_unref(GST_OBJECT(ghostpad));
2817 g_list_free(element_bucket);
2819 /* release element which are not added to bin */
2820 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2821 /* NOTE : skip bin */
2822 if (audiobin[i].gst) {
2823 GstObject *parent = NULL;
2824 parent = gst_element_get_parent(audiobin[i].gst);
2827 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2828 audiobin[i].gst = NULL;
2830 gst_object_unref(GST_OBJECT(parent));
2834 /* release audiobin with it's childs */
2835 if (audiobin[MMPLAYER_A_BIN].gst)
2836 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2838 MMPLAYER_FREEIF(audiobin);
2840 player->pipeline->audiobin = NULL;
2842 return MM_ERROR_PLAYER_INTERNAL;
2846 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2848 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2852 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2854 int ret = MM_ERROR_NONE;
2856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2857 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2859 MMPLAYER_VIDEO_BO_LOCK(player);
2861 if (player->video_bo_list) {
2862 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2863 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2864 if (tmp && tmp->bo == bo) {
2866 LOGD("release bo %p", bo);
2867 tbm_bo_unref(tmp->bo);
2868 MMPLAYER_VIDEO_BO_UNLOCK(player);
2869 MMPLAYER_VIDEO_BO_SIGNAL(player);
2874 /* hw codec is running or the list was reset for DRC. */
2875 LOGW("there is no bo list.");
2877 MMPLAYER_VIDEO_BO_UNLOCK(player);
2879 LOGW("failed to find bo %p", bo);
2884 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2889 MMPLAYER_RETURN_IF_FAIL(player);
2891 MMPLAYER_VIDEO_BO_LOCK(player);
2892 if (player->video_bo_list) {
2893 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2894 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2895 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2898 tbm_bo_unref(tmp->bo);
2902 g_list_free(player->video_bo_list);
2903 player->video_bo_list = NULL;
2905 player->video_bo_size = 0;
2906 MMPLAYER_VIDEO_BO_UNLOCK(player);
2913 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2916 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2917 gboolean ret = TRUE;
2919 /* check DRC, if it is, destroy the prev bo list to create again */
2920 if (player->video_bo_size != size) {
2921 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2922 __mmplayer_video_stream_destroy_bo_list(player);
2923 player->video_bo_size = size;
2926 MMPLAYER_VIDEO_BO_LOCK(player);
2928 if ((!player->video_bo_list) ||
2929 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2931 /* create bo list */
2933 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2935 if (player->video_bo_list) {
2936 /* if bo list did not created all, try it again. */
2937 idx = g_list_length(player->video_bo_list);
2938 LOGD("bo list exist(len: %d)", idx);
2941 for (; idx < player->ini.num_of_video_bo; idx++) {
2942 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2944 LOGE("Fail to alloc bo_info.");
2947 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2949 LOGE("Fail to tbm_bo_alloc.");
2950 MMPLAYER_FREEIF(bo_info);
2953 bo_info->used = FALSE;
2954 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2957 /* update video num buffers */
2958 player->video_num_buffers = idx;
2959 if (idx == player->ini.num_of_video_bo)
2960 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2963 MMPLAYER_VIDEO_BO_UNLOCK(player);
2967 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2971 /* get bo from list*/
2972 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2973 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2974 if (tmp && (tmp->used == FALSE)) {
2975 LOGD("found bo %p to use", tmp->bo);
2977 MMPLAYER_VIDEO_BO_UNLOCK(player);
2978 return tbm_bo_ref(tmp->bo);
2982 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
2983 MMPLAYER_VIDEO_BO_UNLOCK(player);
2987 if (player->ini.video_bo_timeout <= 0) {
2988 MMPLAYER_VIDEO_BO_WAIT(player);
2990 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
2991 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
2998 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3000 mm_player_t *player = (mm_player_t *)data;
3002 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3004 /* send prerolled pkt */
3005 player->video_stream_prerolled = false;
3007 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3009 /* not to send prerolled pkt again */
3010 player->video_stream_prerolled = true;
3014 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3016 mm_player_t *player = (mm_player_t *)data;
3017 MMPlayerVideoStreamDataType *stream = NULL;
3018 GstMemory *mem = NULL;
3021 MMPLAYER_RETURN_IF_FAIL(player);
3022 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3024 if (player->video_stream_prerolled) {
3025 player->video_stream_prerolled = false;
3026 LOGD("skip the prerolled pkt not to send it again");
3030 /* clear stream data structure */
3031 stream = __mmplayer_create_stream_from_pad(pad);
3033 LOGE("failed to alloc stream");
3037 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3039 /* set size and timestamp */
3040 mem = gst_buffer_peek_memory(buffer, 0);
3041 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3042 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3044 /* check zero-copy */
3045 if (player->set_mode.video_zc &&
3046 player->set_mode.media_packet_video_stream &&
3047 gst_is_tizen_memory(mem)) {
3048 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3049 stream->internal_buffer = gst_buffer_ref(buffer);
3050 } else { /* sw codec */
3051 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3054 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3058 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3059 LOGE("failed to send video stream data.");
3066 LOGE("release video stream resource.");
3067 if (gst_is_tizen_memory(mem)) {
3069 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3071 tbm_bo_unref(stream->bo[i]);
3074 /* unref gst buffer */
3075 if (stream->internal_buffer)
3076 gst_buffer_unref(stream->internal_buffer);
3079 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3081 MMPLAYER_FREEIF(stream);
3086 __mmplayer_gst_set_video360_property(mm_player_t *player)
3088 MMPlayerGstElement *videobin = NULL;
3091 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3093 videobin = player->pipeline->videobin;
3095 /* Set spatial media metadata and/or user settings to the element.
3097 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3098 "projection-type", player->video360_metadata.projection_type, NULL);
3100 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3101 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3103 if (player->video360_metadata.full_pano_width_pixels &&
3104 player->video360_metadata.full_pano_height_pixels &&
3105 player->video360_metadata.cropped_area_image_width &&
3106 player->video360_metadata.cropped_area_image_height) {
3107 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3108 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3109 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3110 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3111 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3112 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3113 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3117 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3118 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3119 "horizontal-fov", player->video360_horizontal_fov,
3120 "vertical-fov", player->video360_vertical_fov, NULL);
3123 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3124 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3125 "zoom", 1.0f / player->video360_zoom, NULL);
3128 if (player->video360_yaw_radians <= M_PI &&
3129 player->video360_yaw_radians >= -M_PI &&
3130 player->video360_pitch_radians <= M_PI_2 &&
3131 player->video360_pitch_radians >= -M_PI_2) {
3132 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3133 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3134 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3135 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3136 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3137 "pose-yaw", player->video360_metadata.init_view_heading,
3138 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3141 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3142 "passthrough", !player->is_video360_enabled, NULL);
3149 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3151 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3152 GList *element_bucket = NULL;
3155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3157 /* create video360 filter */
3158 if (player->is_360_feature_enabled && player->is_content_spherical) {
3159 LOGD("create video360 element");
3160 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3161 __mmplayer_gst_set_video360_property(player);
3165 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3166 LOGD("skip creating the videoconv and rotator");
3167 return MM_ERROR_NONE;
3170 /* in case of sw codec & overlay surface type, except 360 playback.
3171 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3172 LOGD("create video converter: %s", video_csc);
3173 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3175 /* set video rotator */
3176 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3179 *bucket = element_bucket;
3181 return MM_ERROR_NONE;
3183 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3184 g_list_free(element_bucket);
3188 return MM_ERROR_PLAYER_INTERNAL;
3192 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3194 gchar *factory_name = NULL;
3196 switch (surface_type) {
3197 case MM_DISPLAY_SURFACE_OVERLAY:
3198 if (strlen(player->ini.videosink_element_overlay) > 0)
3199 factory_name = player->ini.videosink_element_overlay;
3201 case MM_DISPLAY_SURFACE_REMOTE:
3202 case MM_DISPLAY_SURFACE_NULL:
3203 if (strlen(player->ini.videosink_element_fake) > 0)
3204 factory_name = player->ini.videosink_element_fake;
3207 LOGE("unidentified surface type");
3211 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3212 return factory_name;
3216 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3218 gchar *factory_name = NULL;
3219 MMPlayerGstElement *videobin = NULL;
3224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3226 videobin = player->pipeline->videobin;
3227 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3229 attrs = MMPLAYER_GET_ATTRS(player);
3231 LOGE("cannot get content attribute");
3232 return MM_ERROR_PLAYER_INTERNAL;
3235 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3236 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3237 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3239 /* support shard memory with S/W codec on HawkP */
3240 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3241 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3242 "use-tbm", use_tbm, NULL);
3246 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3247 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3250 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3252 LOGD("disable last-sample");
3253 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3256 if (player->set_mode.media_packet_video_stream) {
3258 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3259 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3260 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3262 __mmplayer_add_signal_connection(player,
3263 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3264 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3266 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3269 __mmplayer_add_signal_connection(player,
3270 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3271 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3273 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3277 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3278 return MM_ERROR_PLAYER_INTERNAL;
3280 if (videobin[MMPLAYER_V_SINK].gst) {
3281 GstPad *sink_pad = NULL;
3282 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3284 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3285 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3286 gst_object_unref(GST_OBJECT(sink_pad));
3288 LOGE("failed to get sink pad from videosink");
3292 return MM_ERROR_NONE;
3297 * - video overlay surface(arm/x86) : tizenwlsink
3300 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3303 GList *element_bucket = NULL;
3304 MMPlayerGstElement *first_element = NULL;
3305 MMPlayerGstElement *videobin = NULL;
3306 gchar *videosink_factory_name = NULL;
3309 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3312 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3314 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3316 player->pipeline->videobin = videobin;
3319 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3320 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3321 if (!videobin[MMPLAYER_V_BIN].gst) {
3322 LOGE("failed to create videobin");
3326 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3329 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3330 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3332 /* additional setting for sink plug-in */
3333 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3334 LOGE("failed to set video property");
3338 /* store it as it's sink element */
3339 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3341 /* adding created elements to bin */
3342 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3343 LOGE("failed to add elements");
3347 /* Linking elements in the bucket by added order */
3348 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3349 LOGE("failed to link elements");
3353 /* get first element's sinkpad for creating ghostpad */
3354 first_element = (MMPlayerGstElement *)element_bucket->data;
3355 if (!first_element) {
3356 LOGE("failed to get first element from bucket");
3360 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3362 LOGE("failed to get pad from first element");
3366 /* create ghostpad */
3367 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3368 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3369 LOGE("failed to add ghostpad to videobin");
3372 gst_object_unref(pad);
3374 /* done. free allocated variables */
3375 g_list_free(element_bucket);
3379 return MM_ERROR_NONE;
3382 LOGE("ERROR : releasing videobin");
3383 g_list_free(element_bucket);
3386 gst_object_unref(GST_OBJECT(pad));
3388 /* release videobin with it's childs */
3389 if (videobin[MMPLAYER_V_BIN].gst)
3390 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3392 MMPLAYER_FREEIF(videobin);
3393 player->pipeline->videobin = NULL;
3395 return MM_ERROR_PLAYER_INTERNAL;
3399 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3401 GList *element_bucket = NULL;
3402 MMPlayerGstElement *textbin = player->pipeline->textbin;
3404 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3405 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3406 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3407 "signal-handoffs", FALSE,
3410 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3411 __mmplayer_add_signal_connection(player,
3412 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3413 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3415 G_CALLBACK(__mmplayer_update_subtitle),
3418 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3419 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3421 if (!player->play_subtitle) {
3422 LOGD("add textbin sink as sink element of whole pipeline.");
3423 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3426 /* adding created elements to bin */
3427 LOGD("adding created elements to bin");
3428 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3429 LOGE("failed to add elements");
3433 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3434 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3435 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3437 /* linking elements in the bucket by added order. */
3438 LOGD("Linking elements in the bucket by added order.");
3439 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3440 LOGE("failed to link elements");
3444 /* done. free allocated variables */
3445 g_list_free(element_bucket);
3447 if (textbin[MMPLAYER_T_QUEUE].gst) {
3449 GstPad *ghostpad = NULL;
3451 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3453 LOGE("failed to get sink pad of text queue");
3457 ghostpad = gst_ghost_pad_new("text_sink", pad);
3458 gst_object_unref(pad);
3461 LOGE("failed to create ghostpad of textbin");
3465 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3466 LOGE("failed to add ghostpad to textbin");
3467 gst_object_unref(ghostpad);
3472 return MM_ERROR_NONE;
3475 g_list_free(element_bucket);
3477 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3478 LOGE("remove textbin sink from sink list");
3479 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3482 /* release element at __mmplayer_gst_create_text_sink_bin */
3483 return MM_ERROR_PLAYER_INTERNAL;
3487 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3489 MMPlayerGstElement *textbin = NULL;
3490 GList *element_bucket = NULL;
3491 int surface_type = 0;
3496 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3499 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3501 LOGE("failed to allocate memory for textbin");
3502 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3506 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3507 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3508 if (!textbin[MMPLAYER_T_BIN].gst) {
3509 LOGE("failed to create textbin");
3514 player->pipeline->textbin = textbin;
3517 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3518 LOGD("surface type for subtitle : %d", surface_type);
3519 switch (surface_type) {
3520 case MM_DISPLAY_SURFACE_OVERLAY:
3521 case MM_DISPLAY_SURFACE_NULL:
3522 case MM_DISPLAY_SURFACE_REMOTE:
3523 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3524 LOGE("failed to make plain text elements");
3535 return MM_ERROR_NONE;
3539 LOGD("ERROR : releasing textbin");
3541 g_list_free(element_bucket);
3543 /* release signal */
3544 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3546 /* release element which are not added to bin */
3547 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3548 /* NOTE : skip bin */
3549 if (textbin[i].gst) {
3550 GstObject *parent = NULL;
3551 parent = gst_element_get_parent(textbin[i].gst);
3554 gst_object_unref(GST_OBJECT(textbin[i].gst));
3555 textbin[i].gst = NULL;
3557 gst_object_unref(GST_OBJECT(parent));
3562 /* release textbin with it's childs */
3563 if (textbin[MMPLAYER_T_BIN].gst)
3564 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3566 MMPLAYER_FREEIF(player->pipeline->textbin);
3567 player->pipeline->textbin = NULL;
3570 return MM_ERROR_PLAYER_INTERNAL;
3574 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3576 MMPlayerGstElement *mainbin = NULL;
3577 MMPlayerGstElement *textbin = NULL;
3578 MMHandleType attrs = 0;
3579 GstElement *subsrc = NULL;
3580 GstElement *subparse = NULL;
3581 gchar *subtitle_uri = NULL;
3582 const gchar *charset = NULL;
3588 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3590 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3592 mainbin = player->pipeline->mainbin;
3594 attrs = MMPLAYER_GET_ATTRS(player);
3596 LOGE("cannot get content attribute");
3597 return MM_ERROR_PLAYER_INTERNAL;
3600 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3601 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3602 LOGE("subtitle uri is not proper filepath.");
3603 return MM_ERROR_PLAYER_INVALID_URI;
3606 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3607 LOGE("failed to get storage info of subtitle path");
3608 return MM_ERROR_PLAYER_INVALID_URI;
3611 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3613 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3614 player->subtitle_language_list = NULL;
3615 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3617 /* create the subtitle source */
3618 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3620 LOGE("failed to create filesrc element");
3623 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3625 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3626 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3628 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3629 LOGW("failed to add queue");
3630 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3631 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3632 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3637 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3639 LOGE("failed to create subparse element");
3643 charset = util_get_charset(subtitle_uri);
3645 LOGD("detected charset is %s", charset);
3646 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3649 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3650 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3652 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3653 LOGW("failed to add subparse");
3654 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3655 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3656 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3660 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3661 LOGW("failed to link subsrc and subparse");
3665 player->play_subtitle = TRUE;
3666 player->adjust_subtitle_pos = 0;
3668 LOGD("play subtitle using subtitle file");
3670 if (player->pipeline->textbin == NULL) {
3671 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3672 LOGE("failed to create text sink bin. continuing without text");
3676 textbin = player->pipeline->textbin;
3678 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3679 LOGW("failed to add textbin");
3681 /* release signal */
3682 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3684 /* release textbin with it's childs */
3685 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3686 MMPLAYER_FREEIF(player->pipeline->textbin);
3687 player->pipeline->textbin = textbin = NULL;
3691 LOGD("link text input selector and textbin ghost pad");
3693 player->textsink_linked = 1;
3694 player->external_text_idx = 0;
3695 LOGI("textsink is linked");
3697 textbin = player->pipeline->textbin;
3698 LOGD("text bin has been created. reuse it.");
3699 player->external_text_idx = 1;
3702 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3703 LOGW("failed to link subparse and textbin");
3707 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3709 LOGE("failed to get sink pad from textsink to probe data");
3713 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3714 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3716 gst_object_unref(pad);
3719 /* create dot. for debugging */
3720 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3723 return MM_ERROR_NONE;
3726 /* release text pipeline resource */
3727 player->textsink_linked = 0;
3729 /* release signal */
3730 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3732 if (player->pipeline->textbin) {
3733 LOGE("remove textbin");
3735 /* release textbin with it's childs */
3736 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3737 MMPLAYER_FREEIF(player->pipeline->textbin);
3738 player->pipeline->textbin = NULL;
3742 /* release subtitle elem */
3743 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3744 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3746 return MM_ERROR_PLAYER_INTERNAL;
3750 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3752 mm_player_t *player = (mm_player_t *)data;
3753 MMMessageParamType msg = {0, };
3754 GstClockTime duration = 0;
3755 gpointer text = NULL;
3756 guint text_size = 0;
3757 gboolean ret = TRUE;
3758 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3762 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3763 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3765 if (player->is_subtitle_force_drop) {
3766 LOGW("subtitle is dropped forcedly.");
3770 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3771 text = mapinfo.data;
3772 text_size = mapinfo.size;
3773 duration = GST_BUFFER_DURATION(buffer);
3775 if (player->set_mode.subtitle_off) {
3776 LOGD("subtitle is OFF.");
3780 if (!text || (text_size == 0)) {
3781 LOGD("There is no subtitle to be displayed.");
3785 msg.data = (void *)text;
3786 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3788 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3790 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3791 gst_buffer_unmap(buffer, &mapinfo);
3798 static GstPadProbeReturn
3799 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3801 mm_player_t *player = (mm_player_t *)u_data;
3802 GstClockTime cur_timestamp = 0;
3803 gint64 adjusted_timestamp = 0;
3804 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3806 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3808 if (player->set_mode.subtitle_off) {
3809 LOGD("subtitle is OFF.");
3813 if (player->adjust_subtitle_pos == 0) {
3814 LOGD("nothing to do");
3818 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3819 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3821 if (adjusted_timestamp < 0) {
3822 LOGD("adjusted_timestamp under zero");
3827 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3828 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3829 GST_TIME_ARGS(cur_timestamp),
3830 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3832 return GST_PAD_PROBE_OK;
3836 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3840 /* check player and subtitlebin are created */
3841 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3842 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3844 if (position == 0) {
3845 LOGD("nothing to do");
3847 return MM_ERROR_NONE;
3851 case MM_PLAYER_POS_FORMAT_TIME:
3853 /* check current postion */
3854 player->adjust_subtitle_pos = position;
3856 LOGD("save adjust_subtitle_pos in player") ;
3862 LOGW("invalid format.");
3864 return MM_ERROR_INVALID_ARGUMENT;
3870 return MM_ERROR_NONE;
3874 * This function is to create audio or video pipeline for playing.
3876 * @param player [in] handle of player
3878 * @return This function returns zero on success.
3883 __mmplayer_gst_create_pipeline(mm_player_t *player)
3885 int ret = MM_ERROR_NONE;
3886 MMPlayerGstElement *mainbin = NULL;
3887 MMHandleType attrs = 0;
3890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3892 /* get profile attribute */
3893 attrs = MMPLAYER_GET_ATTRS(player);
3895 LOGE("failed to get content attribute");
3899 /* create pipeline handles */
3900 if (player->pipeline) {
3901 LOGE("pipeline should be released before create new one");
3905 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3906 if (player->pipeline == NULL)
3909 /* create mainbin */
3910 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3911 if (mainbin == NULL)
3914 /* create pipeline */
3915 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3916 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3917 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3918 LOGE("failed to create pipeline");
3923 player->pipeline->mainbin = mainbin;
3925 /* create the source and decoder elements */
3926 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3927 ret = __mmplayer_gst_build_es_pipeline(player);
3929 ret = __mmplayer_gst_build_pipeline(player);
3931 if (ret != MM_ERROR_NONE) {
3932 LOGE("failed to create some elements");
3936 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3937 if (__mmplayer_check_subtitle(player)
3938 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3939 LOGE("failed to create text pipeline");
3942 ret = __mmplayer_gst_add_bus_watch(player);
3943 if (ret != MM_ERROR_NONE) {
3944 LOGE("failed to add bus watch");
3949 return MM_ERROR_NONE;
3952 __mmplayer_gst_destroy_pipeline(player);
3953 return MM_ERROR_PLAYER_INTERNAL;
3957 __mmplayer_reset_gapless_state(mm_player_t *player)
3960 MMPLAYER_RETURN_IF_FAIL(player
3962 && player->pipeline->audiobin
3963 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3965 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3972 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
3975 int ret = MM_ERROR_NONE;
3979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
3981 /* cleanup stuffs */
3982 MMPLAYER_FREEIF(player->type);
3983 player->no_more_pad = FALSE;
3984 player->num_dynamic_pad = 0;
3985 player->demux_pad_index = 0;
3987 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3988 player->subtitle_language_list = NULL;
3989 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3991 __mmplayer_reset_gapless_state(player);
3993 if (player->streamer) {
3994 __mm_player_streaming_initialize(player->streamer, FALSE);
3995 __mm_player_streaming_destroy(player->streamer);
3996 player->streamer = NULL;
3999 /* cleanup unlinked mime type */
4000 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4001 MMPLAYER_FREEIF(player->unlinked_video_mime);
4002 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4004 /* cleanup running stuffs */
4005 __mmplayer_cancel_eos_timer(player);
4007 /* cleanup gst stuffs */
4008 if (player->pipeline) {
4009 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4010 GstTagList *tag_list = player->pipeline->tag_list;
4012 /* first we need to disconnect all signal hander */
4013 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4016 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4017 MMPlayerGstElement *videobin = player->pipeline->videobin;
4018 MMPlayerGstElement *textbin = player->pipeline->textbin;
4019 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4020 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4021 gst_object_unref(bus);
4023 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4024 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4025 if (ret != MM_ERROR_NONE) {
4026 LOGE("fail to change state to NULL");
4027 return MM_ERROR_PLAYER_INTERNAL;
4030 LOGW("succeeded in changing state to NULL");
4032 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4035 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4036 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4038 /* free avsysaudiosink
4039 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4040 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4042 MMPLAYER_FREEIF(audiobin);
4043 MMPLAYER_FREEIF(videobin);
4044 MMPLAYER_FREEIF(textbin);
4045 MMPLAYER_FREEIF(mainbin);
4049 gst_tag_list_unref(tag_list);
4051 MMPLAYER_FREEIF(player->pipeline);
4053 MMPLAYER_FREEIF(player->album_art);
4055 if (player->v_stream_caps) {
4056 gst_caps_unref(player->v_stream_caps);
4057 player->v_stream_caps = NULL;
4060 if (player->a_stream_caps) {
4061 gst_caps_unref(player->a_stream_caps);
4062 player->a_stream_caps = NULL;
4065 if (player->s_stream_caps) {
4066 gst_caps_unref(player->s_stream_caps);
4067 player->s_stream_caps = NULL;
4069 __mmplayer_track_destroy(player);
4071 if (player->sink_elements)
4072 g_list_free(player->sink_elements);
4073 player->sink_elements = NULL;
4075 if (player->bufmgr) {
4076 tbm_bufmgr_deinit(player->bufmgr);
4077 player->bufmgr = NULL;
4080 LOGW("finished destroy pipeline");
4088 __mmplayer_gst_realize(mm_player_t *player)
4091 int ret = MM_ERROR_NONE;
4095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4097 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4099 ret = __mmplayer_gst_create_pipeline(player);
4101 LOGE("failed to create pipeline");
4105 /* set pipeline state to READY */
4106 /* NOTE : state change to READY must be performed sync. */
4107 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4108 ret = __mmplayer_gst_set_state(player,
4109 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4111 if (ret != MM_ERROR_NONE) {
4112 /* return error if failed to set state */
4113 LOGE("failed to set READY state");
4117 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4119 /* create dot before error-return. for debugging */
4120 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4128 __mmplayer_gst_unrealize(mm_player_t *player)
4130 int ret = MM_ERROR_NONE;
4134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4136 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4137 MMPLAYER_PRINT_STATE(player);
4139 /* release miscellaneous information */
4140 __mmplayer_release_misc(player);
4142 /* destroy pipeline */
4143 ret = __mmplayer_gst_destroy_pipeline(player);
4144 if (ret != MM_ERROR_NONE) {
4145 LOGE("failed to destory pipeline");
4149 /* release miscellaneous information.
4150 these info needs to be released after pipeline is destroyed. */
4151 __mmplayer_release_misc_post(player);
4153 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4161 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4166 LOGW("set_message_callback is called with invalid player handle");
4167 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4170 player->msg_cb = callback;
4171 player->msg_cb_param = user_param;
4173 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4177 return MM_ERROR_NONE;
4181 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4183 int ret = MM_ERROR_NONE;
4188 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4189 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4190 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4192 memset(data, 0, sizeof(MMPlayerParseProfile));
4194 if (strstr(uri, "es_buff://")) {
4195 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4196 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4197 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4198 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4200 tmp = g_ascii_strdown(uri, strlen(uri));
4201 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4202 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4204 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4206 } else if (strstr(uri, "mms://")) {
4207 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4208 } else if ((path = strstr(uri, "mem://"))) {
4209 ret = __mmplayer_set_mem_uri(data, path, param);
4211 ret = __mmplayer_set_file_uri(data, uri);
4214 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4215 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4216 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4217 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4219 /* dump parse result */
4220 SECURE_LOGW("incoming uri : %s", uri);
4221 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4222 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4230 __mmplayer_can_do_interrupt(mm_player_t *player)
4232 if (!player || !player->pipeline || !player->attrs) {
4233 LOGW("not initialized");
4237 if (player->audio_stream_render_cb) {
4238 LOGW("not support in pcm extraction mode");
4242 /* check if seeking */
4243 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4244 MMMessageParamType msg_param;
4245 memset(&msg_param, 0, sizeof(MMMessageParamType));
4246 msg_param.code = MM_ERROR_PLAYER_SEEK;
4247 player->seek_state = MMPLAYER_SEEK_NONE;
4248 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4252 /* check other thread */
4253 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4254 LOGW("locked already, cmd state : %d", player->cmd);
4256 /* check application command */
4257 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4258 LOGW("playing.. should wait cmd lock then, will be interrupted");
4260 /* lock will be released at mrp_resource_release_cb() */
4261 MMPLAYER_CMD_LOCK(player);
4264 LOGW("nothing to do");
4267 LOGW("can interrupt immediately");
4271 FAILED: /* with CMD UNLOCKED */
4274 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4279 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4282 mm_player_t *player = NULL;
4286 if (user_data == NULL) {
4287 LOGE("- user_data is null");
4290 player = (mm_player_t *)user_data;
4292 /* do something to release resource here.
4293 * player stop and interrupt forwarding */
4294 if (!__mmplayer_can_do_interrupt(player)) {
4295 LOGW("no need to interrupt, so leave");
4297 MMMessageParamType msg = {0, };
4300 player->interrupted_by_resource = TRUE;
4302 /* get last play position */
4303 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4304 LOGW("failed to get play position.");
4306 msg.union_type = MM_MSG_UNION_TIME;
4307 msg.time.elapsed = pos;
4308 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4310 LOGD("video resource conflict so, resource will be freed by unrealizing");
4311 if (_mmplayer_unrealize((MMHandleType)player))
4312 LOGW("failed to unrealize");
4314 /* lock is called in __mmplayer_can_do_interrupt() */
4315 MMPLAYER_CMD_UNLOCK(player);
4318 if (res == player->video_overlay_resource)
4319 player->video_overlay_resource = FALSE;
4321 player->video_decoder_resource = FALSE;
4329 __mmplayer_initialize_video_roi(mm_player_t *player)
4331 player->video_roi.scale_x = 0.0;
4332 player->video_roi.scale_y = 0.0;
4333 player->video_roi.scale_width = 1.0;
4334 player->video_roi.scale_height = 1.0;
4338 _mmplayer_create_player(MMHandleType handle)
4340 int ret = MM_ERROR_PLAYER_INTERNAL;
4341 bool enabled = false;
4343 mm_player_t *player = MM_PLAYER_CAST(handle);
4347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4349 /* initialize player state */
4350 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4351 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4352 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4353 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4355 /* check current state */
4356 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4358 /* construct attributes */
4359 player->attrs = _mmplayer_construct_attribute(handle);
4361 if (!player->attrs) {
4362 LOGE("Failed to construct attributes");
4366 /* initialize gstreamer with configured parameter */
4367 if (!__mmplayer_init_gstreamer(player)) {
4368 LOGE("Initializing gstreamer failed");
4369 _mmplayer_deconstruct_attribute(handle);
4373 /* create lock. note that g_tread_init() has already called in gst_init() */
4374 g_mutex_init(&player->fsink_lock);
4376 /* create update tag lock */
4377 g_mutex_init(&player->update_tag_lock);
4379 /* create gapless play mutex */
4380 g_mutex_init(&player->gapless_play_thread_mutex);
4382 /* create gapless play cond */
4383 g_cond_init(&player->gapless_play_thread_cond);
4385 /* create gapless play thread */
4386 player->gapless_play_thread =
4387 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4388 if (!player->gapless_play_thread) {
4389 LOGE("failed to create gapless play thread");
4390 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4391 g_mutex_clear(&player->gapless_play_thread_mutex);
4392 g_cond_clear(&player->gapless_play_thread_cond);
4396 player->bus_msg_q = g_queue_new();
4397 if (!player->bus_msg_q) {
4398 LOGE("failed to create queue for bus_msg");
4399 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4403 ret = _mmplayer_initialize_video_capture(player);
4404 if (ret != MM_ERROR_NONE) {
4405 LOGE("failed to initialize video capture");
4409 /* initialize resource manager */
4410 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4411 __resource_release_cb, player, &player->resource_manager)
4412 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4413 LOGE("failed to initialize resource manager");
4414 ret = MM_ERROR_PLAYER_INTERNAL;
4418 /* create video bo lock and cond */
4419 g_mutex_init(&player->video_bo_mutex);
4420 g_cond_init(&player->video_bo_cond);
4422 /* create media stream callback mutex */
4423 g_mutex_init(&player->media_stream_cb_lock);
4425 /* create subtitle info lock and cond */
4426 g_mutex_init(&player->subtitle_info_mutex);
4427 g_cond_init(&player->subtitle_info_cond);
4429 player->streaming_type = STREAMING_SERVICE_NONE;
4431 /* give default value of audio effect setting */
4432 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4433 player->sound.rg_enable = false;
4434 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4436 player->play_subtitle = FALSE;
4437 player->has_closed_caption = FALSE;
4438 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4439 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4440 player->pending_resume = FALSE;
4441 if (player->ini.dump_element_keyword[0][0] == '\0')
4442 player->ini.set_dump_element_flag = FALSE;
4444 player->ini.set_dump_element_flag = TRUE;
4446 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4447 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4448 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4450 /* Set video360 settings to their defaults for just-created player.
4453 player->is_360_feature_enabled = FALSE;
4454 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4455 LOGI("spherical feature info: %d", enabled);
4457 player->is_360_feature_enabled = TRUE;
4459 LOGE("failed to get spherical feature info");
4462 player->is_content_spherical = FALSE;
4463 player->is_video360_enabled = TRUE;
4464 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4465 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4466 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4467 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4468 player->video360_zoom = 1.0f;
4469 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4470 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4472 __mmplayer_initialize_video_roi(player);
4474 /* set player state to null */
4475 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4476 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4480 return MM_ERROR_NONE;
4484 g_mutex_clear(&player->fsink_lock);
4485 /* free update tag lock */
4486 g_mutex_clear(&player->update_tag_lock);
4487 g_queue_free(player->bus_msg_q);
4488 /* free gapless play thread */
4489 if (player->gapless_play_thread) {
4490 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4491 player->gapless_play_thread_exit = TRUE;
4492 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4493 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4495 g_thread_join(player->gapless_play_thread);
4496 player->gapless_play_thread = NULL;
4498 g_mutex_clear(&player->gapless_play_thread_mutex);
4499 g_cond_clear(&player->gapless_play_thread_cond);
4502 /* release attributes */
4503 _mmplayer_deconstruct_attribute(handle);
4511 __mmplayer_init_gstreamer(mm_player_t *player)
4513 static gboolean initialized = FALSE;
4514 static const int max_argc = 50;
4516 gchar **argv = NULL;
4517 gchar **argv2 = NULL;
4523 LOGD("gstreamer already initialized.");
4528 argc = malloc(sizeof(int));
4529 argv = malloc(sizeof(gchar *) * max_argc);
4530 argv2 = malloc(sizeof(gchar *) * max_argc);
4532 if (!argc || !argv || !argv2)
4535 memset(argv, 0, sizeof(gchar *) * max_argc);
4536 memset(argv2, 0, sizeof(gchar *) * max_argc);
4540 argv[0] = g_strdup("mmplayer");
4543 for (i = 0; i < 5; i++) {
4544 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4545 if (strlen(player->ini.gst_param[i]) > 0) {
4546 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4551 /* we would not do fork for scanning plugins */
4552 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4555 /* check disable registry scan */
4556 if (player->ini.skip_rescan) {
4557 argv[*argc] = g_strdup("--gst-disable-registry-update");
4561 /* check disable segtrap */
4562 if (player->ini.disable_segtrap) {
4563 argv[*argc] = g_strdup("--gst-disable-segtrap");
4567 LOGD("initializing gstreamer with following parameter");
4568 LOGD("argc : %d", *argc);
4571 for (i = 0; i < arg_count; i++) {
4573 LOGD("argv[%d] : %s", i, argv2[i]);
4576 /* initializing gstreamer */
4577 if (!gst_init_check(argc, &argv, &err)) {
4578 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4585 for (i = 0; i < arg_count; i++) {
4586 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4587 MMPLAYER_FREEIF(argv2[i]);
4590 MMPLAYER_FREEIF(argv);
4591 MMPLAYER_FREEIF(argv2);
4592 MMPLAYER_FREEIF(argc);
4602 for (i = 0; i < arg_count; i++) {
4603 LOGD("free[%d] : %s", i, argv2[i]);
4604 MMPLAYER_FREEIF(argv2[i]);
4607 MMPLAYER_FREEIF(argv);
4608 MMPLAYER_FREEIF(argv2);
4609 MMPLAYER_FREEIF(argc);
4615 __mmplayer_check_async_state_transition(mm_player_t *player)
4617 GstState element_state = GST_STATE_VOID_PENDING;
4618 GstState element_pending_state = GST_STATE_VOID_PENDING;
4619 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4620 GstElement *element = NULL;
4621 gboolean async = FALSE;
4623 /* check player handle */
4624 MMPLAYER_RETURN_IF_FAIL(player &&
4626 player->pipeline->mainbin &&
4627 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4630 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4632 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4633 LOGD("don't need to check the pipeline state");
4637 MMPLAYER_PRINT_STATE(player);
4639 /* wait for state transition */
4640 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4641 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4643 if (ret == GST_STATE_CHANGE_FAILURE) {
4644 LOGE(" [%s] state : %s pending : %s",
4645 GST_ELEMENT_NAME(element),
4646 gst_element_state_get_name(element_state),
4647 gst_element_state_get_name(element_pending_state));
4649 /* dump state of all element */
4650 __mmplayer_dump_pipeline_state(player);
4655 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4660 _mmplayer_destroy(MMHandleType handle)
4662 mm_player_t *player = MM_PLAYER_CAST(handle);
4666 /* check player handle */
4667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4669 /* destroy can called at anytime */
4670 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4672 /* check async state transition */
4673 __mmplayer_check_async_state_transition(player);
4675 /* release gapless play thread */
4676 if (player->gapless_play_thread) {
4677 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4678 player->gapless_play_thread_exit = TRUE;
4679 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4680 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4682 LOGD("waitting for gapless play thread exit");
4683 g_thread_join(player->gapless_play_thread);
4684 g_mutex_clear(&player->gapless_play_thread_mutex);
4685 g_cond_clear(&player->gapless_play_thread_cond);
4686 LOGD("gapless play thread released");
4689 _mmplayer_release_video_capture(player);
4691 /* de-initialize resource manager */
4692 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4693 player->resource_manager))
4694 LOGE("failed to deinitialize resource manager");
4696 /* release pipeline */
4697 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4698 LOGE("failed to destory pipeline");
4699 return MM_ERROR_PLAYER_INTERNAL;
4702 g_queue_free(player->bus_msg_q);
4704 /* release subtitle info lock and cond */
4705 g_mutex_clear(&player->subtitle_info_mutex);
4706 g_cond_clear(&player->subtitle_info_cond);
4708 __mmplayer_release_dump_list(player->dump_list);
4710 /* release miscellaneous information */
4711 __mmplayer_release_misc(player);
4713 /* release miscellaneous information.
4714 these info needs to be released after pipeline is destroyed. */
4715 __mmplayer_release_misc_post(player);
4717 /* release attributes */
4718 _mmplayer_deconstruct_attribute(handle);
4721 g_mutex_clear(&player->fsink_lock);
4724 g_mutex_clear(&player->update_tag_lock);
4726 /* release video bo lock and cond */
4727 g_mutex_clear(&player->video_bo_mutex);
4728 g_cond_clear(&player->video_bo_cond);
4730 /* release media stream callback lock */
4731 g_mutex_clear(&player->media_stream_cb_lock);
4735 return MM_ERROR_NONE;
4739 _mmplayer_realize(MMHandleType hplayer)
4741 mm_player_t *player = (mm_player_t *)hplayer;
4744 MMHandleType attrs = 0;
4745 int ret = MM_ERROR_NONE;
4749 /* check player handle */
4750 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4752 /* check current state */
4753 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4755 attrs = MMPLAYER_GET_ATTRS(player);
4757 LOGE("fail to get attributes.");
4758 return MM_ERROR_PLAYER_INTERNAL;
4760 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4761 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4763 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4764 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4766 if (ret != MM_ERROR_NONE) {
4767 LOGE("failed to parse profile");
4772 if (uri && (strstr(uri, "es_buff://"))) {
4773 if (strstr(uri, "es_buff://push_mode"))
4774 player->es_player_push_mode = TRUE;
4776 player->es_player_push_mode = FALSE;
4779 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4780 LOGW("mms protocol is not supported format.");
4781 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4784 if (MMPLAYER_IS_STREAMING(player))
4785 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4787 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4789 player->smooth_streaming = FALSE;
4790 player->videodec_linked = 0;
4791 player->audiodec_linked = 0;
4792 player->textsink_linked = 0;
4793 player->is_external_subtitle_present = FALSE;
4794 player->is_external_subtitle_added_now = FALSE;
4795 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4796 player->video360_metadata.is_spherical = -1;
4797 player->is_openal_plugin_used = FALSE;
4798 player->demux_pad_index = 0;
4799 player->subtitle_language_list = NULL;
4800 player->is_subtitle_force_drop = FALSE;
4801 player->last_multiwin_status = FALSE;
4803 __mmplayer_track_initialize(player);
4804 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4806 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4807 gint prebuffer_ms = 0, rebuffer_ms = 0;
4809 player->streamer = __mm_player_streaming_create();
4810 __mm_player_streaming_initialize(player->streamer, TRUE);
4812 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4813 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4815 if (prebuffer_ms > 0) {
4816 prebuffer_ms = MAX(prebuffer_ms, 1000);
4817 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4820 if (rebuffer_ms > 0) {
4821 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4822 rebuffer_ms = MAX(rebuffer_ms, 1000);
4823 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4826 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4827 player->streamer->buffering_req.rebuffer_time);
4830 /* realize pipeline */
4831 ret = __mmplayer_gst_realize(player);
4832 if (ret != MM_ERROR_NONE)
4833 LOGE("fail to realize the player.");
4835 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4843 _mmplayer_unrealize(MMHandleType hplayer)
4845 mm_player_t *player = (mm_player_t *)hplayer;
4846 int ret = MM_ERROR_NONE;
4850 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4852 MMPLAYER_CMD_UNLOCK(player);
4853 /* destroy the gst bus msg thread which is created during realize.
4854 this funct have to be called before getting cmd lock. */
4855 __mmplayer_bus_msg_thread_destroy(player);
4856 MMPLAYER_CMD_LOCK(player);
4858 /* check current state */
4859 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4861 /* check async state transition */
4862 __mmplayer_check_async_state_transition(player);
4864 /* unrealize pipeline */
4865 ret = __mmplayer_gst_unrealize(player);
4867 /* set asm stop if success */
4868 if (MM_ERROR_NONE == ret) {
4869 if (!player->interrupted_by_resource) {
4870 if (player->video_decoder_resource != NULL) {
4871 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4872 player->video_decoder_resource);
4873 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4874 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4876 player->video_decoder_resource = NULL;
4879 if (player->video_overlay_resource != NULL) {
4880 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4881 player->video_overlay_resource);
4882 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4883 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4885 player->video_overlay_resource = NULL;
4888 ret = mm_resource_manager_commit(player->resource_manager);
4889 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4890 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4893 LOGE("failed and don't change asm state to stop");
4901 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4903 mm_player_t *player = (mm_player_t *)hplayer;
4905 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4907 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4911 _mmplayer_get_state(MMHandleType hplayer, int *state)
4913 mm_player_t *player = (mm_player_t *)hplayer;
4915 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4917 *state = MMPLAYER_CURRENT_STATE(player);
4919 return MM_ERROR_NONE;
4924 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4926 mm_player_t *player = (mm_player_t *)hplayer;
4927 GstElement *vol_element = NULL;
4932 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4934 LOGD("volume [L]=%f:[R]=%f",
4935 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4937 /* invalid factor range or not */
4938 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4939 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4940 LOGE("Invalid factor!(valid factor:0~1.0)");
4941 return MM_ERROR_INVALID_ARGUMENT;
4945 /* not support to set other value into each channel */
4946 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4947 return MM_ERROR_INVALID_ARGUMENT;
4949 /* Save volume to handle. Currently the first array element will be saved. */
4950 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4952 /* check pipeline handle */
4953 if (!player->pipeline || !player->pipeline->audiobin) {
4954 LOGD("audiobin is not created yet");
4955 LOGD("but, current stored volume will be set when it's created.");
4957 /* NOTE : stored volume will be used in create_audiobin
4958 * returning MM_ERROR_NONE here makes application to able to
4959 * set volume at anytime.
4961 return MM_ERROR_NONE;
4964 /* setting volume to volume element */
4965 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4968 LOGD("volume is set [%f]", player->sound.volume);
4969 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4974 return MM_ERROR_NONE;
4978 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
4980 mm_player_t *player = (mm_player_t *)hplayer;
4985 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4986 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4988 /* returning stored volume */
4989 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4990 volume->level[i] = player->sound.volume;
4994 return MM_ERROR_NONE;
4998 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5000 mm_player_t *player = (mm_player_t *)hplayer;
5001 GstElement *vol_element = NULL;
5005 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5007 /* mute value shoud 0 or 1 */
5008 if (mute != 0 && mute != 1) {
5009 LOGE("bad mute value");
5011 /* FIXIT : definitly, we need _BAD_PARAM error code */
5012 return MM_ERROR_INVALID_ARGUMENT;
5015 player->sound.mute = mute;
5017 /* just hold mute value if pipeline is not ready */
5018 if (!player->pipeline || !player->pipeline->audiobin) {
5019 LOGD("pipeline is not ready. holding mute value");
5020 return MM_ERROR_NONE;
5023 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5025 /* NOTE : volume will only created when the bt is enabled */
5027 LOGD("mute : %d", mute);
5028 g_object_set(vol_element, "mute", mute, NULL);
5030 LOGD("volume elemnet is not created. using volume in audiosink");
5034 return MM_ERROR_NONE;
5038 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5040 mm_player_t *player = (mm_player_t *)hplayer;
5044 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5045 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5047 /* just hold mute value if pipeline is not ready */
5048 if (!player->pipeline || !player->pipeline->audiobin) {
5049 LOGD("pipeline is not ready. returning stored value");
5050 *pmute = player->sound.mute;
5051 return MM_ERROR_NONE;
5054 *pmute = player->sound.mute;
5058 return MM_ERROR_NONE;
5062 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5064 mm_player_t *player = (mm_player_t *)hplayer;
5068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5070 player->video_stream_changed_cb = callback;
5071 player->video_stream_changed_cb_user_param = user_param;
5072 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5076 return MM_ERROR_NONE;
5080 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5082 mm_player_t *player = (mm_player_t *)hplayer;
5086 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5088 player->audio_stream_changed_cb = callback;
5089 player->audio_stream_changed_cb_user_param = user_param;
5090 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5094 return MM_ERROR_NONE;
5098 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5100 mm_player_t *player = (mm_player_t *)hplayer;
5104 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106 player->audio_stream_render_cb = callback;
5107 player->audio_stream_cb_user_param = user_param;
5108 player->audio_stream_sink_sync = sync;
5109 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5113 return MM_ERROR_NONE;
5117 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5119 mm_player_t *player = (mm_player_t *)hplayer;
5123 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5125 if (callback && !player->bufmgr)
5126 player->bufmgr = tbm_bufmgr_init(-1);
5128 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5129 player->video_stream_cb = callback;
5130 player->video_stream_cb_user_param = user_param;
5132 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5136 return MM_ERROR_NONE;
5140 _mmplayer_start(MMHandleType hplayer)
5142 mm_player_t *player = (mm_player_t *)hplayer;
5143 gint ret = MM_ERROR_NONE;
5147 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 /* check current state */
5150 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5152 /* start pipeline */
5153 ret = __mmplayer_gst_start(player);
5154 if (ret != MM_ERROR_NONE)
5155 LOGE("failed to start player.");
5157 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5158 LOGD("force playing start even during buffering");
5159 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5167 /* NOTE: post "not supported codec message" to application
5168 * when one codec is not found during AUTOPLUGGING in MSL.
5169 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5170 * And, if any codec is not found, don't send message here.
5171 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5174 __mmplayer_handle_missed_plugin(mm_player_t *player)
5176 MMMessageParamType msg_param;
5177 memset(&msg_param, 0, sizeof(MMMessageParamType));
5178 gboolean post_msg_direct = FALSE;
5182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5184 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5185 player->not_supported_codec, player->can_support_codec);
5187 if (player->not_found_demuxer) {
5188 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5189 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5191 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5192 MMPLAYER_FREEIF(msg_param.data);
5194 return MM_ERROR_NONE;
5197 if (player->not_supported_codec) {
5198 if (player->can_support_codec) {
5199 // There is one codec to play
5200 post_msg_direct = TRUE;
5202 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5203 post_msg_direct = TRUE;
5206 if (post_msg_direct) {
5207 MMMessageParamType msg_param;
5208 memset(&msg_param, 0, sizeof(MMMessageParamType));
5210 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5211 LOGW("not found AUDIO codec, posting error code to application.");
5213 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5214 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5215 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5216 LOGW("not found VIDEO codec, posting error code to application.");
5218 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5219 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5222 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5224 MMPLAYER_FREEIF(msg_param.data);
5226 return MM_ERROR_NONE;
5228 // no any supported codec case
5229 LOGW("not found any codec, posting error code to application.");
5231 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5232 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5233 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5235 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5236 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5239 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5241 MMPLAYER_FREEIF(msg_param.data);
5247 return MM_ERROR_NONE;
5251 __mmplayer_check_pipeline(mm_player_t *player)
5253 GstState element_state = GST_STATE_VOID_PENDING;
5254 GstState element_pending_state = GST_STATE_VOID_PENDING;
5256 int ret = MM_ERROR_NONE;
5258 if (!player->gapless.reconfigure)
5261 LOGW("pipeline is under construction.");
5263 MMPLAYER_PLAYBACK_LOCK(player);
5264 MMPLAYER_PLAYBACK_UNLOCK(player);
5266 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5268 /* wait for state transition */
5269 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5270 if (ret == GST_STATE_CHANGE_FAILURE)
5271 LOGE("failed to change pipeline state within %d sec", timeout);
5274 /* NOTE : it should be able to call 'stop' anytime*/
5276 _mmplayer_stop(MMHandleType hplayer)
5278 mm_player_t *player = (mm_player_t *)hplayer;
5279 int ret = MM_ERROR_NONE;
5283 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5285 /* check current state */
5286 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5288 /* check pipline building state */
5289 __mmplayer_check_pipeline(player);
5290 __mmplayer_reset_gapless_state(player);
5292 /* NOTE : application should not wait for EOS after calling STOP */
5293 __mmplayer_cancel_eos_timer(player);
5296 player->seek_state = MMPLAYER_SEEK_NONE;
5299 ret = __mmplayer_gst_stop(player);
5301 if (ret != MM_ERROR_NONE)
5302 LOGE("failed to stop player.");
5310 _mmplayer_pause(MMHandleType hplayer)
5312 mm_player_t *player = (mm_player_t *)hplayer;
5313 gint64 pos_nsec = 0;
5314 gboolean async = FALSE;
5315 gint ret = MM_ERROR_NONE;
5319 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5321 /* check current state */
5322 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5324 /* check pipline building state */
5325 __mmplayer_check_pipeline(player);
5327 switch (MMPLAYER_CURRENT_STATE(player)) {
5328 case MM_PLAYER_STATE_READY:
5330 /* check prepare async or not.
5331 * In the case of streaming playback, it's recommned to avoid blocking wait.
5333 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5334 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5336 /* Changing back sync of rtspsrc to async */
5337 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5338 LOGD("async prepare working mode for rtsp");
5344 case MM_PLAYER_STATE_PLAYING:
5346 /* NOTE : store current point to overcome some bad operation
5347 *(returning zero when getting current position in paused state) of some
5350 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5351 LOGW("getting current position failed in paused");
5353 player->last_position = pos_nsec;
5355 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5356 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5357 This causes problem is position calculation during normal pause resume scenarios also.
5358 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5359 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5360 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5361 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5367 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5368 LOGD("doing async pause in case of ms buff src");
5372 /* pause pipeline */
5373 ret = __mmplayer_gst_pause(player, async);
5375 if (ret != MM_ERROR_NONE)
5376 LOGE("failed to pause player. ret : 0x%x", ret);
5378 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5379 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5380 LOGE("failed to update display_rotation");
5388 /* in case of streaming, pause could take long time.*/
5390 _mmplayer_abort_pause(MMHandleType hplayer)
5392 mm_player_t *player = (mm_player_t *)hplayer;
5393 int ret = MM_ERROR_NONE;
5397 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5399 player->pipeline->mainbin,
5400 MM_ERROR_PLAYER_NOT_INITIALIZED);
5402 LOGD("set the pipeline state to READY");
5404 /* set state to READY */
5405 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5406 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5407 if (ret != MM_ERROR_NONE) {
5408 LOGE("fail to change state to READY");
5409 return MM_ERROR_PLAYER_INTERNAL;
5412 LOGD("succeeded in changing state to READY");
5417 _mmplayer_resume(MMHandleType hplayer)
5419 mm_player_t *player = (mm_player_t *)hplayer;
5420 int ret = MM_ERROR_NONE;
5421 gboolean async = FALSE;
5425 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5427 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5428 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5429 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5433 /* Changing back sync mode rtspsrc to async */
5434 LOGD("async resume for rtsp case");
5438 /* check current state */
5439 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5441 ret = __mmplayer_gst_resume(player, async);
5442 if (ret != MM_ERROR_NONE)
5443 LOGE("failed to resume player.");
5445 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5446 LOGD("force resume even during buffering");
5447 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5456 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5458 mm_player_t *player = (mm_player_t *)hplayer;
5459 gint64 pos_nsec = 0;
5460 int ret = MM_ERROR_NONE;
5462 signed long long start = 0, stop = 0;
5463 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5466 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5467 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5469 /* The sound of video is not supported under 0.0 and over 2.0. */
5470 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5471 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5474 _mmplayer_set_mute(hplayer, mute);
5476 if (player->playback_rate == rate)
5477 return MM_ERROR_NONE;
5479 /* If the position is reached at start potion during fast backward, EOS is posted.
5480 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5482 player->playback_rate = rate;
5484 current_state = MMPLAYER_CURRENT_STATE(player);
5486 if (current_state != MM_PLAYER_STATE_PAUSED)
5487 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5489 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5491 if ((current_state == MM_PLAYER_STATE_PAUSED)
5492 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5493 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5494 pos_nsec = player->last_position;
5499 stop = GST_CLOCK_TIME_NONE;
5501 start = GST_CLOCK_TIME_NONE;
5505 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5506 player->playback_rate,
5508 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5509 GST_SEEK_TYPE_SET, start,
5510 GST_SEEK_TYPE_SET, stop)) {
5511 LOGE("failed to set speed playback");
5512 return MM_ERROR_PLAYER_SEEK;
5515 LOGD("succeeded to set speed playback as %0.1f", rate);
5519 return MM_ERROR_NONE;;
5523 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5525 mm_player_t *player = (mm_player_t *)hplayer;
5526 int ret = MM_ERROR_NONE;
5530 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5532 /* check pipline building state */
5533 __mmplayer_check_pipeline(player);
5535 ret = __mmplayer_gst_set_position(player, position, FALSE);
5543 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5545 mm_player_t *player = (mm_player_t *)hplayer;
5546 int ret = MM_ERROR_NONE;
5548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5550 ret = __mmplayer_gst_get_position(player, position);
5556 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5558 mm_player_t *player = (mm_player_t *)hplayer;
5559 int ret = MM_ERROR_NONE;
5561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5562 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5564 if (g_strrstr(player->type, "video/mpegts"))
5565 __mmplayer_update_duration_value(player);
5567 *duration = player->duration;
5572 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5574 mm_player_t *player = (mm_player_t *)hplayer;
5575 int ret = MM_ERROR_NONE;
5577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5579 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5585 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5587 mm_player_t *player = (mm_player_t *)hplayer;
5588 int ret = MM_ERROR_NONE;
5592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5594 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5602 __mmplayer_is_midi_type(gchar *str_caps)
5604 if ((g_strrstr(str_caps, "audio/midi")) ||
5605 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5606 (g_strrstr(str_caps, "application/x-smaf")) ||
5607 (g_strrstr(str_caps, "audio/x-imelody")) ||
5608 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5609 (g_strrstr(str_caps, "audio/xmf")) ||
5610 (g_strrstr(str_caps, "audio/mxmf"))) {
5619 __mmplayer_is_only_mp3_type(gchar *str_caps)
5621 if (g_strrstr(str_caps, "application/x-id3") ||
5622 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5628 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5630 GstStructure *caps_structure = NULL;
5631 gint samplerate = 0;
5635 MMPLAYER_RETURN_IF_FAIL(player && caps);
5637 caps_structure = gst_caps_get_structure(caps, 0);
5639 /* set stream information */
5640 gst_structure_get_int(caps_structure, "rate", &samplerate);
5641 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5643 gst_structure_get_int(caps_structure, "channels", &channels);
5644 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5646 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5650 __mmplayer_update_content_type_info(mm_player_t *player)
5653 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5655 if (__mmplayer_is_midi_type(player->type)) {
5656 player->bypass_audio_effect = TRUE;
5660 if (!player->streamer) {
5661 LOGD("no need to check streaming type");
5665 if (g_strrstr(player->type, "application/x-hls")) {
5666 /* If it can't know exact type when it parses uri because of redirection case,
5667 * it will be fixed by typefinder or when doing autoplugging.
5669 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5670 player->streamer->is_adaptive_streaming = TRUE;
5671 } else if (g_strrstr(player->type, "application/dash+xml")) {
5672 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5673 player->streamer->is_adaptive_streaming = TRUE;
5676 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5677 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5678 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5680 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5681 if (player->streamer->is_adaptive_streaming)
5682 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5684 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5688 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5693 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5694 GstCaps *caps, gpointer data)
5696 mm_player_t *player = (mm_player_t *)data;
5701 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5703 /* store type string */
5704 MMPLAYER_FREEIF(player->type);
5705 player->type = gst_caps_to_string(caps);
5707 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5708 player, player->type, probability, gst_caps_get_size(caps));
5710 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5711 (g_strrstr(player->type, "audio/x-raw-int"))) {
5712 LOGE("not support media format");
5714 if (player->msg_posted == FALSE) {
5715 MMMessageParamType msg_param;
5716 memset(&msg_param, 0, sizeof(MMMessageParamType));
5718 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5719 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5721 /* don't post more if one was sent already */
5722 player->msg_posted = TRUE;
5727 __mmplayer_update_content_type_info(player);
5729 pad = gst_element_get_static_pad(tf, "src");
5731 LOGE("fail to get typefind src pad.");
5735 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5736 gboolean async = FALSE;
5737 LOGE("failed to autoplug %s", player->type);
5739 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5741 if (async && player->msg_posted == FALSE)
5742 __mmplayer_handle_missed_plugin(player);
5748 gst_object_unref(GST_OBJECT(pad));
5756 __mmplayer_gst_make_decodebin(mm_player_t *player)
5758 GstElement *decodebin = NULL;
5762 /* create decodebin */
5763 decodebin = gst_element_factory_make("decodebin", NULL);
5766 LOGE("fail to create decodebin");
5770 /* raw pad handling signal */
5771 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5772 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5774 /* no-more-pad pad handling signal */
5775 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5776 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5778 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5779 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5781 /* This signal is emitted when a pad for which there is no further possible
5782 decoding is added to the decodebin.*/
5783 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5784 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5786 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5787 before looking for any elements that can handle that stream.*/
5788 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5789 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5791 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5792 before looking for any elements that can handle that stream.*/
5793 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5794 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5796 /* This signal is emitted once decodebin has finished decoding all the data.*/
5797 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5798 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5800 /* This signal is emitted when a element is added to the bin.*/
5801 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5802 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5809 __mmplayer_gst_make_queue2(mm_player_t *player)
5811 GstElement *queue2 = NULL;
5812 gint64 dur_bytes = 0L;
5813 MMPlayerGstElement *mainbin = NULL;
5814 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5817 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5819 mainbin = player->pipeline->mainbin;
5821 queue2 = gst_element_factory_make("queue2", "queue2");
5823 LOGE("failed to create buffering queue element");
5827 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5828 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5830 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5832 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5833 * skip the pull mode(file or ring buffering) setting. */
5834 if (dur_bytes > 0) {
5835 if (!g_strrstr(player->type, "video/mpegts")) {
5836 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5837 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5843 __mm_player_streaming_set_queue2(player->streamer,
5847 (guint64)dur_bytes); /* no meaning at the moment */
5853 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5855 MMPlayerGstElement *mainbin = NULL;
5856 GstElement *decodebin = NULL;
5857 GstElement *queue2 = NULL;
5858 GstPad *sinkpad = NULL;
5859 GstPad *qsrcpad = NULL;
5862 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5864 mainbin = player->pipeline->mainbin;
5866 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5868 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5869 LOGW("need to check: muxed buffer is not null");
5872 queue2 = __mmplayer_gst_make_queue2(player);
5874 LOGE("failed to make queue2");
5878 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5879 LOGE("failed to add buffering queue");
5883 sinkpad = gst_element_get_static_pad(queue2, "sink");
5884 qsrcpad = gst_element_get_static_pad(queue2, "src");
5886 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5887 LOGE("failed to link [%s:%s]-[%s:%s]",
5888 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5892 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5893 LOGE("failed to sync queue2 state with parent");
5897 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5898 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5902 gst_object_unref(GST_OBJECT(sinkpad));
5906 /* create decodebin */
5907 decodebin = __mmplayer_gst_make_decodebin(player);
5909 LOGE("failed to make decodebin");
5913 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5914 LOGE("failed to add decodebin");
5918 /* to force caps on the decodebin element and avoid reparsing stuff by
5919 * typefind. It also avoids a deadlock in the way typefind activates pads in
5920 * the state change */
5921 g_object_set(decodebin, "sink-caps", caps, NULL);
5923 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5925 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5926 LOGE("failed to link [%s:%s]-[%s:%s]",
5927 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5931 gst_object_unref(GST_OBJECT(sinkpad));
5934 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5935 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5937 /* set decodebin property about buffer in streaming playback. *
5938 * in case of HLS/DASH, it does not need to have big buffer *
5939 * because it is kind of adaptive streaming. */
5940 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5941 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5942 gint high_percent = 0;
5944 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5945 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5947 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5949 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5951 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5952 "high-percent", high_percent,
5953 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
5954 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
5955 "max-size-buffers", 0, NULL); // disable or automatic
5958 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
5959 LOGE("failed to sync decodebin state with parent");
5970 gst_object_unref(GST_OBJECT(sinkpad));
5973 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5974 * You need to explicitly set elements to the NULL state before
5975 * dropping the final reference, to allow them to clean up.
5977 gst_element_set_state(queue2, GST_STATE_NULL);
5979 /* And, it still has a parent "player".
5980 * You need to let the parent manage the object instead of unreffing the object directly.
5982 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5983 gst_object_unref(queue2);
5988 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5989 * You need to explicitly set elements to the NULL state before
5990 * dropping the final reference, to allow them to clean up.
5992 gst_element_set_state(decodebin, GST_STATE_NULL);
5994 /* And, it still has a parent "player".
5995 * You need to let the parent manage the object instead of unreffing the object directly.
5998 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5999 gst_object_unref(decodebin);
6007 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6011 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6012 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6014 LOGD("class : %s, mime : %s", factory_class, mime);
6016 /* add missing plugin */
6017 /* NOTE : msl should check missing plugin for image mime type.
6018 * Some motion jpeg clips can have playable audio track.
6019 * So, msl have to play audio after displaying popup written video format not supported.
6021 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6022 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6023 LOGD("not found demuxer");
6024 player->not_found_demuxer = TRUE;
6025 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6031 if (!g_strrstr(factory_class, "Demuxer")) {
6032 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6033 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6034 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6036 /* check that clip have multi tracks or not */
6037 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6038 LOGD("video plugin is already linked");
6040 LOGW("add VIDEO to missing plugin");
6041 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6042 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6044 } else if (g_str_has_prefix(mime, "audio")) {
6045 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6046 LOGD("audio plugin is already linked");
6048 LOGW("add AUDIO to missing plugin");
6049 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6050 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6058 return MM_ERROR_NONE;
6062 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6064 mm_player_t *player = (mm_player_t *)data;
6068 MMPLAYER_RETURN_IF_FAIL(player);
6070 /* remove fakesink. */
6071 if (!__mmplayer_gst_remove_fakesink(player,
6072 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6073 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6074 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6075 * source element are not same. To overcome this situation, this function will called
6076 * several places and several times. Therefore, this is not an error case.
6081 LOGD("[handle: %p] pipeline has completely constructed", player);
6083 if ((player->ini.async_start) &&
6084 (player->msg_posted == FALSE) &&
6085 (player->cmd >= MMPLAYER_COMMAND_START))
6086 __mmplayer_handle_missed_plugin(player);
6088 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6092 __mmplayer_check_profile(void)
6095 static int profile_tv = -1;
6097 if (__builtin_expect(profile_tv != -1, 1))
6100 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6101 switch (*profileName) {
6116 __mmplayer_get_next_uri(mm_player_t *player)
6118 MMPlayerParseProfile profile;
6120 guint num_of_list = 0;
6123 num_of_list = g_list_length(player->uri_info.uri_list);
6124 uri_idx = player->uri_info.uri_idx;
6126 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6127 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6128 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6130 LOGW("next uri does not exist");
6134 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6135 LOGE("failed to parse profile");
6139 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6140 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6141 LOGW("uri type is not supported(%d)", profile.uri_type);
6145 LOGD("success to find next uri %d", uri_idx);
6149 if (uri_idx == num_of_list) {
6150 LOGE("failed to find next uri");
6154 player->uri_info.uri_idx = uri_idx;
6155 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6157 if (mm_attrs_commit_all(player->attrs)) {
6158 LOGE("failed to commit");
6162 SECURE_LOGD("next playback uri: %s", uri);
6167 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6169 #define REPEAT_COUNT_INFINITELY -1
6170 #define REPEAT_COUNT_MIN 2
6172 MMHandleType attrs = 0;
6176 guint num_of_list = 0;
6177 int profile_tv = -1;
6181 LOGD("checking for gapless play option");
6183 if (player->pipeline->textbin) {
6184 LOGE("subtitle path is enabled. gapless play is not supported.");
6188 attrs = MMPLAYER_GET_ATTRS(player);
6190 LOGE("fail to get attributes.");
6194 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6196 /* gapless playback is not supported in case of video at TV profile. */
6197 profile_tv = __mmplayer_check_profile();
6198 if (profile_tv && video) {
6199 LOGW("not support video gapless playback");
6203 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6204 LOGE("failed to get play count");
6206 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6207 LOGE("failed to get gapless mode");
6209 /* check repeat count in case of audio */
6211 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6212 LOGW("gapless is disabled");
6216 num_of_list = g_list_length(player->uri_info.uri_list);
6218 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6220 if (num_of_list == 0) {
6221 /* audio looping path */
6222 if (count >= REPEAT_COUNT_MIN) {
6223 /* decrease play count */
6224 /* we succeeded to rewind. update play count and then wait for next EOS */
6226 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6227 /* commit attribute */
6228 if (mm_attrs_commit_all(attrs))
6229 LOGE("failed to commit attribute");
6231 } else if (count != REPEAT_COUNT_INFINITELY) {
6232 LOGD("there is no next uri and no repeat");
6235 LOGD("looping cnt %d", count);
6237 /* gapless playback path */
6238 if (!__mmplayer_get_next_uri(player)) {
6239 LOGE("failed to get next uri");
6246 LOGE("unable to play gapless path. EOS will be posted soon");
6251 __mmplayer_initialize_gapless_play(mm_player_t *player)
6257 player->smooth_streaming = FALSE;
6258 player->videodec_linked = 0;
6259 player->audiodec_linked = 0;
6260 player->textsink_linked = 0;
6261 player->is_external_subtitle_present = FALSE;
6262 player->is_external_subtitle_added_now = FALSE;
6263 player->not_supported_codec = MISSING_PLUGIN_NONE;
6264 player->can_support_codec = FOUND_PLUGIN_NONE;
6265 player->pending_seek.is_pending = false;
6266 player->pending_seek.pos = 0;
6267 player->msg_posted = FALSE;
6268 player->has_many_types = FALSE;
6269 player->no_more_pad = FALSE;
6270 player->not_found_demuxer = 0;
6271 player->seek_state = MMPLAYER_SEEK_NONE;
6272 player->is_subtitle_force_drop = FALSE;
6273 player->play_subtitle = FALSE;
6274 player->adjust_subtitle_pos = 0;
6276 player->total_bitrate = 0;
6277 player->total_maximum_bitrate = 0;
6279 __mmplayer_track_initialize(player);
6280 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6282 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6283 player->bitrate[i] = 0;
6284 player->maximum_bitrate[i] = 0;
6287 if (player->v_stream_caps) {
6288 gst_caps_unref(player->v_stream_caps);
6289 player->v_stream_caps = NULL;
6292 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6294 /* clean found parsers */
6295 if (player->parsers) {
6296 GList *parsers = player->parsers;
6297 for (; parsers; parsers = g_list_next(parsers)) {
6298 gchar *name = parsers->data;
6299 MMPLAYER_FREEIF(name);
6301 g_list_free(player->parsers);
6302 player->parsers = NULL;
6305 /* clean found audio decoders */
6306 if (player->audio_decoders) {
6307 GList *a_dec = player->audio_decoders;
6308 for (; a_dec; a_dec = g_list_next(a_dec)) {
6309 gchar *name = a_dec->data;
6310 MMPLAYER_FREEIF(name);
6312 g_list_free(player->audio_decoders);
6313 player->audio_decoders = NULL;
6320 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6322 MMPlayerGstElement *mainbin = NULL;
6323 MMMessageParamType msg_param = {0,};
6324 GstElement *element = NULL;
6325 MMHandleType attrs = 0;
6327 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6331 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6332 LOGE("player is not initialized");
6336 mainbin = player->pipeline->mainbin;
6337 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6339 attrs = MMPLAYER_GET_ATTRS(player);
6341 LOGE("fail to get attributes");
6345 /* Initialize Player values */
6346 __mmplayer_initialize_gapless_play(player);
6348 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6350 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6351 LOGE("failed to parse profile");
6352 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6356 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6357 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6358 LOGE("dash or hls is not supportable");
6359 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6363 element = __mmplayer_gst_create_source(player);
6365 LOGE("no source element was created");
6369 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6370 LOGE("failed to add source element to pipeline");
6371 gst_object_unref(GST_OBJECT(element));
6376 /* take source element */
6377 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6378 mainbin[MMPLAYER_M_SRC].gst = element;
6382 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6383 if (player->streamer == NULL) {
6384 player->streamer = __mm_player_streaming_create();
6385 __mm_player_streaming_initialize(player->streamer, TRUE);
6388 elem_idx = MMPLAYER_M_TYPEFIND;
6389 element = gst_element_factory_make("typefind", "typefinder");
6390 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6391 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6393 elem_idx = MMPLAYER_M_AUTOPLUG;
6394 element = __mmplayer_gst_make_decodebin(player);
6397 /* check autoplug element is OK */
6399 LOGE("can not create element(%d)", elem_idx);
6403 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6404 LOGE("failed to add sinkbin to pipeline");
6405 gst_object_unref(GST_OBJECT(element));
6410 mainbin[elem_idx].id = elem_idx;
6411 mainbin[elem_idx].gst = element;
6413 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6414 LOGE("Failed to link src - autoplug(or typefind)");
6418 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6419 LOGE("Failed to change state of src element");
6423 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6424 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6425 LOGE("Failed to change state of decodebin");
6429 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6430 LOGE("Failed to change state of src element");
6435 player->gapless.stream_changed = TRUE;
6436 player->gapless.running = TRUE;
6442 MMPLAYER_PLAYBACK_UNLOCK(player);
6444 if (!player->msg_posted) {
6445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6446 player->msg_posted = TRUE;
6453 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6455 mm_player_selector_t *selector = &player->selector[type];
6456 MMPlayerGstElement *sinkbin = NULL;
6457 enum MainElementID selectorId = MMPLAYER_M_NUM;
6458 enum MainElementID sinkId = MMPLAYER_M_NUM;
6459 GstPad *srcpad = NULL;
6460 GstPad *sinkpad = NULL;
6461 gboolean send_notice = FALSE;
6464 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6466 LOGD("type %d", type);
6469 case MM_PLAYER_TRACK_TYPE_AUDIO:
6470 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6471 sinkId = MMPLAYER_A_BIN;
6472 sinkbin = player->pipeline->audiobin;
6474 case MM_PLAYER_TRACK_TYPE_VIDEO:
6475 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6476 sinkId = MMPLAYER_V_BIN;
6477 sinkbin = player->pipeline->videobin;
6480 case MM_PLAYER_TRACK_TYPE_TEXT:
6481 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6482 sinkId = MMPLAYER_T_BIN;
6483 sinkbin = player->pipeline->textbin;
6486 LOGE("requested type is not supportable");
6491 if (player->pipeline->mainbin[selectorId].gst) {
6494 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6496 if (selector->event_probe_id != 0)
6497 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6498 selector->event_probe_id = 0;
6500 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6501 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6503 if (srcpad && sinkpad) {
6504 /* after getting drained signal there is no data flows, so no need to do pad_block */
6505 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6506 gst_pad_unlink(srcpad, sinkpad);
6508 /* send custom event to sink pad to handle it at video sink */
6510 LOGD("send custom event to sinkpad");
6511 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6512 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6513 gst_pad_send_event(sinkpad, event);
6517 gst_object_unref(sinkpad);
6520 gst_object_unref(srcpad);
6523 LOGD("selector release");
6525 /* release and unref requests pad from the selector */
6526 for (n = 0; n < selector->channels->len; n++) {
6527 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6528 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6530 g_ptr_array_set_size(selector->channels, 0);
6532 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6533 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6535 player->pipeline->mainbin[selectorId].gst = NULL;
6543 __mmplayer_deactivate_old_path(mm_player_t *player)
6546 MMPLAYER_RETURN_IF_FAIL(player);
6548 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6549 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6550 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6551 LOGE("deactivate selector error");
6555 __mmplayer_track_destroy(player);
6556 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6558 if (player->streamer) {
6559 __mm_player_streaming_initialize(player->streamer, FALSE);
6560 __mm_player_streaming_destroy(player->streamer);
6561 player->streamer = NULL;
6564 MMPLAYER_PLAYBACK_LOCK(player);
6565 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6572 if (!player->msg_posted) {
6573 MMMessageParamType msg = {0,};
6576 msg.code = MM_ERROR_PLAYER_INTERNAL;
6577 LOGE("gapless_uri_play> deactivate error");
6579 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6580 player->msg_posted = TRUE;
6586 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6588 int result = MM_ERROR_NONE;
6589 mm_player_t *player = (mm_player_t *)hplayer;
6592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6594 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6595 if (mm_attrs_commit_all(player->attrs)) {
6596 LOGE("failed to commit the original uri.");
6597 result = MM_ERROR_PLAYER_INTERNAL;
6599 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6600 LOGE("failed to add the original uri in the uri list.");
6608 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6610 mm_player_t *player = (mm_player_t *)hplayer;
6611 guint num_of_list = 0;
6615 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6616 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6618 if (player->pipeline && player->pipeline->textbin) {
6619 LOGE("subtitle path is enabled.");
6620 return MM_ERROR_PLAYER_INVALID_STATE;
6623 num_of_list = g_list_length(player->uri_info.uri_list);
6625 if (is_first_path) {
6626 if (num_of_list == 0) {
6627 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6628 LOGD("add original path : %s", uri);
6630 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6631 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6633 LOGD("change original path : %s", uri);
6636 MMHandleType attrs = 0;
6637 attrs = MMPLAYER_GET_ATTRS(player);
6639 if (num_of_list == 0) {
6640 char *original_uri = NULL;
6643 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6645 if (!original_uri) {
6646 LOGE("there is no original uri.");
6647 return MM_ERROR_PLAYER_INVALID_STATE;
6650 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6651 player->uri_info.uri_idx = 0;
6653 LOGD("add original path at first : %s", original_uri);
6657 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6658 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6662 return MM_ERROR_NONE;
6666 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6668 mm_player_t *player = (mm_player_t *)hplayer;
6669 char *next_uri = NULL;
6670 guint num_of_list = 0;
6673 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6675 num_of_list = g_list_length(player->uri_info.uri_list);
6677 if (num_of_list > 0) {
6678 gint uri_idx = player->uri_info.uri_idx;
6680 if (uri_idx < num_of_list-1)
6685 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6686 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6688 *uri = g_strdup(next_uri);
6692 return MM_ERROR_NONE;
6696 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6697 GstCaps *caps, gpointer data)
6699 mm_player_t *player = (mm_player_t *)data;
6700 const gchar *klass = NULL;
6701 const gchar *mime = NULL;
6702 gchar *caps_str = NULL;
6704 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6705 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6706 caps_str = gst_caps_to_string(caps);
6708 LOGW("unknown type of caps : %s from %s",
6709 caps_str, GST_ELEMENT_NAME(elem));
6711 MMPLAYER_FREEIF(caps_str);
6713 /* There is no available codec. */
6714 __mmplayer_check_not_supported_codec(player, klass, mime);
6718 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6719 GstCaps *caps, gpointer data)
6721 mm_player_t *player = (mm_player_t *)data;
6722 const char *mime = NULL;
6723 gboolean ret = TRUE;
6725 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6726 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6728 if (g_str_has_prefix(mime, "audio")) {
6729 GstStructure *caps_structure = NULL;
6730 gint samplerate = 0;
6732 gchar *caps_str = NULL;
6734 caps_structure = gst_caps_get_structure(caps, 0);
6735 gst_structure_get_int(caps_structure, "rate", &samplerate);
6736 gst_structure_get_int(caps_structure, "channels", &channels);
6738 if ((channels > 0 && samplerate == 0)) {
6739 LOGD("exclude audio...");
6743 caps_str = gst_caps_to_string(caps);
6744 /* set it directly because not sent by TAG */
6745 if (g_strrstr(caps_str, "mobile-xmf"))
6746 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6747 MMPLAYER_FREEIF(caps_str);
6748 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6749 MMMessageParamType msg_param;
6750 memset(&msg_param, 0, sizeof(MMMessageParamType));
6751 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6752 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6753 LOGD("video file is not supported on this device");
6755 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6756 LOGD("already video linked");
6759 LOGD("found new stream");
6766 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6768 int ret = MM_ERROR_NONE;
6770 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6772 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6773 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6775 LOGD("audio codec type: %d", codec_type);
6776 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6777 /* sw codec will be skipped */
6778 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6779 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6780 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6781 ret = MM_ERROR_PLAYER_INTERNAL;
6785 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6786 /* hw codec will be skipped */
6787 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6788 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6789 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6790 ret = MM_ERROR_PLAYER_INTERNAL;
6795 /* set stream information */
6796 if (!player->audiodec_linked)
6797 __mmplayer_set_audio_attrs(player, caps);
6799 /* update codec info */
6800 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6801 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6802 player->audiodec_linked = 1;
6804 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6806 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6808 LOGD("video codec type: %d", codec_type);
6809 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6810 /* sw codec is skipped */
6811 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6812 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6813 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6814 ret = MM_ERROR_PLAYER_INTERNAL;
6818 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6819 /* hw codec is skipped */
6820 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6821 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6822 ret = MM_ERROR_PLAYER_INTERNAL;
6827 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6828 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6830 /* mark video decoder for acquire */
6831 if (player->video_decoder_resource == NULL) {
6832 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6833 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6834 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6835 &player->video_decoder_resource)
6836 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6837 LOGE("could not mark video_decoder resource for acquire");
6838 ret = MM_ERROR_PLAYER_INTERNAL;
6842 LOGW("video decoder resource is already acquired, skip it.");
6843 ret = MM_ERROR_PLAYER_INTERNAL;
6847 player->interrupted_by_resource = FALSE;
6848 /* acquire resources for video playing */
6849 if (mm_resource_manager_commit(player->resource_manager)
6850 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6851 LOGE("could not acquire resources for video decoding");
6852 ret = MM_ERROR_PLAYER_INTERNAL;
6857 /* update codec info */
6858 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6859 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6860 player->videodec_linked = 1;
6868 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6869 GstCaps *caps, GstElementFactory *factory, gpointer data)
6871 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6872 We are defining our own and will be removed when it actually exposed */
6874 GST_AUTOPLUG_SELECT_TRY,
6875 GST_AUTOPLUG_SELECT_EXPOSE,
6876 GST_AUTOPLUG_SELECT_SKIP
6877 } GstAutoplugSelectResult;
6879 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6880 mm_player_t *player = (mm_player_t *)data;
6882 gchar *factory_name = NULL;
6883 gchar *caps_str = NULL;
6884 const gchar *klass = NULL;
6887 factory_name = GST_OBJECT_NAME(factory);
6888 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6889 caps_str = gst_caps_to_string(caps);
6891 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6893 /* store type string */
6894 if (player->type == NULL) {
6895 player->type = gst_caps_to_string(caps);
6896 __mmplayer_update_content_type_info(player);
6899 /* filtering exclude keyword */
6900 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6901 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6902 LOGW("skipping [%s] by exculde keyword [%s]",
6903 factory_name, player->ini.exclude_element_keyword[idx]);
6905 result = GST_AUTOPLUG_SELECT_SKIP;
6910 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6911 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6912 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6913 factory_name, player->ini.unsupported_codec_keyword[idx]);
6914 result = GST_AUTOPLUG_SELECT_SKIP;
6919 /* exclude webm format */
6920 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6921 * because webm format is not supportable.
6922 * If webm is disabled in "autoplug-continue", there is no state change
6923 * failure or error because the decodebin will expose the pad directly.
6924 * It make MSL invoke _prepare_async_callback.
6925 * So, we need to disable webm format in "autoplug-select" */
6926 if (caps_str && strstr(caps_str, "webm")) {
6927 LOGW("webm is not supported");
6928 result = GST_AUTOPLUG_SELECT_SKIP;
6932 /* check factory class for filtering */
6933 /* NOTE : msl don't need to use image plugins.
6934 * So, those plugins should be skipped for error handling.
6936 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6937 LOGD("skipping [%s] by not required", factory_name);
6938 result = GST_AUTOPLUG_SELECT_SKIP;
6942 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6943 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6944 // TO CHECK : subtitle if needed, add subparse exception.
6945 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
6946 result = GST_AUTOPLUG_SELECT_SKIP;
6950 if (g_strrstr(factory_name, "mpegpsdemux")) {
6951 LOGD("skipping PS container - not support");
6952 result = GST_AUTOPLUG_SELECT_SKIP;
6956 if (g_strrstr(factory_name, "mssdemux"))
6957 player->smooth_streaming = TRUE;
6959 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6960 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6963 GstStructure *str = NULL;
6964 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6966 /* don't make video because of not required */
6967 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6968 (!player->set_mode.media_packet_video_stream)) {
6969 LOGD("no need video decoding, expose pad");
6970 result = GST_AUTOPLUG_SELECT_EXPOSE;
6974 /* get w/h for omx state-tune */
6975 /* FIXME: deprecated? */
6976 str = gst_caps_get_structure(caps, 0);
6977 gst_structure_get_int(str, "width", &width);
6980 if (player->v_stream_caps) {
6981 gst_caps_unref(player->v_stream_caps);
6982 player->v_stream_caps = NULL;
6985 player->v_stream_caps = gst_caps_copy(caps);
6986 LOGD("take caps for video state tune");
6987 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
6991 if (g_strrstr(klass, "Codec/Decoder")) {
6992 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
6993 LOGD("skipping %s codec", factory_name);
6994 result = GST_AUTOPLUG_SELECT_SKIP;
7000 MMPLAYER_FREEIF(caps_str);
7006 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7009 //mm_player_t *player = (mm_player_t *)data;
7010 GstCaps *caps = NULL;
7012 LOGD("[Decodebin2] pad-removed signal");
7014 caps = gst_pad_query_caps(new_pad, NULL);
7016 LOGW("query caps is NULL");
7020 gchar *caps_str = NULL;
7021 caps_str = gst_caps_to_string(caps);
7023 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7025 MMPLAYER_FREEIF(caps_str);
7026 gst_caps_unref(caps);
7030 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7032 mm_player_t *player = (mm_player_t *)data;
7033 GstIterator *iter = NULL;
7034 GValue item = { 0, };
7036 gboolean done = FALSE;
7037 gboolean is_all_drained = TRUE;
7040 MMPLAYER_RETURN_IF_FAIL(player);
7042 LOGD("__mmplayer_gst_decode_drained");
7044 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7045 LOGW("Fail to get cmd lock");
7049 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7050 !__mmplayer_verify_gapless_play_path(player)) {
7051 LOGD("decoding is finished.");
7052 __mmplayer_reset_gapless_state(player);
7053 MMPLAYER_CMD_UNLOCK(player);
7057 player->gapless.reconfigure = TRUE;
7059 /* check decodebin src pads whether they received EOS or not */
7060 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7063 switch (gst_iterator_next(iter, &item)) {
7064 case GST_ITERATOR_OK:
7065 pad = g_value_get_object(&item);
7066 if (pad && !GST_PAD_IS_EOS(pad)) {
7067 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7068 is_all_drained = FALSE;
7071 g_value_reset(&item);
7073 case GST_ITERATOR_RESYNC:
7074 gst_iterator_resync(iter);
7076 case GST_ITERATOR_ERROR:
7077 case GST_ITERATOR_DONE:
7082 g_value_unset(&item);
7083 gst_iterator_free(iter);
7085 if (!is_all_drained) {
7086 LOGD("Wait util the all pads get EOS.");
7087 MMPLAYER_CMD_UNLOCK(player);
7092 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7093 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7095 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7096 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7097 __mmplayer_deactivate_old_path(player);
7098 MMPLAYER_CMD_UNLOCK(player);
7104 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7106 mm_player_t *player = (mm_player_t *)data;
7107 const gchar *klass = NULL;
7108 gchar *factory_name = NULL;
7110 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7111 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7113 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7115 if (__mmplayer_add_dump_buffer_probe(player, element))
7116 LOGD("add buffer probe");
7119 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7120 gchar *selected = NULL;
7121 selected = g_strdup(GST_ELEMENT_NAME(element));
7122 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7126 if (g_strrstr(klass, "Parser")) {
7127 gchar *selected = NULL;
7129 selected = g_strdup(factory_name);
7130 player->parsers = g_list_append(player->parsers, selected);
7133 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7134 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7135 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7137 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7138 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7140 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7141 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7142 "max-video-width", player->adaptive_info.limit.width,
7143 "max-video-height", player->adaptive_info.limit.height, NULL);
7145 } else if (g_strrstr(klass, "Demuxer")) {
7146 //LOGD("plugged element is demuxer. take it");
7147 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7148 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7151 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7152 int surface_type = 0;
7154 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7157 // to support trust-zone only
7158 if (g_strrstr(factory_name, "asfdemux")) {
7159 LOGD("set file-location %s", player->profile.uri);
7160 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7161 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7162 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7163 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7164 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7165 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7166 (__mmplayer_is_only_mp3_type(player->type))) {
7167 LOGD("[mpegaudioparse] set streaming pull mode.");
7168 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7170 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7171 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7174 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7175 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7176 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7178 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7179 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7181 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7182 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7183 (MMPLAYER_IS_DASH_STREAMING(player))) {
7184 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7185 __mm_player_streaming_set_multiqueue(player->streamer, element);
7186 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7195 __mmplayer_release_misc(mm_player_t *player)
7198 bool cur_mode = player->set_mode.rich_audio;
7201 MMPLAYER_RETURN_IF_FAIL(player);
7203 player->video_stream_cb = NULL;
7204 player->video_stream_cb_user_param = NULL;
7205 player->video_stream_prerolled = false;
7207 player->audio_stream_render_cb = NULL;
7208 player->audio_stream_cb_user_param = NULL;
7209 player->audio_stream_sink_sync = false;
7211 player->video_stream_changed_cb = NULL;
7212 player->video_stream_changed_cb_user_param = NULL;
7214 player->audio_stream_changed_cb = NULL;
7215 player->audio_stream_changed_cb_user_param = NULL;
7217 player->sent_bos = FALSE;
7218 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7220 player->seek_state = MMPLAYER_SEEK_NONE;
7222 player->total_bitrate = 0;
7223 player->total_maximum_bitrate = 0;
7225 player->not_found_demuxer = 0;
7227 player->last_position = 0;
7228 player->duration = 0;
7229 player->http_content_size = 0;
7230 player->not_supported_codec = MISSING_PLUGIN_NONE;
7231 player->can_support_codec = FOUND_PLUGIN_NONE;
7232 player->pending_seek.is_pending = false;
7233 player->pending_seek.pos = 0;
7234 player->msg_posted = FALSE;
7235 player->has_many_types = FALSE;
7236 player->is_subtitle_force_drop = FALSE;
7237 player->play_subtitle = FALSE;
7238 player->adjust_subtitle_pos = 0;
7239 player->last_multiwin_status = FALSE;
7240 player->has_closed_caption = FALSE;
7241 player->set_mode.media_packet_video_stream = false;
7242 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7243 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7245 player->set_mode.rich_audio = cur_mode;
7247 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7248 player->bitrate[i] = 0;
7249 player->maximum_bitrate[i] = 0;
7252 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7254 /* remove media stream cb(appsrc cb) */
7255 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7256 player->media_stream_buffer_status_cb[i] = NULL;
7257 player->media_stream_seek_data_cb[i] = NULL;
7258 player->buffer_cb_user_param[i] = NULL;
7259 player->seek_cb_user_param[i] = NULL;
7261 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7263 /* free memory related to audio effect */
7264 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7266 if (player->adaptive_info.var_list) {
7267 g_list_free_full(player->adaptive_info.var_list, g_free);
7268 player->adaptive_info.var_list = NULL;
7271 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7272 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7273 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7275 /* Reset video360 settings to their defaults in case if the pipeline is to be
7278 player->video360_metadata.is_spherical = -1;
7279 player->is_openal_plugin_used = FALSE;
7281 player->is_content_spherical = FALSE;
7282 player->is_video360_enabled = TRUE;
7283 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7284 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7285 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7286 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7287 player->video360_zoom = 1.0f;
7288 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7289 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7291 player->sound.rg_enable = false;
7293 __mmplayer_initialize_video_roi(player);
7298 __mmplayer_release_misc_post(mm_player_t *player)
7300 char *original_uri = NULL;
7303 /* player->pipeline is already released before. */
7305 MMPLAYER_RETURN_IF_FAIL(player);
7307 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7309 /* clean found parsers */
7310 if (player->parsers) {
7311 GList *parsers = player->parsers;
7312 for (; parsers; parsers = g_list_next(parsers)) {
7313 gchar *name = parsers->data;
7314 MMPLAYER_FREEIF(name);
7316 g_list_free(player->parsers);
7317 player->parsers = NULL;
7320 /* clean found audio decoders */
7321 if (player->audio_decoders) {
7322 GList *a_dec = player->audio_decoders;
7323 for (; a_dec; a_dec = g_list_next(a_dec)) {
7324 gchar *name = a_dec->data;
7325 MMPLAYER_FREEIF(name);
7327 g_list_free(player->audio_decoders);
7328 player->audio_decoders = NULL;
7331 /* clean the uri list except original uri */
7332 if (player->uri_info.uri_list) {
7333 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7335 if (player->attrs) {
7336 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7337 LOGD("restore original uri = %s", original_uri);
7339 if (mm_attrs_commit_all(player->attrs))
7340 LOGE("failed to commit the original uri.");
7343 GList *uri_list = player->uri_info.uri_list;
7344 for (; uri_list; uri_list = g_list_next(uri_list)) {
7345 gchar *uri = uri_list->data;
7346 MMPLAYER_FREEIF(uri);
7348 g_list_free(player->uri_info.uri_list);
7349 player->uri_info.uri_list = NULL;
7352 /* clear the audio stream buffer list */
7353 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7355 /* clear the video stream bo list */
7356 __mmplayer_video_stream_destroy_bo_list(player);
7357 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7359 if (player->profile.input_mem.buf) {
7360 free(player->profile.input_mem.buf);
7361 player->profile.input_mem.buf = NULL;
7363 player->profile.input_mem.len = 0;
7364 player->profile.input_mem.offset = 0;
7366 player->uri_info.uri_idx = 0;
7371 __mmplayer_check_subtitle(mm_player_t *player)
7373 MMHandleType attrs = 0;
7374 char *subtitle_uri = NULL;
7378 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7380 /* get subtitle attribute */
7381 attrs = MMPLAYER_GET_ATTRS(player);
7385 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7386 if (!subtitle_uri || !strlen(subtitle_uri))
7389 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7390 player->is_external_subtitle_present = TRUE;
7398 __mmplayer_cancel_eos_timer(mm_player_t *player)
7400 MMPLAYER_RETURN_IF_FAIL(player);
7402 if (player->eos_timer) {
7403 LOGD("cancel eos timer");
7404 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7405 player->eos_timer = 0;
7412 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7416 MMPLAYER_RETURN_IF_FAIL(player);
7417 MMPLAYER_RETURN_IF_FAIL(sink);
7419 player->sink_elements = g_list_append(player->sink_elements, sink);
7425 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7429 MMPLAYER_RETURN_IF_FAIL(player);
7430 MMPLAYER_RETURN_IF_FAIL(sink);
7432 player->sink_elements = g_list_remove(player->sink_elements, sink);
7438 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7439 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7441 MMPlayerSignalItem *item = NULL;
7444 MMPLAYER_RETURN_IF_FAIL(player);
7446 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7447 LOGE("invalid signal type [%d]", type);
7451 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7453 LOGE("cannot connect signal [%s]", signal);
7458 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7459 player->signals[type] = g_list_append(player->signals[type], item);
7465 /* NOTE : be careful with calling this api. please refer to below glib comment
7466 * glib comment : Note that there is a bug in GObject that makes this function much
7467 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7468 * will no longer be called, but, the signal handler is not currently disconnected.
7469 * If the instance is itself being freed at the same time than this doesn't matter,
7470 * since the signal will automatically be removed, but if instance persists,
7471 * then the signal handler will leak. You should not remove the signal yourself
7472 * because in a future versions of GObject, the handler will automatically be
7475 * It's possible to work around this problem in a way that will continue to work
7476 * with future versions of GObject by checking that the signal handler is still
7477 * connected before disconnected it:
7479 * if (g_signal_handler_is_connected(instance, id))
7480 * g_signal_handler_disconnect(instance, id);
7483 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7485 GList *sig_list = NULL;
7486 MMPlayerSignalItem *item = NULL;
7490 MMPLAYER_RETURN_IF_FAIL(player);
7492 LOGD("release signals type : %d", type);
7494 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7495 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7496 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7497 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7498 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7499 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7503 sig_list = player->signals[type];
7505 for (; sig_list; sig_list = sig_list->next) {
7506 item = sig_list->data;
7508 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7509 if (g_signal_handler_is_connected(item->obj, item->sig))
7510 g_signal_handler_disconnect(item->obj, item->sig);
7513 MMPLAYER_FREEIF(item);
7516 g_list_free(player->signals[type]);
7517 player->signals[type] = NULL;
7525 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7527 mm_player_t *player = 0;
7528 int prev_display_surface_type = 0;
7529 void *prev_display_overlay = NULL;
7533 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7534 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7536 player = MM_PLAYER_CAST(handle);
7538 /* check video sinkbin is created */
7539 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7540 LOGE("Videosink is already created");
7541 return MM_ERROR_NONE;
7544 LOGD("videosink element is not yet ready");
7546 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7547 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7549 return MM_ERROR_INVALID_ARGUMENT;
7552 /* load previous attributes */
7553 if (player->attrs) {
7554 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7555 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7556 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7557 if (prev_display_surface_type == surface_type) {
7558 LOGD("incoming display surface type is same as previous one, do nothing..");
7560 return MM_ERROR_NONE;
7563 LOGE("failed to load attributes");
7565 return MM_ERROR_PLAYER_INTERNAL;
7568 /* videobin is not created yet, so we just set attributes related to display surface */
7569 LOGD("store display attribute for given surface type(%d)", surface_type);
7570 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7571 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7572 if (mm_attrs_commit_all(player->attrs)) {
7573 LOGE("failed to commit attribute");
7575 return MM_ERROR_PLAYER_INTERNAL;
7579 return MM_ERROR_NONE;
7582 /* Note : if silent is true, then subtitle would not be displayed. :*/
7584 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7586 mm_player_t *player = (mm_player_t *)hplayer;
7590 /* check player handle */
7591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7593 player->set_mode.subtitle_off = silent;
7595 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7599 return MM_ERROR_NONE;
7603 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7605 MMPlayerGstElement *mainbin = NULL;
7606 MMPlayerGstElement *textbin = NULL;
7607 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7608 GstState current_state = GST_STATE_VOID_PENDING;
7609 GstState element_state = GST_STATE_VOID_PENDING;
7610 GstState element_pending_state = GST_STATE_VOID_PENDING;
7612 GstEvent *event = NULL;
7613 int result = MM_ERROR_NONE;
7615 GstClock *curr_clock = NULL;
7616 GstClockTime base_time, start_time, curr_time;
7621 /* check player handle */
7622 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7624 player->pipeline->mainbin &&
7625 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7627 mainbin = player->pipeline->mainbin;
7628 textbin = player->pipeline->textbin;
7630 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7632 // sync clock with current pipeline
7633 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7634 curr_time = gst_clock_get_time(curr_clock);
7636 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7637 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7639 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7640 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7642 if (current_state > GST_STATE_READY) {
7643 // sync state with current pipeline
7644 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7645 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7646 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7648 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7649 if (GST_STATE_CHANGE_FAILURE == ret) {
7650 LOGE("fail to state change.");
7651 result = MM_ERROR_PLAYER_INTERNAL;
7655 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7656 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7659 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7660 gst_object_unref(curr_clock);
7663 // seek to current position
7664 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7665 result = MM_ERROR_PLAYER_INVALID_STATE;
7666 LOGE("gst_element_query_position failed, invalid state");
7670 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7671 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);
7673 __mmplayer_gst_send_event_to_sink(player, event);
7675 result = MM_ERROR_PLAYER_INTERNAL;
7676 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7680 /* sync state with current pipeline */
7681 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7682 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7683 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7685 return MM_ERROR_NONE;
7688 /* release text pipeline resource */
7689 player->textsink_linked = 0;
7691 /* release signal */
7692 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7694 /* release textbin with it's childs */
7695 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7696 MMPLAYER_FREEIF(player->pipeline->textbin);
7697 player->pipeline->textbin = NULL;
7699 /* release subtitle elem */
7700 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7701 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7707 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7709 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7710 GstState current_state = GST_STATE_VOID_PENDING;
7712 MMHandleType attrs = 0;
7713 MMPlayerGstElement *mainbin = NULL;
7714 MMPlayerGstElement *textbin = NULL;
7716 gchar *subtitle_uri = NULL;
7717 int result = MM_ERROR_NONE;
7718 const gchar *charset = NULL;
7722 /* check player handle */
7723 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7725 player->pipeline->mainbin &&
7726 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7727 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7729 mainbin = player->pipeline->mainbin;
7730 textbin = player->pipeline->textbin;
7732 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7733 if (current_state < GST_STATE_READY) {
7734 result = MM_ERROR_PLAYER_INVALID_STATE;
7735 LOGE("Pipeline is not in proper state");
7739 attrs = MMPLAYER_GET_ATTRS(player);
7741 LOGE("cannot get content attribute");
7742 result = MM_ERROR_PLAYER_INTERNAL;
7746 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7747 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7748 LOGE("subtitle uri is not proper filepath");
7749 result = MM_ERROR_PLAYER_INVALID_URI;
7753 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7754 LOGE("failed to get storage info of subtitle path");
7755 result = MM_ERROR_PLAYER_INVALID_URI;
7759 LOGD("old subtitle file path is [%s]", subtitle_uri);
7760 LOGD("new subtitle file path is [%s]", filepath);
7762 if (!strcmp(filepath, subtitle_uri)) {
7763 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7766 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7767 if (mm_attrs_commit_all(player->attrs)) {
7768 LOGE("failed to commit.");
7773 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7774 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7775 player->subtitle_language_list = NULL;
7776 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7778 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7779 if (ret != GST_STATE_CHANGE_SUCCESS) {
7780 LOGE("failed to change state of textbin to READY");
7781 result = MM_ERROR_PLAYER_INTERNAL;
7785 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7786 if (ret != GST_STATE_CHANGE_SUCCESS) {
7787 LOGE("failed to change state of subparse to READY");
7788 result = MM_ERROR_PLAYER_INTERNAL;
7792 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7793 if (ret != GST_STATE_CHANGE_SUCCESS) {
7794 LOGE("failed to change state of filesrc to READY");
7795 result = MM_ERROR_PLAYER_INTERNAL;
7799 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7801 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7803 charset = util_get_charset(filepath);
7805 LOGD("detected charset is %s", charset);
7806 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7809 result = _mmplayer_sync_subtitle_pipeline(player);
7816 /* API to switch between external subtitles */
7818 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7820 int result = MM_ERROR_NONE;
7821 mm_player_t *player = (mm_player_t *)hplayer;
7826 /* check player handle */
7827 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7829 /* filepath can be null in idle state */
7831 /* check file path */
7832 if ((path = strstr(filepath, "file://")))
7833 result = util_exist_file_path(path + 7);
7835 result = util_exist_file_path(filepath);
7837 if (result != MM_ERROR_NONE) {
7838 LOGE("invalid subtitle path 0x%X", result);
7839 return result; /* file not found or permission denied */
7843 if (!player->pipeline) {
7845 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7846 if (mm_attrs_commit_all(player->attrs)) {
7847 LOGE("failed to commit"); /* subtitle path will not be created */
7848 return MM_ERROR_PLAYER_INTERNAL;
7851 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7852 /* check filepath */
7853 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7855 if (!__mmplayer_check_subtitle(player)) {
7856 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7857 if (mm_attrs_commit_all(player->attrs)) {
7858 LOGE("failed to commit");
7859 return MM_ERROR_PLAYER_INTERNAL;
7862 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7863 LOGE("fail to create text pipeline");
7864 return MM_ERROR_PLAYER_INTERNAL;
7867 result = _mmplayer_sync_subtitle_pipeline(player);
7869 result = __mmplayer_change_external_subtitle_language(player, filepath);
7872 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7873 player->is_external_subtitle_added_now = TRUE;
7875 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7876 if (!player->subtitle_language_list) {
7877 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7878 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7879 LOGW("subtitle language list is not updated yet");
7881 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7889 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7891 int result = MM_ERROR_NONE;
7892 gchar *change_pad_name = NULL;
7893 GstPad *sinkpad = NULL;
7894 MMPlayerGstElement *mainbin = NULL;
7895 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7896 GstCaps *caps = NULL;
7897 gint total_track_num = 0;
7901 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7902 MM_ERROR_PLAYER_NOT_INITIALIZED);
7904 LOGD("Change Track(%d) to %d", type, index);
7906 mainbin = player->pipeline->mainbin;
7908 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7909 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7910 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7911 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7913 /* Changing Video Track is not supported. */
7914 LOGE("Track Type Error");
7918 if (mainbin[elem_idx].gst == NULL) {
7919 result = MM_ERROR_PLAYER_NO_OP;
7920 LOGD("Req track doesn't exist");
7924 total_track_num = player->selector[type].total_track_num;
7925 if (total_track_num <= 0) {
7926 result = MM_ERROR_PLAYER_NO_OP;
7927 LOGD("Language list is not available");
7931 if ((index < 0) || (index >= total_track_num)) {
7932 result = MM_ERROR_INVALID_ARGUMENT;
7933 LOGD("Not a proper index : %d", index);
7937 /*To get the new pad from the selector*/
7938 change_pad_name = g_strdup_printf("sink_%u", index);
7939 if (change_pad_name == NULL) {
7940 result = MM_ERROR_PLAYER_INTERNAL;
7941 LOGD("Pad does not exists");
7945 LOGD("new active pad name: %s", change_pad_name);
7947 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7948 if (sinkpad == NULL) {
7949 LOGD("sinkpad is NULL");
7950 result = MM_ERROR_PLAYER_INTERNAL;
7954 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
7955 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7957 caps = gst_pad_get_current_caps(sinkpad);
7958 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7961 gst_object_unref(sinkpad);
7963 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7964 __mmplayer_set_audio_attrs(player, caps);
7967 MMPLAYER_FREEIF(change_pad_name);
7972 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7974 int result = MM_ERROR_NONE;
7975 mm_player_t *player = NULL;
7976 MMPlayerGstElement *mainbin = NULL;
7978 gint current_active_index = 0;
7980 GstState current_state = GST_STATE_VOID_PENDING;
7981 GstEvent *event = NULL;
7986 player = (mm_player_t *)hplayer;
7987 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7989 if (!player->pipeline) {
7990 LOGE("Track %d pre setting -> %d", type, index);
7992 player->selector[type].active_pad_index = index;
7996 mainbin = player->pipeline->mainbin;
7998 current_active_index = player->selector[type].active_pad_index;
8000 /*If index is same as running index no need to change the pad*/
8001 if (current_active_index == index)
8004 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8005 result = MM_ERROR_PLAYER_INVALID_STATE;
8009 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8010 if (current_state < GST_STATE_PAUSED) {
8011 result = MM_ERROR_PLAYER_INVALID_STATE;
8012 LOGW("Pipeline not in porper state");
8016 result = __mmplayer_change_selector_pad(player, type, index);
8017 if (result != MM_ERROR_NONE) {
8018 LOGE("change selector pad error");
8022 player->selector[type].active_pad_index = index;
8024 if (current_state == GST_STATE_PLAYING) {
8025 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8026 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8027 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8029 __mmplayer_gst_send_event_to_sink(player, event);
8031 result = MM_ERROR_PLAYER_INTERNAL;
8041 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8043 mm_player_t *player = (mm_player_t *)hplayer;
8047 /* check player handle */
8048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8050 *silent = player->set_mode.subtitle_off;
8052 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8056 return MM_ERROR_NONE;
8060 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8062 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8063 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8065 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8066 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8070 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8071 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8072 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8073 mm_player_dump_t *dump_s;
8074 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8075 if (dump_s == NULL) {
8076 LOGE("malloc fail");
8080 dump_s->dump_element_file = NULL;
8081 dump_s->dump_pad = NULL;
8082 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8084 if (dump_s->dump_pad) {
8085 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8086 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]);
8087 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8088 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);
8089 /* add list for removed buffer probe and close FILE */
8090 player->dump_list = g_list_append(player->dump_list, dump_s);
8091 LOGD("%s sink pad added buffer probe for dump", factory_name);
8094 MMPLAYER_FREEIF(dump_s);
8095 LOGE("failed to get %s sink pad added", factory_name);
8102 static GstPadProbeReturn
8103 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8105 FILE *dump_data = (FILE *)u_data;
8107 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8108 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8110 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8112 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8114 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8116 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8118 return GST_PAD_PROBE_OK;
8122 __mmplayer_release_dump_list(GList *dump_list)
8124 GList *d_list = dump_list;
8129 for (; d_list; d_list = g_list_next(d_list)) {
8130 mm_player_dump_t *dump_s = d_list->data;
8131 if (dump_s->dump_pad) {
8132 if (dump_s->probe_handle_id)
8133 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8135 if (dump_s->dump_element_file) {
8136 fclose(dump_s->dump_element_file);
8137 dump_s->dump_element_file = NULL;
8139 MMPLAYER_FREEIF(dump_s);
8141 g_list_free(dump_list);
8146 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8148 mm_player_t *player = (mm_player_t *)hplayer;
8152 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8153 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8155 *exist = (bool)player->has_closed_caption;
8159 return MM_ERROR_NONE;
8163 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8167 // LOGD("unref internal gst buffer %p", buffer);
8168 gst_buffer_unref((GstBuffer *)buffer);
8175 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8177 mm_player_t *player = (mm_player_t *)hplayer;
8181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8182 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8184 if (MMPLAYER_IS_STREAMING(player))
8185 *timeout = (int)player->ini.live_state_change_timeout;
8187 *timeout = (int)player->ini.localplayback_state_change_timeout;
8189 LOGD("timeout = %d", *timeout);
8192 return MM_ERROR_NONE;
8196 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8198 mm_player_t *player = (mm_player_t *)hplayer;
8202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8203 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8205 *num = player->video_num_buffers;
8206 *extra_num = player->video_extra_num_buffers;
8208 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8211 return MM_ERROR_NONE;
8215 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8219 MMPLAYER_RETURN_IF_FAIL(player);
8221 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8223 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8224 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8225 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8226 player->storage_info[i].id = -1;
8227 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8229 if (path_type != MMPLAYER_PATH_MAX)
8238 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8240 int ret = MM_ERROR_NONE;
8241 mm_player_t *player = (mm_player_t *)hplayer;
8242 MMMessageParamType msg_param = {0, };
8245 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8247 LOGW("state changed storage %d:%d", id, state);
8249 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8250 return MM_ERROR_NONE;
8252 /* FIXME: text path should be handled seperately. */
8253 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8254 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8255 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8256 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8257 LOGW("external storage is removed");
8259 if (player->msg_posted == FALSE) {
8260 memset(&msg_param, 0, sizeof(MMMessageParamType));
8261 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8262 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8263 player->msg_posted = TRUE;
8266 /* unrealize the player */
8267 ret = _mmplayer_unrealize(hplayer);
8268 if (ret != MM_ERROR_NONE)
8269 LOGE("failed to unrealize");
8277 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8279 int ret = MM_ERROR_NONE;
8280 mm_player_t *player = (mm_player_t *)hplayer;
8281 int idx = 0, total = 0;
8282 gchar *result = NULL, *tmp = NULL;
8285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8286 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8288 total = *num = g_list_length(player->adaptive_info.var_list);
8290 LOGW("There is no stream variant info.");
8294 result = g_strdup("");
8295 for (idx = 0 ; idx < total ; idx++) {
8296 VariantData *v_data = NULL;
8297 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8300 gchar data[64] = {0};
8301 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8303 tmp = g_strconcat(result, data, NULL);
8307 LOGW("There is no variant data in %d", idx);
8312 *var_info = (char *)result;
8314 LOGD("variant info %d:%s", *num, *var_info);
8320 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8322 int ret = MM_ERROR_NONE;
8323 mm_player_t *player = (mm_player_t *)hplayer;
8326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8328 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8330 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8331 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8332 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8334 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8335 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8336 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8337 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8339 /* FIXME: seek to current position for applying new variant limitation */
8348 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8350 int ret = MM_ERROR_NONE;
8351 mm_player_t *player = (mm_player_t *)hplayer;
8354 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8355 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8357 *bandwidth = player->adaptive_info.limit.bandwidth;
8358 *width = player->adaptive_info.limit.width;
8359 *height = player->adaptive_info.limit.height;
8361 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8368 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8370 int ret = MM_ERROR_NONE;
8371 mm_player_t *player = (mm_player_t *)hplayer;
8372 MMHandleType attrs = 0;
8375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8376 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8378 attrs = MMPLAYER_GET_ATTRS(player);
8379 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8381 mm_attrs_get_int_by_name(attrs, MM_PLAYER_PREBUFFER_MS, prebuffer_ms);
8382 mm_attrs_get_int_by_name(attrs, MM_PLAYER_REBUFFER_MS, rebuffer_ms);
8384 LOGD("attr buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8386 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8387 /* set the platform default (3000 ms) value */
8388 if (*prebuffer_ms <= MIN_BUFFERING_TIME)
8389 *prebuffer_ms = DEFAULT_PREBUFFERING_TIME;
8394 MMPLAYER_RETURN_VAL_IF_FAIL(player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8395 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8397 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8399 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8400 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8401 else /* live case */
8402 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8404 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8411 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8413 #define IDX_FIRST_SW_CODEC 0
8414 mm_player_t *player = (mm_player_t *)hplayer;
8415 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8416 MMHandleType attrs = 0;
8419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8421 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8422 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8423 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8425 switch (stream_type) {
8426 case MM_PLAYER_STREAM_TYPE_AUDIO:
8427 /* to support audio codec selection, codec info have to be added in ini file as below.
8428 audio codec element hw = xxxx
8429 audio codec element sw = avdec */
8430 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8431 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8432 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8433 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8434 LOGE("There is no audio codec info for codec_type %d", codec_type);
8435 return MM_ERROR_PLAYER_NO_OP;
8438 case MM_PLAYER_STREAM_TYPE_VIDEO:
8439 /* to support video codec selection, codec info have to be added in ini file as below.
8440 video codec element hw = omx
8441 video codec element sw = avdec */
8442 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8443 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8444 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8445 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8446 LOGE("There is no video codec info for codec_type %d", codec_type);
8447 return MM_ERROR_PLAYER_NO_OP;
8451 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8452 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8456 LOGD("update %s codec_type to %d", attr_name, codec_type);
8458 attrs = MMPLAYER_GET_ATTRS(player);
8459 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8461 if (mm_attrs_commit_all(player->attrs)) {
8462 LOGE("failed to commit codec_type attributes");
8463 return MM_ERROR_PLAYER_INTERNAL;
8467 return MM_ERROR_NONE;
8471 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8473 mm_player_t *player = (mm_player_t *)hplayer;
8474 GstElement *rg_vol_element = NULL;
8478 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8480 player->sound.rg_enable = enabled;
8482 /* just hold rgvolume enable value if pipeline is not ready */
8483 if (!player->pipeline || !player->pipeline->audiobin) {
8484 LOGD("pipeline is not ready. holding rgvolume enable value");
8485 return MM_ERROR_NONE;
8488 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8490 if (!rg_vol_element) {
8491 LOGD("rgvolume element is not created");
8492 return MM_ERROR_PLAYER_INTERNAL;
8496 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8498 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8502 return MM_ERROR_NONE;
8506 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8508 mm_player_t *player = (mm_player_t *)hplayer;
8509 GstElement *rg_vol_element = NULL;
8510 gboolean enable = FALSE;
8514 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8515 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8517 /* just hold enable_rg value if pipeline is not ready */
8518 if (!player->pipeline || !player->pipeline->audiobin) {
8519 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8520 *enabled = player->sound.rg_enable;
8521 return MM_ERROR_NONE;
8524 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8526 if (!rg_vol_element) {
8527 LOGD("rgvolume element is not created");
8528 return MM_ERROR_PLAYER_INTERNAL;
8531 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8532 *enabled = (bool)enable;
8536 return MM_ERROR_NONE;
8540 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8542 mm_player_t *player = (mm_player_t *)hplayer;
8543 MMHandleType attrs = 0;
8544 void *handle = NULL;
8545 int ret = MM_ERROR_NONE;
8549 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8551 attrs = MMPLAYER_GET_ATTRS(player);
8552 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8554 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8556 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8557 return MM_ERROR_PLAYER_INTERNAL;
8560 player->video_roi.scale_x = scale_x;
8561 player->video_roi.scale_y = scale_y;
8562 player->video_roi.scale_width = scale_width;
8563 player->video_roi.scale_height = scale_height;
8565 /* check video sinkbin is created */
8566 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8567 return MM_ERROR_NONE;
8569 if (!gst_video_overlay_set_video_roi_area(
8570 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8571 scale_x, scale_y, scale_width, scale_height))
8572 ret = MM_ERROR_PLAYER_INTERNAL;
8574 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8575 scale_x, scale_y, scale_width, scale_height);
8583 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8585 mm_player_t *player = (mm_player_t *)hplayer;
8586 int ret = MM_ERROR_NONE;
8590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8591 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8593 *scale_x = player->video_roi.scale_x;
8594 *scale_y = player->video_roi.scale_y;
8595 *scale_width = player->video_roi.scale_width;
8596 *scale_height = player->video_roi.scale_height;
8598 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8599 *scale_x, *scale_y, *scale_width, *scale_height);
8605 __mmplayer_update_duration_value(mm_player_t *player)
8607 gboolean ret = FALSE;
8608 gint64 dur_nsec = 0;
8609 LOGD("try to update duration");
8611 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8612 player->duration = dur_nsec;
8613 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8617 if (player->duration < 0) {
8618 LOGW("duration is Non-Initialized !!!");
8619 player->duration = 0;
8622 /* update streaming service type */
8623 player->streaming_type = __mmplayer_get_stream_service_type(player);
8625 /* check duration is OK */
8626 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8627 /* FIXIT : find another way to get duration here. */
8628 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8634 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8636 /* update audio params
8637 NOTE : We need original audio params and it can be only obtained from src pad of audio
8638 decoder. Below code only valid when we are not using 'resampler' just before
8639 'audioconverter'. */
8640 GstCaps *caps_a = NULL;
8642 gint samplerate = 0, channels = 0;
8643 GstStructure *p = NULL;
8645 LOGD("try to update audio attrs");
8647 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8648 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8650 pad = gst_element_get_static_pad(
8651 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8654 LOGW("failed to get pad from audiosink");
8658 caps_a = gst_pad_get_current_caps(pad);
8660 LOGW("not ready to get audio caps");
8661 gst_object_unref(pad);
8665 p = gst_caps_get_structure(caps_a, 0);
8667 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8669 gst_structure_get_int(p, "rate", &samplerate);
8670 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8672 gst_structure_get_int(p, "channels", &channels);
8673 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8675 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8677 gst_caps_unref(caps_a);
8678 gst_object_unref(pad);
8684 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8686 LOGD("try to update video attrs");
8688 GstCaps *caps_v = NULL;
8692 GstStructure *p = NULL;
8694 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8695 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8697 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8699 LOGD("no videosink sink pad");
8703 caps_v = gst_pad_get_current_caps(pad);
8704 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8705 if (!caps_v && player->v_stream_caps) {
8706 caps_v = player->v_stream_caps;
8707 gst_caps_ref(caps_v);
8711 LOGD("no negitiated caps from videosink");
8712 gst_object_unref(pad);
8716 p = gst_caps_get_structure(caps_v, 0);
8717 gst_structure_get_int(p, "width", &width);
8718 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8720 gst_structure_get_int(p, "height", &height);
8721 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8723 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8725 SECURE_LOGD("width : %d height : %d", width, height);
8727 gst_caps_unref(caps_v);
8728 gst_object_unref(pad);
8731 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8732 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8739 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8741 gboolean ret = FALSE;
8742 guint64 data_size = 0;
8746 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8747 if (!player->duration)
8750 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8751 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8752 if (stat(path, &sb) == 0)
8753 data_size = (guint64)sb.st_size;
8755 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8756 data_size = player->http_content_size;
8759 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8762 guint64 bitrate = 0;
8763 guint64 msec_dur = 0;
8765 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8767 bitrate = data_size * 8 * 1000 / msec_dur;
8768 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8769 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8773 LOGD("player duration is less than 0");
8777 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8778 if (player->total_bitrate) {
8779 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8788 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8790 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8791 data->uri_type = uri_type;
8795 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8797 int ret = MM_ERROR_PLAYER_INVALID_URI;
8799 char *buffer = NULL;
8800 char *seperator = strchr(path, ',');
8801 char ext[100] = {0,}, size[100] = {0,};
8804 if ((buffer = strstr(path, "ext="))) {
8805 buffer += strlen("ext=");
8807 if (strlen(buffer)) {
8808 strncpy(ext, buffer, 99);
8810 if ((seperator = strchr(ext, ','))
8811 || (seperator = strchr(ext, ' '))
8812 || (seperator = strchr(ext, '\0'))) {
8813 seperator[0] = '\0';
8818 if ((buffer = strstr(path, "size="))) {
8819 buffer += strlen("size=");
8821 if (strlen(buffer) > 0) {
8822 strncpy(size, buffer, 99);
8824 if ((seperator = strchr(size, ','))
8825 || (seperator = strchr(size, ' '))
8826 || (seperator = strchr(size, '\0'))) {
8827 seperator[0] = '\0';
8830 mem_size = atoi(size);
8835 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8837 if (mem_size && param) {
8838 if (data->input_mem.buf)
8839 free(data->input_mem.buf);
8840 data->input_mem.buf = malloc(mem_size);
8842 if (data->input_mem.buf) {
8843 memcpy(data->input_mem.buf, param, mem_size);
8844 data->input_mem.len = mem_size;
8845 ret = MM_ERROR_NONE;
8847 LOGE("failed to alloc mem %d", mem_size);
8848 ret = MM_ERROR_PLAYER_INTERNAL;
8851 data->input_mem.offset = 0;
8852 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8859 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8861 gchar *location = NULL;
8864 int ret = MM_ERROR_NONE;
8866 if ((path = strstr(uri, "file://"))) {
8867 location = g_filename_from_uri(uri, NULL, &err);
8868 if (!location || (err != NULL)) {
8869 LOGE("Invalid URI '%s' for filesrc: %s", path,
8870 (err != NULL) ? err->message : "unknown error");
8874 MMPLAYER_FREEIF(location);
8876 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8877 return MM_ERROR_PLAYER_INVALID_URI;
8879 LOGD("path from uri: %s", location);
8882 path = (location != NULL) ? (location) : ((char *)uri);
8885 ret = util_exist_file_path(path);
8887 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8888 if (ret == MM_ERROR_NONE) {
8889 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8890 if (util_is_sdp_file(path)) {
8891 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8892 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8894 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8896 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8897 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8899 LOGE("invalid uri, could not play..");
8900 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8903 MMPLAYER_FREEIF(location);
8908 static MMPlayerVideoStreamDataType *
8909 __mmplayer_create_stream_from_pad(GstPad *pad)
8911 GstCaps *caps = NULL;
8912 GstStructure *structure = NULL;
8913 unsigned int fourcc = 0;
8914 const gchar *string_format = NULL;
8915 MMPlayerVideoStreamDataType *stream = NULL;
8917 MMPixelFormatType format;
8919 caps = gst_pad_get_current_caps(pad);
8921 LOGE("Caps is NULL.");
8925 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8926 structure = gst_caps_get_structure(caps, 0);
8927 gst_structure_get_int(structure, "width", &width);
8928 gst_structure_get_int(structure, "height", &height);
8929 string_format = gst_structure_get_string(structure, "format");
8931 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8932 format = util_get_pixtype(fourcc);
8933 gst_caps_unref(caps);
8936 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8937 LOGE("Wrong condition!!");
8941 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
8943 LOGE("failed to alloc mem for video data");
8947 stream->width = width;
8948 stream->height = height;
8949 stream->format = format;
8955 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8957 unsigned int pitch = 0;
8959 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8961 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8962 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8963 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8964 stream->stride[index] = pitch;
8965 stream->elevation[index] = stream->height;
8970 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8972 if (stream->format == MM_PIXEL_FORMAT_I420) {
8973 int ret = TBM_SURFACE_ERROR_NONE;
8974 tbm_surface_h surface;
8975 tbm_surface_info_s info;
8977 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8979 ret = tbm_surface_get_info(surface, &info);
8980 if (ret != TBM_SURFACE_ERROR_NONE) {
8981 tbm_surface_destroy(surface);
8985 tbm_surface_destroy(surface);
8986 stream->stride[0] = info.planes[0].stride;
8987 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
8988 stream->stride[1] = info.planes[1].stride;
8989 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
8990 stream->stride[2] = info.planes[2].stride;
8991 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
8992 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
8993 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
8994 stream->stride[0] = stream->width * 4;
8995 stream->elevation[0] = stream->height;
8996 stream->bo_size = stream->stride[0] * stream->height;
8998 LOGE("Not support format %d", stream->format);
9006 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9008 tbm_bo_handle thandle;
9010 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9011 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9012 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9016 unsigned char *src = NULL;
9017 unsigned char *dest = NULL;
9018 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9020 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9022 LOGE("fail to gst_memory_map");
9026 if (!mapinfo.data) {
9027 LOGE("data pointer is wrong");
9031 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9032 if (!stream->bo[0]) {
9033 LOGE("Fail to tbm_bo_alloc!!");
9037 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9039 LOGE("thandle pointer is wrong");
9043 if (stream->format == MM_PIXEL_FORMAT_I420) {
9044 src_stride[0] = GST_ROUND_UP_4(stream->width);
9045 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9046 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9047 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9050 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9051 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9053 for (i = 0; i < 3; i++) {
9054 src = mapinfo.data + src_offset[i];
9055 dest = thandle.ptr + dest_offset[i];
9060 for (j = 0; j < stream->height >> k; j++) {
9061 memcpy(dest, src, stream->width>>k);
9062 src += src_stride[i];
9063 dest += stream->stride[i];
9066 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9067 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9069 LOGE("Not support format %d", stream->format);
9073 tbm_bo_unmap(stream->bo[0]);
9074 gst_memory_unmap(mem, &mapinfo);
9080 tbm_bo_unmap(stream->bo[0]);
9083 gst_memory_unmap(mem, &mapinfo);
9089 __mmplayer_set_pause_state(mm_player_t *player)
9091 if (player->sent_bos)
9094 /* rtsp case, get content attrs by GstMessage */
9095 if (MMPLAYER_IS_RTSP_STREAMING(player))
9098 /* it's first time to update all content attrs. */
9099 __mmplayer_update_content_attrs(player, ATTR_ALL);
9103 __mmplayer_set_playing_state(mm_player_t *player)
9105 gchar *audio_codec = NULL;
9107 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9108 /* initialize because auto resume is done well. */
9109 player->resumed_by_rewind = FALSE;
9110 player->playback_rate = 1.0;
9113 if (player->sent_bos)
9116 /* try to get content metadata */
9118 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9119 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9120 * legacy mmfw-player api
9122 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9124 if ((player->cmd == MMPLAYER_COMMAND_START)
9125 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9126 __mmplayer_handle_missed_plugin(player);
9129 /* check audio codec field is set or not
9130 * we can get it from typefinder or codec's caps.
9132 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9134 /* The codec format can't be sent for audio only case like amr, mid etc.
9135 * Because, parser don't make related TAG.
9136 * So, if it's not set yet, fill it with found data.
9139 if (g_strrstr(player->type, "audio/midi"))
9140 audio_codec = "MIDI";
9141 else if (g_strrstr(player->type, "audio/x-amr"))
9142 audio_codec = "AMR";
9143 else if (g_strrstr(player->type, "audio/mpeg")
9144 && !g_strrstr(player->type, "mpegversion= (int)1"))
9145 audio_codec = "AAC";
9147 audio_codec = "unknown";
9149 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9151 if (mm_attrs_commit_all(player->attrs))
9152 LOGE("failed to update attributes");
9154 LOGD("set audio codec type with caps");