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 MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
93 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
94 (player->ini.http_use_file_buffer) && \
95 (player->http_file_buffering_path) && \
96 (strlen(player->http_file_buffering_path) > 0))
98 #define PLAYER_DISPLAY_MODE_DST_ROI 5
100 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
102 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
103 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
104 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
105 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
107 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
108 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
110 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | GLOBAL VARIABLE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | LOCAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
127 static sound_stream_info_h stream_info;
129 /*---------------------------------------------------------------------------
130 | LOCAL FUNCTION PROTOTYPES: |
131 ---------------------------------------------------------------------------*/
132 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
133 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
134 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
135 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
136 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
137 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
139 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
140 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
141 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
142 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
143 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
144 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
145 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
146 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
147 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
148 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
149 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
151 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
152 static void __mmplayer_release_misc(mm_player_t *player);
153 static void __mmplayer_release_misc_post(mm_player_t *player);
154 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
155 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
158 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
160 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
161 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
162 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
163 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
164 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
165 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
166 static gpointer __mmplayer_gapless_play_thread(gpointer data);
167 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
168 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
169 static void __mmplayer_release_dump_list(GList *dump_list);
170 static int __mmplayer_gst_realize(mm_player_t *player);
171 static int __mmplayer_gst_unrealize(mm_player_t *player);
172 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
173 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
176 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
177 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
178 static void __mmplayer_check_pipeline(mm_player_t *player);
179 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
180 static void __mmplayer_deactivate_old_path(mm_player_t *player);
181 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
182 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
183 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
184 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
185 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
186 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
187 static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
188 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
189 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
192 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
193 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
194 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
196 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
197 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
198 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
199 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
201 static void __mmplayer_set_pause_state(mm_player_t *player);
202 static void __mmplayer_set_playing_state(mm_player_t *player);
203 /*===========================================================================================
205 | FUNCTION DEFINITIONS |
207 ========================================================================================== */
211 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
215 count = gst_tag_list_get_tag_size(list, tag);
217 LOGD("count = %d", count);
219 for (i = 0; i < count; i++) {
222 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
223 if (!gst_tag_list_get_string_index(list, tag, i, &str))
224 g_assert_not_reached();
226 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
230 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
232 g_print(" : %s", str);
239 /* This function should be called after the pipeline goes PAUSED or higher
242 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
244 static gboolean has_duration = FALSE;
245 static gboolean has_video_attrs = FALSE;
246 static gboolean has_audio_attrs = FALSE;
247 static gboolean has_bitrate = FALSE;
248 gboolean missing_only = FALSE;
249 gboolean all = FALSE;
250 MMHandleType attrs = 0;
254 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
256 /* check player state here */
257 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
258 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
259 /* give warning now only */
260 LOGW("be careful. content attributes may not available in this state ");
263 /* get content attribute first */
264 attrs = MMPLAYER_GET_ATTRS(player);
266 LOGE("cannot get content attribute");
270 /* get update flag */
272 if (flag & ATTR_MISSING_ONLY) {
274 LOGD("updating missed attr only");
277 if (flag & ATTR_ALL) {
279 has_duration = FALSE;
280 has_video_attrs = FALSE;
281 has_audio_attrs = FALSE;
284 LOGD("updating all attrs");
287 if (missing_only && all) {
288 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
289 missing_only = FALSE;
292 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
293 has_duration = __mmplayer_update_duration_attrs(player, attrs);
295 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
296 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
298 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
299 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
301 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
302 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
305 if (mm_attrs_commit_all(attrs)) {
306 LOGE("failed to update attributes");
316 __mmplayer_get_stream_service_type(mm_player_t *player)
318 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
322 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
324 player->pipeline->mainbin &&
325 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
326 STREAMING_SERVICE_NONE);
328 /* streaming service type if streaming */
329 if (!MMPLAYER_IS_STREAMING(player))
330 return STREAMING_SERVICE_NONE;
332 streaming_type = (player->duration == 0) ?
333 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
335 switch (streaming_type) {
336 case STREAMING_SERVICE_LIVE:
337 LOGD("it's live streaming");
339 case STREAMING_SERVICE_VOD:
340 LOGD("it's vod streaming");
343 LOGE("should not get here");
349 return streaming_type;
352 /* this function sets the player state and also report
353 * it to applicaton by calling callback function
356 __mmplayer_set_state(mm_player_t *player, int state)
358 MMMessageParamType msg = {0, };
360 MMPLAYER_RETURN_IF_FAIL(player);
362 if (MMPLAYER_CURRENT_STATE(player) == state) {
363 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
364 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
368 /* update player states */
369 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
370 MMPLAYER_CURRENT_STATE(player) = state;
372 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
373 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
376 MMPLAYER_PRINT_STATE(player);
378 switch (MMPLAYER_CURRENT_STATE(player)) {
379 case MM_PLAYER_STATE_NULL:
380 case MM_PLAYER_STATE_READY:
382 case MM_PLAYER_STATE_PAUSED:
383 __mmplayer_set_pause_state(player);
385 case MM_PLAYER_STATE_PLAYING:
386 __mmplayer_set_playing_state(player);
388 case MM_PLAYER_STATE_NONE:
390 LOGW("invalid target state, there is nothing to do.");
395 /* post message to application */
396 if (MMPLAYER_TARGET_STATE(player) == state) {
397 /* fill the message with state of player */
398 msg.union_type = MM_MSG_UNION_STATE;
399 msg.state.previous = MMPLAYER_PREV_STATE(player);
400 msg.state.current = MMPLAYER_CURRENT_STATE(player);
402 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
404 /* state changed by resource callback */
405 if (player->interrupted_by_resource)
406 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
407 else /* state changed by usecase */
408 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
411 LOGD("intermediate state, do nothing.");
412 MMPLAYER_PRINT_STATE(player);
416 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
417 && !player->sent_bos) {
418 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
419 player->sent_bos = TRUE;
426 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
428 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
429 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
431 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
433 //LOGD("incomming command : %d ", command);
435 current_state = MMPLAYER_CURRENT_STATE(player);
436 pending_state = MMPLAYER_PENDING_STATE(player);
438 MMPLAYER_PRINT_STATE(player);
441 case MMPLAYER_COMMAND_CREATE:
443 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
445 if (current_state == MM_PLAYER_STATE_NULL ||
446 current_state == MM_PLAYER_STATE_READY ||
447 current_state == MM_PLAYER_STATE_PAUSED ||
448 current_state == MM_PLAYER_STATE_PLAYING)
453 case MMPLAYER_COMMAND_DESTROY:
455 /* destroy can called anytime */
457 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
461 case MMPLAYER_COMMAND_REALIZE:
463 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
465 if (pending_state != MM_PLAYER_STATE_NONE) {
468 /* need ready state to realize */
469 if (current_state == MM_PLAYER_STATE_READY)
472 if (current_state != MM_PLAYER_STATE_NULL)
478 case MMPLAYER_COMMAND_UNREALIZE:
480 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
482 if (current_state == MM_PLAYER_STATE_NULL)
487 case MMPLAYER_COMMAND_START:
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PLAYING)
494 else if (current_state != MM_PLAYER_STATE_READY &&
495 current_state != MM_PLAYER_STATE_PAUSED)
497 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
500 LOGD("player is going to paused state, just change the pending state as playing");
507 case MMPLAYER_COMMAND_STOP:
509 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
511 if (current_state == MM_PLAYER_STATE_READY)
514 /* need playing/paused state to stop */
515 if (current_state != MM_PLAYER_STATE_PLAYING &&
516 current_state != MM_PLAYER_STATE_PAUSED)
521 case MMPLAYER_COMMAND_PAUSE:
523 if (MMPLAYER_IS_LIVE_STREAMING(player))
526 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
527 goto NOT_COMPLETED_SEEK;
529 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
531 if (pending_state == MM_PLAYER_STATE_NONE) {
532 if (current_state == MM_PLAYER_STATE_PAUSED)
534 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
536 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
538 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
539 if (current_state == MM_PLAYER_STATE_PAUSED)
540 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
547 case MMPLAYER_COMMAND_RESUME:
549 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
550 goto NOT_COMPLETED_SEEK;
552 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
554 if (pending_state == MM_PLAYER_STATE_NONE) {
555 if (current_state == MM_PLAYER_STATE_PLAYING)
557 else if (current_state != MM_PLAYER_STATE_PAUSED)
559 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
561 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
562 LOGD("player is going to paused state, just change the pending state as playing");
572 player->cmd = command;
574 return MM_ERROR_NONE;
577 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
578 MMPLAYER_STATE_GET_NAME(current_state), command);
579 return MM_ERROR_PLAYER_INVALID_STATE;
582 LOGW("not completed seek");
583 return MM_ERROR_PLAYER_DOING_SEEK;
586 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
587 return MM_ERROR_PLAYER_NO_OP;
590 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
591 return MM_ERROR_PLAYER_NO_OP;
595 __mmplayer_gapless_play_thread(gpointer data)
597 mm_player_t *player = (mm_player_t *)data;
598 MMPlayerGstElement *mainbin = NULL;
600 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
602 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
603 while (!player->gapless_play_thread_exit) {
604 LOGD("gapless play thread started. waiting for signal.");
605 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
607 LOGD("reconfigure pipeline for gapless play.");
609 if (player->gapless_play_thread_exit) {
610 if (player->gapless.reconfigure) {
611 player->gapless.reconfigure = false;
612 MMPLAYER_PLAYBACK_UNLOCK(player);
614 LOGD("exiting gapless play thread");
618 mainbin = player->pipeline->mainbin;
620 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
621 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
622 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
626 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
628 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
634 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
636 GSource *source = NULL;
640 source = g_main_context_find_source_by_id(context, source_id);
641 if (source != NULL) {
642 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
643 g_source_destroy(source);
650 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
652 mm_player_t *player = (mm_player_t *)hplayer;
653 GstMessage *msg = NULL;
654 GQueue *queue = NULL;
657 MMPLAYER_RETURN_IF_FAIL(player);
659 /* disconnecting bus watch */
660 if (player->bus_watcher)
661 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
662 player->bus_watcher = 0;
664 /* destroy the gst bus msg thread */
665 if (player->bus_msg_thread) {
666 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
667 player->bus_msg_thread_exit = TRUE;
668 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
669 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
671 LOGD("gst bus msg thread exit.");
672 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
673 player->bus_msg_thread = NULL;
675 g_mutex_clear(&player->bus_msg_thread_mutex);
676 g_cond_clear(&player->bus_msg_thread_cond);
679 g_mutex_lock(&player->bus_msg_q_lock);
680 queue = player->bus_msg_q;
681 while (!g_queue_is_empty(queue)) {
682 msg = (GstMessage *)g_queue_pop_head(queue);
687 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
688 gst_message_unref(msg);
690 g_mutex_unlock(&player->bus_msg_q_lock);
696 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
698 GstElement *parent = NULL;
700 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
702 /* if we have no fakesink. this meas we are using decodebin which doesn'
703 t need to add extra fakesink */
704 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
707 MMPLAYER_FSINK_LOCK(player);
712 /* get parent of fakesink */
713 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
715 LOGD("fakesink already removed");
719 gst_element_set_locked_state(fakesink->gst, TRUE);
721 /* setting the state to NULL never returns async
722 * so no need to wait for completion of state transiton
724 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
725 LOGE("fakesink state change failure!");
726 /* FIXIT : should I return here? or try to proceed to next? */
729 /* remove fakesink from it's parent */
730 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
731 LOGE("failed to remove fakesink");
733 gst_object_unref(parent);
738 gst_object_unref(parent);
740 LOGD("state-holder removed");
742 gst_element_set_locked_state(fakesink->gst, FALSE);
744 MMPLAYER_FSINK_UNLOCK(player);
749 gst_element_set_locked_state(fakesink->gst, FALSE);
751 MMPLAYER_FSINK_UNLOCK(player);
755 static GstPadProbeReturn
756 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
758 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
759 return GST_PAD_PROBE_OK;
763 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
765 gint64 stop_running_time = 0;
766 gint64 position_running_time = 0;
770 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
771 if ((player->gapless.update_segment[idx] == TRUE) ||
772 !(player->selector[idx].event_probe_id)) {
773 /* LOGW("[%d] skip", idx); */
777 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
779 gst_segment_to_running_time(&player->gapless.segment[idx],
780 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
781 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
783 gst_segment_to_running_time(&player->gapless.segment[idx],
784 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
786 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
788 gst_segment_to_running_time(&player->gapless.segment[idx],
789 GST_FORMAT_TIME, player->duration);
792 position_running_time =
793 gst_segment_to_running_time(&player->gapless.segment[idx],
794 GST_FORMAT_TIME, player->gapless.segment[idx].position);
796 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
797 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
799 GST_TIME_ARGS(stop_running_time),
800 GST_TIME_ARGS(position_running_time),
801 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
802 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
804 position_running_time = MAX(position_running_time, stop_running_time);
805 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
806 GST_FORMAT_TIME, player->gapless.segment[idx].start);
807 position_running_time = MAX(0, position_running_time);
808 position = MAX(position, position_running_time);
812 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
813 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
814 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
816 player->gapless.start_time[stream_type] += position;
822 static GstPadProbeReturn
823 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
825 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
826 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
827 mm_player_t *player = (mm_player_t *)data;
828 GstCaps *caps = NULL;
829 GstStructure *str = NULL;
830 const gchar *name = NULL;
831 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
832 gboolean caps_ret = TRUE;
834 if (GST_EVENT_IS_DOWNSTREAM(event) &&
835 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
836 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
837 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
838 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
840 } else if (GST_EVENT_IS_UPSTREAM(event) &&
841 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
845 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
849 if (strstr(name, "audio")) {
850 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
851 } else if (strstr(name, "video")) {
852 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
854 /* text track is not supportable */
855 LOGE("invalid name %s", name);
859 switch (GST_EVENT_TYPE(event)) {
862 /* in case of gapless, drop eos event not to send it to sink */
863 if (player->gapless.reconfigure && !player->msg_posted) {
864 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
865 ret = GST_PAD_PROBE_DROP;
869 case GST_EVENT_STREAM_START:
871 __mmplayer_gst_selector_update_start_time(player, stream_type);
874 case GST_EVENT_FLUSH_STOP:
876 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
877 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
878 player->gapless.start_time[stream_type] = 0;
881 case GST_EVENT_SEGMENT:
886 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
887 gst_event_copy_segment(event, &segment);
889 if (segment.format != GST_FORMAT_TIME)
892 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
893 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
894 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
895 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
896 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
897 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
899 /* keep the all the segment ev to cover the seeking */
900 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
901 player->gapless.update_segment[stream_type] = TRUE;
903 if (!player->gapless.running)
906 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
908 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
910 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
911 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
912 gst_event_unref(event);
913 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
919 gdouble proportion = 0.0;
920 GstClockTimeDiff diff = 0;
921 GstClockTime timestamp = 0;
922 gint64 running_time_diff = -1;
924 GstEvent *tmpev = NULL;
926 running_time_diff = player->gapless.segment[stream_type].base;
928 if (running_time_diff <= 0) /* don't need to adjust */
931 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
932 gst_event_unref(event);
934 if (timestamp < running_time_diff) {
935 LOGW("QOS event from previous group");
936 ret = GST_PAD_PROBE_DROP;
940 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
941 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
942 stream_type, GST_TIME_ARGS(timestamp),
943 GST_TIME_ARGS(running_time_diff),
944 GST_TIME_ARGS(timestamp - running_time_diff));
946 timestamp -= running_time_diff;
948 /* That case is invalid for QoS events */
949 if (diff < 0 && -diff > timestamp) {
950 LOGW("QOS event from previous group");
951 ret = GST_PAD_PROBE_DROP;
955 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
956 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
966 gst_caps_unref(caps);
970 /* create fakesink for audio or video path witout audiobin or videobin */
972 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
974 GstElement *pipeline = NULL;
975 GstElement *fakesink = NULL;
976 GstPad *sinkpad = NULL;
979 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
981 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
984 fakesink = gst_element_factory_make("fakesink", NULL);
985 if (fakesink == NULL) {
986 LOGE("failed to create fakesink");
990 /* store it as it's sink element */
991 __mmplayer_add_sink(player, fakesink);
993 gst_bin_add(GST_BIN(pipeline), fakesink);
996 sinkpad = gst_element_get_static_pad(fakesink, "sink");
998 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1000 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1001 LOGE("failed to link fakesink");
1002 gst_object_unref(GST_OBJECT(fakesink));
1006 if (strstr(name, "video")) {
1007 if (player->v_stream_caps) {
1008 gst_caps_unref(player->v_stream_caps);
1009 player->v_stream_caps = NULL;
1011 if (player->ini.set_dump_element_flag)
1012 __mmplayer_add_dump_buffer_probe(player, fakesink);
1015 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1016 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1020 gst_object_unref(GST_OBJECT(sinkpad));
1027 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1029 GstElement *pipeline = NULL;
1030 GstElement *selector = NULL;
1031 GstPad *srcpad = NULL;
1034 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1036 selector = gst_element_factory_make("input-selector", NULL);
1038 LOGE("failed to create input-selector");
1041 g_object_set(selector, "sync-streams", TRUE, NULL);
1043 player->pipeline->mainbin[elem_idx].id = elem_idx;
1044 player->pipeline->mainbin[elem_idx].gst = selector;
1046 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1048 srcpad = gst_element_get_static_pad(selector, "src");
1050 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1051 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1052 __mmplayer_gst_selector_blocked, NULL, NULL);
1053 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1054 __mmplayer_gst_selector_event_probe, player, NULL);
1056 gst_element_set_state(selector, GST_STATE_PAUSED);
1058 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1059 gst_bin_add(GST_BIN(pipeline), selector);
1066 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1068 mm_player_t *player = (mm_player_t *)data;
1069 GstElement *selector = NULL;
1070 GstCaps *caps = NULL;
1071 GstStructure *str = NULL;
1072 const gchar *name = NULL;
1073 GstPad *sinkpad = NULL;
1074 gboolean first_track = FALSE;
1075 gboolean caps_ret = TRUE;
1077 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1078 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1081 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 LOGD("pad-added signal handling");
1086 /* get mimetype from caps */
1087 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1091 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1092 /* LOGD("detected mimetype : %s", name); */
1094 if (strstr(name, "video")) {
1096 gchar *caps_str = NULL;
1098 caps_str = gst_caps_to_string(caps);
1099 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1100 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1101 player->set_mode.video_zc = true;
1103 MMPLAYER_FREEIF(caps_str);
1105 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1106 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1108 LOGD("surface type : %d", stype);
1110 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1111 __mmplayer_gst_create_sinkbin(elem, pad, player);
1115 /* in case of exporting video frame, it requires the 360 video filter.
1116 * it will be handled in _no_more_pads(). */
1117 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
1118 __mmplayer_gst_make_fakesink(player, pad, name);
1122 LOGD("video selector is required");
1123 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1124 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1125 } else if (strstr(name, "audio")) {
1126 gint samplerate = 0;
1129 gst_structure_get_int(str, "rate", &samplerate);
1130 gst_structure_get_int(str, "channels", &channels);
1132 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1133 __mmplayer_gst_create_sinkbin(elem, pad, player);
1137 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1138 __mmplayer_gst_make_fakesink(player, pad, name);
1142 LOGD("audio selector is required");
1143 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1144 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1146 } else if (strstr(name, "text")) {
1147 LOGD("text selector is required");
1148 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1149 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1151 LOGE("invalid caps info");
1155 /* check selector and create it */
1156 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1157 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1162 LOGD("input-selector is already created.");
1166 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1168 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1170 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1171 LOGE("failed to link selector");
1172 gst_object_unref(GST_OBJECT(selector));
1177 LOGD("this track will be activated");
1178 g_object_set(selector, "active-pad", sinkpad, NULL);
1181 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1187 gst_caps_unref(caps);
1190 gst_object_unref(GST_OBJECT(sinkpad));
1198 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1200 GstPad *srcpad = NULL;
1203 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1205 LOGD("type %d", type);
1208 LOGD("there is no %d track", type);
1212 srcpad = gst_element_get_static_pad(selector, "src");
1214 LOGE("failed to get srcpad from selector");
1218 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1220 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1222 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1223 if (player->selector[type].block_id) {
1224 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1225 player->selector[type].block_id = 0;
1229 gst_object_unref(GST_OBJECT(srcpad));
1238 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1240 MMHandleType attrs = 0;
1241 gint active_index = 0;
1244 MMPLAYER_RETURN_IF_FAIL(player);
1246 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1248 /* change track to active pad */
1249 active_index = player->selector[type].active_pad_index;
1250 if ((active_index != DEFAULT_TRACK) &&
1251 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1252 LOGW("failed to change %d type track to %d", type, active_index);
1253 player->selector[type].active_pad_index = DEFAULT_TRACK;
1257 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1258 attrs = MMPLAYER_GET_ATTRS(player);
1260 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1261 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1263 if (mm_attrs_commit_all(attrs))
1264 LOGW("failed to commit attrs.");
1266 LOGW("cannot get content attribute");
1275 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1280 if (!audio_selector) {
1281 LOGD("there is no audio track");
1283 /* in case the source is changed, output can be changed. */
1284 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1285 LOGD("remove previous audiobin if it exist");
1287 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1288 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1290 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1291 MMPLAYER_FREEIF(player->pipeline->audiobin);
1294 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1295 __mmplayer_pipeline_complete(NULL, player);
1300 /* apply the audio track information */
1301 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1303 /* create audio sink path */
1304 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1305 LOGE("failed to create audio sink path");
1314 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1317 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1319 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1320 LOGD("text path is not supproted");
1324 /* apply the text track information */
1325 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1327 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1328 player->has_closed_caption = TRUE;
1330 /* create text decode path */
1331 player->no_more_pad = TRUE;
1333 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1334 LOGE("failed to create text sink path");
1343 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1345 gint64 dur_bytes = 0L;
1348 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1349 player->pipeline->mainbin && player->streamer, FALSE);
1351 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1352 LOGE("fail to get duration.");
1354 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1355 * use file information was already set on Q2 when it was created. */
1356 __mm_player_streaming_set_queue2(player->streamer,
1357 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1358 TRUE, /* use_buffering */
1359 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1361 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1368 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1370 mm_player_t *player = NULL;
1371 GstElement *video_selector = NULL;
1372 GstElement *audio_selector = NULL;
1373 GstElement *text_selector = NULL;
1376 player = (mm_player_t *)data;
1378 LOGD("no-more-pad signal handling");
1380 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1381 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1382 LOGW("player is shutting down");
1386 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1387 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1388 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1389 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1390 LOGE("failed to set queue2 buffering");
1395 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1396 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1397 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1399 /* create video path followed by video-select */
1400 if (video_selector && !audio_selector && !text_selector)
1401 player->no_more_pad = TRUE;
1403 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1406 /* create audio path followed by audio-select */
1407 if (audio_selector && !text_selector)
1408 player->no_more_pad = TRUE;
1410 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1413 /* create text path followed by text-select */
1414 __mmplayer_create_text_sink_path(player, text_selector);
1417 if (player->gapless.reconfigure) {
1418 player->gapless.reconfigure = FALSE;
1419 MMPLAYER_PLAYBACK_UNLOCK(player);
1426 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1428 gboolean ret = FALSE;
1429 GstElement *pipeline = NULL;
1430 GstPad *sinkpad = NULL;
1433 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1434 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1436 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1438 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1440 LOGE("failed to get pad from sinkbin");
1446 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1447 LOGE("failed to link sinkbin for reusing");
1448 goto EXIT; /* exit either pass or fail */
1452 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1453 LOGE("failed to set state(READY) to sinkbin");
1458 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1459 LOGE("failed to add sinkbin to pipeline");
1464 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1465 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1470 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1471 LOGE("failed to set state(PAUSED) to sinkbin");
1480 gst_object_unref(GST_OBJECT(sinkpad));
1488 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1490 mm_player_t *player = NULL;
1491 MMHandleType attrs = 0;
1492 GstCaps *caps = NULL;
1493 gchar *caps_str = NULL;
1494 GstStructure *str = NULL;
1495 const gchar *name = NULL;
1496 GstElement *sinkbin = NULL;
1497 gboolean reusing = FALSE;
1498 gboolean caps_ret = TRUE;
1499 gchar *sink_pad_name = "sink";
1502 player = (mm_player_t *)data;
1505 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1506 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1508 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1512 caps_str = gst_caps_to_string(caps);
1514 /* LOGD("detected mimetype : %s", name); */
1515 if (strstr(name, "audio")) {
1516 if (player->pipeline->audiobin == NULL) {
1517 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1518 LOGE("failed to create audiobin. continuing without audio");
1522 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1523 LOGD("creating audiobin success");
1526 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1527 LOGD("reusing audiobin");
1528 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1530 } else if (strstr(name, "video")) {
1531 /* 1. zero copy is updated at _decode_pad_added()
1532 * 2. NULL surface type is handled in _decode_pad_added() */
1533 LOGD("zero copy %d", player->set_mode.video_zc);
1534 if (player->pipeline->videobin == NULL) {
1535 int surface_type = 0;
1536 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1537 LOGD("display_surface_type (%d)", surface_type);
1539 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1540 LOGD("mark video overlay for acquire");
1541 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1542 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1543 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1544 &player->video_overlay_resource)
1545 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1546 LOGE("could not mark video_overlay resource for acquire");
1551 player->interrupted_by_resource = FALSE;
1553 if (mm_resource_manager_commit(player->resource_manager) !=
1554 MM_RESOURCE_MANAGER_ERROR_NONE) {
1555 LOGE("could not acquire resources for video playing");
1559 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1560 LOGE("failed to create videobin. continuing without video");
1564 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1565 LOGD("creating videosink bin success");
1568 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1569 LOGD("re-using videobin");
1570 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1572 } else if (strstr(name, "text")) {
1573 if (player->pipeline->textbin == NULL) {
1574 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1575 LOGE("failed to create text sink bin. continuing without text");
1579 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1580 player->textsink_linked = 1;
1581 LOGD("creating textsink bin success");
1583 if (!player->textsink_linked) {
1584 LOGD("re-using textbin");
1586 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1587 player->textsink_linked = 1;
1589 /* linked textbin exist which means that the external subtitle path exist already */
1590 LOGW("ignoring internal subtutle since external subtitle is available");
1593 sink_pad_name = "text_sink";
1595 LOGW("unknown mime type %s, ignoring it", name);
1599 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1602 LOGD("[handle: %p] success to create and link sink bin", player);
1604 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1605 * streaming task. if the task blocked, then buffer will not flow to the next element
1606 *(autoplugging element). so this is special hack for streaming. please try to remove it
1608 /* dec stream count. we can remove fakesink if it's zero */
1609 if (player->num_dynamic_pad)
1610 player->num_dynamic_pad--;
1612 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1614 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1615 __mmplayer_pipeline_complete(NULL, player);
1619 MMPLAYER_FREEIF(caps_str);
1622 gst_caps_unref(caps);
1624 /* flusing out new attributes */
1625 if (mm_attrs_commit_all(attrs))
1626 LOGE("failed to comit attributes");
1632 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1634 int required_angle = 0; /* Angle required for straight view */
1635 int rotation_angle = 0;
1637 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1638 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1640 /* Counter clockwise */
1641 switch (orientation) {
1646 required_angle = 270;
1649 required_angle = 180;
1652 required_angle = 90;
1656 rotation_angle = display_angle + required_angle;
1657 if (rotation_angle >= 360)
1658 rotation_angle -= 360;
1660 /* chech if supported or not */
1661 if (rotation_angle % 90) {
1662 LOGD("not supported rotation angle = %d", rotation_angle);
1666 switch (rotation_angle) {
1668 *value = MM_DISPLAY_ROTATION_NONE;
1671 *value = MM_DISPLAY_ROTATION_90;
1674 *value = MM_DISPLAY_ROTATION_180;
1677 *value = MM_DISPLAY_ROTATION_270;
1681 LOGD("setting rotation property value : %d", *value);
1687 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1689 /* check video sinkbin is created */
1690 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1692 player->pipeline->videobin &&
1693 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1694 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1695 MM_ERROR_PLAYER_NOT_INITIALIZED);
1697 return MM_ERROR_NONE;
1701 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1703 int display_rotation = 0;
1704 gchar *org_orient = NULL;
1705 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1708 LOGE("cannot get content attribute");
1709 return MM_ERROR_PLAYER_INTERNAL;
1712 if (display_angle) {
1713 /* update user roation */
1714 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1716 /* Counter clockwise */
1717 switch (display_rotation) {
1718 case MM_DISPLAY_ROTATION_NONE:
1721 case MM_DISPLAY_ROTATION_90:
1722 *display_angle = 90;
1724 case MM_DISPLAY_ROTATION_180:
1725 *display_angle = 180;
1727 case MM_DISPLAY_ROTATION_270:
1728 *display_angle = 270;
1731 LOGW("wrong angle type : %d", display_rotation);
1734 LOGD("check user angle: %d", *display_angle);
1738 /* Counter clockwise */
1739 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1742 if (!strcmp(org_orient, "rotate-90"))
1744 else if (!strcmp(org_orient, "rotate-180"))
1746 else if (!strcmp(org_orient, "rotate-270"))
1749 LOGD("original rotation is %s", org_orient);
1751 LOGD("content_video_orientation get fail");
1754 LOGD("check orientation: %d", *orientation);
1757 return MM_ERROR_NONE;
1761 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1763 int rotation_value = 0;
1764 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1765 int display_angle = 0;
1768 /* check video sinkbin is created */
1769 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1772 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1774 /* get rotation value to set */
1775 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1776 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1777 LOGD("set video param : rotate %d", rotation_value);
1781 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1783 MMHandleType attrs = 0;
1787 /* check video sinkbin is created */
1788 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1791 attrs = MMPLAYER_GET_ATTRS(player);
1792 MMPLAYER_RETURN_IF_FAIL(attrs);
1794 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1795 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1796 LOGD("set video param : visible %d", visible);
1800 __mmplayer_video_param_set_display_method(mm_player_t *player)
1802 MMHandleType attrs = 0;
1803 int display_method = 0;
1806 /* check video sinkbin is created */
1807 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1810 attrs = MMPLAYER_GET_ATTRS(player);
1811 MMPLAYER_RETURN_IF_FAIL(attrs);
1813 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1814 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1815 LOGD("set video param : method %d", display_method);
1819 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1821 MMHandleType attrs = 0;
1822 void *handle = NULL;
1825 /* check video sinkbin is created */
1826 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1827 LOGW("There is no video sink");
1831 attrs = MMPLAYER_GET_ATTRS(player);
1832 MMPLAYER_RETURN_IF_FAIL(attrs);
1833 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1835 gst_video_overlay_set_video_roi_area(
1836 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1837 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1838 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1839 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1844 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1846 MMHandleType attrs = 0;
1847 void *handle = NULL;
1851 int win_roi_width = 0;
1852 int win_roi_height = 0;
1855 /* check video sinkbin is created */
1856 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1857 LOGW("There is no video sink");
1861 attrs = MMPLAYER_GET_ATTRS(player);
1862 MMPLAYER_RETURN_IF_FAIL(attrs);
1864 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1867 /* It should be set after setting window */
1868 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1869 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1870 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1871 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1873 /* After setting window handle, set display roi area */
1874 gst_video_overlay_set_display_roi_area(
1875 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1876 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1877 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1878 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1883 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1885 MMHandleType attrs = 0;
1886 void *handle = NULL;
1888 /* check video sinkbin is created */
1889 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1892 attrs = MMPLAYER_GET_ATTRS(player);
1893 MMPLAYER_RETURN_IF_FAIL(attrs);
1895 /* common case if using overlay surface */
1896 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1899 /* default is using wl_surface_id */
1900 unsigned int wl_surface_id = 0;
1901 wl_surface_id = *(int *)handle;
1902 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1903 gst_video_overlay_set_wl_window_wl_surface_id(
1904 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1907 /* FIXIT : is it error case? */
1908 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1913 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1915 gboolean update_all_param = FALSE;
1918 /* check video sinkbin is created */
1919 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1920 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1922 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1923 LOGE("can not find tizenwlsink");
1924 return MM_ERROR_PLAYER_INTERNAL;
1927 LOGD("param_name : %s", param_name);
1928 if (!g_strcmp0(param_name, "update_all_param"))
1929 update_all_param = TRUE;
1931 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1932 __mmplayer_video_param_set_display_overlay(player);
1933 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1934 __mmplayer_video_param_set_display_method(player);
1935 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1936 __mmplayer_video_param_set_display_visible(player);
1937 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1938 __mmplayer_video_param_set_display_rotation(player);
1939 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1940 __mmplayer_video_param_set_roi_area(player);
1941 if (update_all_param)
1942 __mmplayer_video_param_set_video_roi_area(player);
1944 return MM_ERROR_NONE;
1948 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1950 MMHandleType attrs = 0;
1951 int surface_type = 0;
1952 int ret = MM_ERROR_NONE;
1956 /* check video sinkbin is created */
1957 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1958 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1960 attrs = MMPLAYER_GET_ATTRS(player);
1962 LOGE("cannot get content attribute");
1963 return MM_ERROR_PLAYER_INTERNAL;
1965 LOGD("param_name : %s", param_name);
1967 /* update display surface */
1968 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1969 LOGD("check display surface type attribute: %d", surface_type);
1971 /* configuring display */
1972 switch (surface_type) {
1973 case MM_DISPLAY_SURFACE_OVERLAY:
1975 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1976 if (ret != MM_ERROR_NONE)
1984 return MM_ERROR_NONE;
1988 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1990 gboolean disable_overlay = FALSE;
1991 mm_player_t *player = (mm_player_t *)hplayer;
1992 int ret = MM_ERROR_NONE;
1995 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1996 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
1997 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1998 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2000 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2001 LOGW("Display control is not supported");
2002 return MM_ERROR_PLAYER_INTERNAL;
2005 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2007 if (audio_only == (bool)disable_overlay) {
2008 LOGE("It's the same with current setting: (%d)", audio_only);
2009 return MM_ERROR_NONE;
2013 LOGE("disable overlay");
2014 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2016 /* release overlay resource */
2017 if (player->video_overlay_resource != NULL) {
2018 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2019 player->video_overlay_resource);
2020 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2021 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2024 player->video_overlay_resource = NULL;
2027 ret = mm_resource_manager_commit(player->resource_manager);
2028 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2029 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2033 /* mark video overlay for acquire */
2034 if (player->video_overlay_resource == NULL) {
2035 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2036 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2037 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2038 &player->video_overlay_resource);
2039 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2040 LOGE("could not prepare for video_overlay resource");
2045 player->interrupted_by_resource = FALSE;
2046 /* acquire resources for video overlay */
2047 ret = mm_resource_manager_commit(player->resource_manager);
2048 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2049 LOGE("could not acquire resources for video playing");
2053 LOGD("enable overlay");
2054 __mmplayer_video_param_set_display_overlay(player);
2055 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2060 return MM_ERROR_NONE;
2064 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2066 mm_player_t *player = (mm_player_t *)hplayer;
2067 gboolean disable_overlay = FALSE;
2071 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2072 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2073 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2074 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2075 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2077 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2078 LOGW("Display control is not supported");
2079 return MM_ERROR_PLAYER_INTERNAL;
2082 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2084 *paudio_only = (bool)disable_overlay;
2086 LOGD("audio_only : %d", *paudio_only);
2090 return MM_ERROR_NONE;
2094 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2096 GList *bucket = element_bucket;
2097 MMPlayerGstElement *element = NULL;
2098 MMPlayerGstElement *prv_element = NULL;
2099 gint successful_link_count = 0;
2103 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2105 prv_element = (MMPlayerGstElement *)bucket->data;
2106 bucket = bucket->next;
2108 for (; bucket; bucket = bucket->next) {
2109 element = (MMPlayerGstElement *)bucket->data;
2111 if (element && element->gst) {
2112 if (prv_element && prv_element->gst) {
2113 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2114 LOGD("linking [%s] to [%s] success",
2115 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2116 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2117 successful_link_count++;
2119 LOGD("linking [%s] to [%s] failed",
2120 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2121 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2127 prv_element = element;
2132 return successful_link_count;
2136 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2138 GList *bucket = element_bucket;
2139 MMPlayerGstElement *element = NULL;
2140 int successful_add_count = 0;
2144 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2145 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2147 for (; bucket; bucket = bucket->next) {
2148 element = (MMPlayerGstElement *)bucket->data;
2150 if (element && element->gst) {
2151 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2152 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2153 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2154 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2157 successful_add_count++;
2163 return successful_add_count;
2167 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2169 mm_player_t *player = (mm_player_t *)data;
2170 GstCaps *caps = NULL;
2171 GstStructure *str = NULL;
2173 gboolean caps_ret = TRUE;
2177 MMPLAYER_RETURN_IF_FAIL(pad);
2178 MMPLAYER_RETURN_IF_FAIL(unused);
2179 MMPLAYER_RETURN_IF_FAIL(data);
2181 caps = gst_pad_get_current_caps(pad);
2185 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2189 LOGD("name = %s", name);
2191 if (strstr(name, "audio")) {
2192 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2194 if (player->audio_stream_changed_cb) {
2195 LOGE("call the audio stream changed cb");
2196 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2198 } else if (strstr(name, "video")) {
2199 if ((name = gst_structure_get_string(str, "format")))
2200 player->set_mode.video_zc = name[0] == 'S';
2202 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2204 if (player->video_stream_changed_cb) {
2205 LOGE("call the video stream changed cb");
2206 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2209 LOGW("invalid caps info");
2214 gst_caps_unref(caps);
2222 * This function is to create audio pipeline for playing.
2224 * @param player [in] handle of player
2226 * @return This function returns zero on success.
2228 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2230 /* macro for code readability. just for sinkbin-creation functions */
2231 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2233 x_bin[x_id].id = x_id;\
2234 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2235 if (!x_bin[x_id].gst) {\
2236 LOGE("failed to create %s", x_factory);\
2239 if (x_player->ini.set_dump_element_flag)\
2240 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2243 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2247 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2252 MMPLAYER_RETURN_IF_FAIL(player);
2254 if (player->audio_stream_buff_list) {
2255 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2256 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2259 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2260 __mmplayer_audio_stream_send_data(player, tmp);
2262 MMPLAYER_FREEIF(tmp->pcm_data);
2263 MMPLAYER_FREEIF(tmp);
2266 g_list_free(player->audio_stream_buff_list);
2267 player->audio_stream_buff_list = NULL;
2274 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2276 MMPlayerAudioStreamDataType audio_stream = { 0, };
2279 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2281 audio_stream.bitrate = a_buffer->bitrate;
2282 audio_stream.channel = a_buffer->channel;
2283 audio_stream.depth = a_buffer->depth;
2284 audio_stream.is_little_endian = a_buffer->is_little_endian;
2285 audio_stream.channel_mask = a_buffer->channel_mask;
2286 audio_stream.data_size = a_buffer->data_size;
2287 audio_stream.data = a_buffer->pcm_data;
2289 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2290 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2296 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2298 mm_player_t *player = (mm_player_t *)data;
2302 gint endianness = 0;
2303 guint64 channel_mask = 0;
2304 void *a_data = NULL;
2306 mm_player_audio_stream_buff_t *a_buffer = NULL;
2307 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2311 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2313 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2314 a_data = mapinfo.data;
2315 a_size = mapinfo.size;
2317 GstCaps *caps = gst_pad_get_current_caps(pad);
2318 GstStructure *structure = gst_caps_get_structure(caps, 0);
2320 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2321 gst_structure_get_int(structure, "rate", &rate);
2322 gst_structure_get_int(structure, "channels", &channel);
2323 gst_structure_get_int(structure, "depth", &depth);
2324 gst_structure_get_int(structure, "endianness", &endianness);
2325 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2326 gst_caps_unref(GST_CAPS(caps));
2328 /* In case of the sync is false, use buffer list. *
2329 * The num of buffer list depends on the num of audio channels */
2330 if (player->audio_stream_buff_list) {
2331 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2332 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2334 if (channel_mask == tmp->channel_mask) {
2335 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2336 if (tmp->data_size + a_size < tmp->buff_size) {
2337 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2338 tmp->data_size += a_size;
2340 /* send data to client */
2341 __mmplayer_audio_stream_send_data(player, tmp);
2343 if (a_size > tmp->buff_size) {
2344 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2345 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2346 if (tmp->pcm_data == NULL) {
2347 LOGE("failed to realloc data.");
2350 tmp->buff_size = a_size;
2352 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2353 memcpy(tmp->pcm_data, a_data, a_size);
2354 tmp->data_size = a_size;
2359 LOGE("data is empty in list.");
2365 /* create new audio stream data */
2366 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2367 if (a_buffer == NULL) {
2368 LOGE("failed to alloc data.");
2371 a_buffer->bitrate = rate;
2372 a_buffer->channel = channel;
2373 a_buffer->depth = depth;
2374 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2375 a_buffer->channel_mask = channel_mask;
2376 a_buffer->data_size = a_size;
2378 if (!player->audio_stream_sink_sync) {
2379 /* If sync is FALSE, use buffer list to reduce the IPC. */
2380 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2381 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2382 if (a_buffer->pcm_data == NULL) {
2383 LOGE("failed to alloc data.");
2384 MMPLAYER_FREEIF(a_buffer);
2387 memcpy(a_buffer->pcm_data, a_data, a_size);
2388 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2389 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2391 /* If sync is TRUE, send data directly. */
2392 a_buffer->pcm_data = a_data;
2393 __mmplayer_audio_stream_send_data(player, a_buffer);
2394 MMPLAYER_FREEIF(a_buffer);
2398 gst_buffer_unmap(buffer, &mapinfo);
2403 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2405 mm_player_t *player = (mm_player_t *)data;
2406 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2407 GstPad *sinkpad = NULL;
2408 GstElement *queue = NULL, *sink = NULL;
2411 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2413 queue = gst_element_factory_make("queue", NULL);
2414 if (queue == NULL) {
2415 LOGD("fail make queue");
2419 sink = gst_element_factory_make("fakesink", NULL);
2421 LOGD("fail make fakesink");
2425 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2427 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2428 LOGW("failed to link queue & sink");
2432 sinkpad = gst_element_get_static_pad(queue, "sink");
2434 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2435 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2439 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2441 gst_object_unref(sinkpad);
2442 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2443 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2445 gst_element_set_state(sink, GST_STATE_PAUSED);
2446 gst_element_set_state(queue, GST_STATE_PAUSED);
2448 __mmplayer_add_signal_connection(player,
2450 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2452 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2459 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2461 gst_object_unref(GST_OBJECT(queue));
2465 gst_object_unref(GST_OBJECT(sink));
2469 gst_object_unref(GST_OBJECT(sinkpad));
2477 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2479 #define MAX_PROPS_LEN 128
2480 gint latency_mode = 0;
2481 gchar *stream_type = NULL;
2482 gchar *latency = NULL;
2484 gchar stream_props[MAX_PROPS_LEN] = {0,};
2485 GstStructure *props = NULL;
2488 * It should be set after player creation through attribute.
2489 * But, it can not be changed during playing.
2492 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2494 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2495 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2498 LOGE("stream_type is null.");
2500 if (player->sound.focus_id)
2501 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2502 stream_type, stream_id, player->sound.focus_id);
2504 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2505 stream_type, stream_id);
2506 props = gst_structure_from_string(stream_props, NULL);
2507 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2508 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2509 stream_type, stream_id, player->sound.focus_id, stream_props);
2510 gst_structure_free(props);
2513 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2515 switch (latency_mode) {
2516 case AUDIO_LATENCY_MODE_LOW:
2517 latency = g_strndup("low", 3);
2519 case AUDIO_LATENCY_MODE_MID:
2520 latency = g_strndup("mid", 3);
2522 case AUDIO_LATENCY_MODE_HIGH:
2523 latency = g_strndup("high", 4);
2527 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2531 LOGD("audiosink property - latency=%s", latency);
2533 MMPLAYER_FREEIF(latency);
2539 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2541 MMPlayerGstElement *audiobin = NULL;
2544 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2546 audiobin = player->pipeline->audiobin;
2548 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2549 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2550 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2552 if (player->video360_yaw_radians <= M_PI &&
2553 player->video360_yaw_radians >= -M_PI &&
2554 player->video360_pitch_radians <= M_PI_2 &&
2555 player->video360_pitch_radians >= -M_PI_2) {
2556 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2557 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2558 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2559 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2560 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2561 "source-orientation-y", player->video360_metadata.init_view_heading,
2562 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2569 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2571 MMPlayerGstElement *audiobin = NULL;
2572 MMHandleType attrs = 0;
2573 GList *element_bucket = NULL;
2574 GstCaps *acaps = NULL;
2575 GstPad *sink_pad = NULL;
2578 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2579 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2581 audiobin = player->pipeline->audiobin;
2582 attrs = MMPLAYER_GET_ATTRS(player);
2585 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2587 /* replaygain volume */
2588 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2589 if (player->sound.rg_enable)
2590 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2595 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2597 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2598 gchar *dst_format = NULL;
2600 int dst_samplerate = 0;
2601 int dst_channels = 0;
2602 GstCaps *caps = NULL;
2603 char *caps_str = NULL;
2605 /* get conf. values */
2606 mm_attrs_multiple_get(player->attrs, NULL,
2607 "pcm_audioformat", &dst_format, &dst_len,
2608 "pcm_extraction_samplerate", &dst_samplerate,
2609 "pcm_extraction_channels", &dst_channels,
2612 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2615 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2616 caps = gst_caps_new_simple("audio/x-raw",
2617 "format", G_TYPE_STRING, dst_format,
2618 "rate", G_TYPE_INT, dst_samplerate,
2619 "channels", G_TYPE_INT, dst_channels,
2622 caps_str = gst_caps_to_string(caps);
2623 LOGD("new caps : %s", caps_str);
2625 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2628 gst_caps_unref(caps);
2629 MMPLAYER_FREEIF(caps_str);
2631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2635 /* raw pad handling signal, audiosink will be added after getting signal */
2636 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2637 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2641 /* normal playback */
2644 /* for logical volume control */
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2648 if (player->sound.mute) {
2649 LOGD("mute enabled");
2650 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2653 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2655 /* audio effect element. if audio effect is enabled */
2656 if ((strcmp(player->ini.audioeffect_element, ""))
2658 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2661 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2663 if ((!player->bypass_audio_effect)
2664 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2665 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2666 if (!_mmplayer_audio_effect_custom_apply(player))
2667 LOGI("apply audio effect(custom) setting success");
2671 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2672 && (player->set_mode.rich_audio))
2673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2676 /* create audio sink */
2677 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2678 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2679 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2681 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2682 if (player->is_360_feature_enabled &&
2683 player->is_content_spherical &&
2685 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2686 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2687 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2689 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2691 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2693 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2694 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2696 gst_caps_unref(acaps);
2698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2700 player->is_openal_plugin_used = TRUE;
2702 if (player->is_360_feature_enabled && player->is_content_spherical)
2703 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2707 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2708 (player->videodec_linked && player->ini.use_system_clock)) {
2709 LOGD("system clock will be used.");
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2713 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2714 __mmplayer_gst_set_pulsesink_property(player, attrs);
2715 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2716 __mmplayer_gst_set_openalsink_property(player);
2719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2722 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2723 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2724 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2725 gst_object_unref(GST_OBJECT(sink_pad));
2727 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2730 *bucket = element_bucket;
2733 return MM_ERROR_NONE;
2736 g_list_free(element_bucket);
2740 return MM_ERROR_PLAYER_INTERNAL;
2744 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2746 MMPlayerGstElement *first_element = NULL;
2747 MMPlayerGstElement *audiobin = NULL;
2749 GstPad *ghostpad = NULL;
2750 GList *element_bucket = NULL;
2754 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2757 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2759 LOGE("failed to allocate memory for audiobin");
2760 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2764 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2765 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2766 if (!audiobin[MMPLAYER_A_BIN].gst) {
2767 LOGE("failed to create audiobin");
2772 player->pipeline->audiobin = audiobin;
2774 /* create audio filters and audiosink */
2775 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2778 /* adding created elements to bin */
2779 LOGD("adding created elements to bin");
2780 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2783 /* linking elements in the bucket by added order. */
2784 LOGD("Linking elements in the bucket by added order.");
2785 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2788 /* get first element's sinkpad for creating ghostpad */
2789 first_element = (MMPlayerGstElement *)element_bucket->data;
2790 if (!first_element) {
2791 LOGE("failed to get first elem");
2795 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2797 LOGE("failed to get pad from first element of audiobin");
2801 ghostpad = gst_ghost_pad_new("sink", pad);
2803 LOGE("failed to create ghostpad");
2807 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2808 LOGE("failed to add ghostpad to audiobin");
2812 gst_object_unref(pad);
2814 g_list_free(element_bucket);
2817 return MM_ERROR_NONE;
2820 LOGD("ERROR : releasing audiobin");
2823 gst_object_unref(GST_OBJECT(pad));
2826 gst_object_unref(GST_OBJECT(ghostpad));
2829 g_list_free(element_bucket);
2831 /* release element which are not added to bin */
2832 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2833 /* NOTE : skip bin */
2834 if (audiobin[i].gst) {
2835 GstObject *parent = NULL;
2836 parent = gst_element_get_parent(audiobin[i].gst);
2839 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2840 audiobin[i].gst = NULL;
2842 gst_object_unref(GST_OBJECT(parent));
2846 /* release audiobin with it's childs */
2847 if (audiobin[MMPLAYER_A_BIN].gst)
2848 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2850 MMPLAYER_FREEIF(audiobin);
2852 player->pipeline->audiobin = NULL;
2854 return MM_ERROR_PLAYER_INTERNAL;
2858 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2860 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2864 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2866 int ret = MM_ERROR_NONE;
2868 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2869 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2871 MMPLAYER_VIDEO_BO_LOCK(player);
2873 if (player->video_bo_list) {
2874 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2875 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2876 if (tmp && tmp->bo == bo) {
2878 LOGD("release bo %p", bo);
2879 tbm_bo_unref(tmp->bo);
2880 MMPLAYER_VIDEO_BO_UNLOCK(player);
2881 MMPLAYER_VIDEO_BO_SIGNAL(player);
2886 /* hw codec is running or the list was reset for DRC. */
2887 LOGW("there is no bo list.");
2889 MMPLAYER_VIDEO_BO_UNLOCK(player);
2891 LOGW("failed to find bo %p", bo);
2896 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2901 MMPLAYER_RETURN_IF_FAIL(player);
2903 MMPLAYER_VIDEO_BO_LOCK(player);
2904 if (player->video_bo_list) {
2905 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2906 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2907 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2910 tbm_bo_unref(tmp->bo);
2914 g_list_free(player->video_bo_list);
2915 player->video_bo_list = NULL;
2917 player->video_bo_size = 0;
2918 MMPLAYER_VIDEO_BO_UNLOCK(player);
2925 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2928 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2929 gboolean ret = TRUE;
2931 /* check DRC, if it is, destroy the prev bo list to create again */
2932 if (player->video_bo_size != size) {
2933 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2934 __mmplayer_video_stream_destroy_bo_list(player);
2935 player->video_bo_size = size;
2938 MMPLAYER_VIDEO_BO_LOCK(player);
2940 if ((!player->video_bo_list) ||
2941 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2943 /* create bo list */
2945 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2947 if (player->video_bo_list) {
2948 /* if bo list did not created all, try it again. */
2949 idx = g_list_length(player->video_bo_list);
2950 LOGD("bo list exist(len: %d)", idx);
2953 for (; idx < player->ini.num_of_video_bo; idx++) {
2954 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2956 LOGE("Fail to alloc bo_info.");
2959 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2961 LOGE("Fail to tbm_bo_alloc.");
2962 MMPLAYER_FREEIF(bo_info);
2965 bo_info->used = FALSE;
2966 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2969 /* update video num buffers */
2970 player->video_num_buffers = idx;
2971 if (idx == player->ini.num_of_video_bo)
2972 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2975 MMPLAYER_VIDEO_BO_UNLOCK(player);
2979 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2983 /* get bo from list*/
2984 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2985 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2986 if (tmp && (tmp->used == FALSE)) {
2987 LOGD("found bo %p to use", tmp->bo);
2989 MMPLAYER_VIDEO_BO_UNLOCK(player);
2990 return tbm_bo_ref(tmp->bo);
2994 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
2995 MMPLAYER_VIDEO_BO_UNLOCK(player);
2999 if (player->ini.video_bo_timeout <= 0) {
3000 MMPLAYER_VIDEO_BO_WAIT(player);
3002 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3003 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3010 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3012 mm_player_t *player = (mm_player_t *)data;
3014 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3016 /* send prerolled pkt */
3017 player->video_stream_prerolled = false;
3019 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3021 /* not to send prerolled pkt again */
3022 player->video_stream_prerolled = true;
3026 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3028 mm_player_t *player = (mm_player_t *)data;
3029 MMPlayerVideoStreamDataType *stream = NULL;
3030 GstMemory *mem = NULL;
3033 MMPLAYER_RETURN_IF_FAIL(player);
3034 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3036 if (player->video_stream_prerolled) {
3037 player->video_stream_prerolled = false;
3038 LOGD("skip the prerolled pkt not to send it again");
3042 /* clear stream data structure */
3043 stream = __mmplayer_create_stream_from_pad(pad);
3045 LOGE("failed to alloc stream");
3049 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3051 /* set size and timestamp */
3052 mem = gst_buffer_peek_memory(buffer, 0);
3053 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3054 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3056 /* check zero-copy */
3057 if (player->set_mode.video_zc &&
3058 player->set_mode.media_packet_video_stream &&
3059 gst_is_tizen_memory(mem)) {
3060 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3061 stream->internal_buffer = gst_buffer_ref(buffer);
3062 } else { /* sw codec */
3063 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3066 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3070 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3071 LOGE("failed to send video stream data.");
3078 LOGE("release video stream resource.");
3079 if (gst_is_tizen_memory(mem)) {
3081 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3083 tbm_bo_unref(stream->bo[i]);
3086 /* unref gst buffer */
3087 if (stream->internal_buffer)
3088 gst_buffer_unref(stream->internal_buffer);
3091 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3093 MMPLAYER_FREEIF(stream);
3098 __mmplayer_gst_set_video360_property(mm_player_t *player)
3100 MMPlayerGstElement *videobin = NULL;
3103 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3105 videobin = player->pipeline->videobin;
3107 /* Set spatial media metadata and/or user settings to the element.
3109 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3110 "projection-type", player->video360_metadata.projection_type, NULL);
3112 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3113 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3115 if (player->video360_metadata.full_pano_width_pixels &&
3116 player->video360_metadata.full_pano_height_pixels &&
3117 player->video360_metadata.cropped_area_image_width &&
3118 player->video360_metadata.cropped_area_image_height) {
3119 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3120 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3121 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3122 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3123 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3124 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3125 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3129 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3130 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3131 "horizontal-fov", player->video360_horizontal_fov,
3132 "vertical-fov", player->video360_vertical_fov, NULL);
3135 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3136 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3137 "zoom", 1.0f / player->video360_zoom, NULL);
3140 if (player->video360_yaw_radians <= M_PI &&
3141 player->video360_yaw_radians >= -M_PI &&
3142 player->video360_pitch_radians <= M_PI_2 &&
3143 player->video360_pitch_radians >= -M_PI_2) {
3144 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3145 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3146 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3147 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3148 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3149 "pose-yaw", player->video360_metadata.init_view_heading,
3150 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3153 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3154 "passthrough", !player->is_video360_enabled, NULL);
3161 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3163 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3164 GList *element_bucket = NULL;
3167 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3169 /* create video360 filter */
3170 if (player->is_360_feature_enabled && player->is_content_spherical) {
3171 LOGD("create video360 element");
3172 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3173 __mmplayer_gst_set_video360_property(player);
3177 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3178 LOGD("skip creating the videoconv and rotator");
3179 return MM_ERROR_NONE;
3182 /* in case of sw codec & overlay surface type, except 360 playback.
3183 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3184 LOGD("create video converter: %s", video_csc);
3185 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3187 /* set video rotator */
3188 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3191 *bucket = element_bucket;
3193 return MM_ERROR_NONE;
3195 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3196 g_list_free(element_bucket);
3200 return MM_ERROR_PLAYER_INTERNAL;
3204 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3206 gchar *factory_name = NULL;
3208 switch (surface_type) {
3209 case MM_DISPLAY_SURFACE_OVERLAY:
3210 if (strlen(player->ini.videosink_element_overlay) > 0)
3211 factory_name = player->ini.videosink_element_overlay;
3213 case MM_DISPLAY_SURFACE_REMOTE:
3214 case MM_DISPLAY_SURFACE_NULL:
3215 if (strlen(player->ini.videosink_element_fake) > 0)
3216 factory_name = player->ini.videosink_element_fake;
3219 LOGE("unidentified surface type");
3223 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3224 return factory_name;
3228 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3230 gchar *factory_name = NULL;
3231 MMPlayerGstElement *videobin = NULL;
3236 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3238 videobin = player->pipeline->videobin;
3239 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3241 attrs = MMPLAYER_GET_ATTRS(player);
3243 LOGE("cannot get content attribute");
3244 return MM_ERROR_PLAYER_INTERNAL;
3247 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3248 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3249 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3251 /* support shard memory with S/W codec on HawkP */
3252 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3253 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3254 "use-tbm", use_tbm, NULL);
3258 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3259 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3262 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3264 LOGD("disable last-sample");
3265 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3268 if (player->set_mode.media_packet_video_stream) {
3270 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3271 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3272 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3274 __mmplayer_add_signal_connection(player,
3275 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3276 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3278 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3281 __mmplayer_add_signal_connection(player,
3282 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3283 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3285 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3289 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3290 return MM_ERROR_PLAYER_INTERNAL;
3292 if (videobin[MMPLAYER_V_SINK].gst) {
3293 GstPad *sink_pad = NULL;
3294 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3296 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3297 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3298 gst_object_unref(GST_OBJECT(sink_pad));
3300 LOGE("failed to get sink pad from videosink");
3304 return MM_ERROR_NONE;
3309 * - video overlay surface(arm/x86) : tizenwlsink
3312 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3315 GList *element_bucket = NULL;
3316 MMPlayerGstElement *first_element = NULL;
3317 MMPlayerGstElement *videobin = NULL;
3318 gchar *videosink_factory_name = NULL;
3321 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3324 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3326 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3328 player->pipeline->videobin = videobin;
3331 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3332 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3333 if (!videobin[MMPLAYER_V_BIN].gst) {
3334 LOGE("failed to create videobin");
3338 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3341 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3342 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3344 /* additional setting for sink plug-in */
3345 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3346 LOGE("failed to set video property");
3350 /* store it as it's sink element */
3351 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3353 /* adding created elements to bin */
3354 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3355 LOGE("failed to add elements");
3359 /* Linking elements in the bucket by added order */
3360 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3361 LOGE("failed to link elements");
3365 /* get first element's sinkpad for creating ghostpad */
3366 first_element = (MMPlayerGstElement *)element_bucket->data;
3367 if (!first_element) {
3368 LOGE("failed to get first element from bucket");
3372 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3374 LOGE("failed to get pad from first element");
3378 /* create ghostpad */
3379 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3380 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3381 LOGE("failed to add ghostpad to videobin");
3384 gst_object_unref(pad);
3386 /* done. free allocated variables */
3387 g_list_free(element_bucket);
3391 return MM_ERROR_NONE;
3394 LOGE("ERROR : releasing videobin");
3395 g_list_free(element_bucket);
3398 gst_object_unref(GST_OBJECT(pad));
3400 /* release videobin with it's childs */
3401 if (videobin[MMPLAYER_V_BIN].gst)
3402 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3404 MMPLAYER_FREEIF(videobin);
3405 player->pipeline->videobin = NULL;
3407 return MM_ERROR_PLAYER_INTERNAL;
3411 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3413 GList *element_bucket = NULL;
3414 MMPlayerGstElement *textbin = player->pipeline->textbin;
3416 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3417 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3418 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3419 "signal-handoffs", FALSE,
3422 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3423 __mmplayer_add_signal_connection(player,
3424 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3425 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3427 G_CALLBACK(__mmplayer_update_subtitle),
3430 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3431 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3433 if (!player->play_subtitle) {
3434 LOGD("add textbin sink as sink element of whole pipeline.");
3435 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3438 /* adding created elements to bin */
3439 LOGD("adding created elements to bin");
3440 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3441 LOGE("failed to add elements");
3445 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3446 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3447 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3449 /* linking elements in the bucket by added order. */
3450 LOGD("Linking elements in the bucket by added order.");
3451 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3452 LOGE("failed to link elements");
3456 /* done. free allocated variables */
3457 g_list_free(element_bucket);
3459 if (textbin[MMPLAYER_T_QUEUE].gst) {
3461 GstPad *ghostpad = NULL;
3463 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3465 LOGE("failed to get sink pad of text queue");
3469 ghostpad = gst_ghost_pad_new("text_sink", pad);
3470 gst_object_unref(pad);
3473 LOGE("failed to create ghostpad of textbin");
3477 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3478 LOGE("failed to add ghostpad to textbin");
3479 gst_object_unref(ghostpad);
3484 return MM_ERROR_NONE;
3487 g_list_free(element_bucket);
3489 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3490 LOGE("remove textbin sink from sink list");
3491 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3494 /* release element at __mmplayer_gst_create_text_sink_bin */
3495 return MM_ERROR_PLAYER_INTERNAL;
3499 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3501 MMPlayerGstElement *textbin = NULL;
3502 GList *element_bucket = NULL;
3503 int surface_type = 0;
3508 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3511 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3513 LOGE("failed to allocate memory for textbin");
3514 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3518 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3519 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3520 if (!textbin[MMPLAYER_T_BIN].gst) {
3521 LOGE("failed to create textbin");
3526 player->pipeline->textbin = textbin;
3529 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3530 LOGD("surface type for subtitle : %d", surface_type);
3531 switch (surface_type) {
3532 case MM_DISPLAY_SURFACE_OVERLAY:
3533 case MM_DISPLAY_SURFACE_NULL:
3534 case MM_DISPLAY_SURFACE_REMOTE:
3535 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3536 LOGE("failed to make plain text elements");
3547 return MM_ERROR_NONE;
3551 LOGD("ERROR : releasing textbin");
3553 g_list_free(element_bucket);
3555 /* release signal */
3556 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3558 /* release element which are not added to bin */
3559 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3560 /* NOTE : skip bin */
3561 if (textbin[i].gst) {
3562 GstObject *parent = NULL;
3563 parent = gst_element_get_parent(textbin[i].gst);
3566 gst_object_unref(GST_OBJECT(textbin[i].gst));
3567 textbin[i].gst = NULL;
3569 gst_object_unref(GST_OBJECT(parent));
3574 /* release textbin with it's childs */
3575 if (textbin[MMPLAYER_T_BIN].gst)
3576 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3578 MMPLAYER_FREEIF(player->pipeline->textbin);
3579 player->pipeline->textbin = NULL;
3582 return MM_ERROR_PLAYER_INTERNAL;
3586 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3588 MMPlayerGstElement *mainbin = NULL;
3589 MMPlayerGstElement *textbin = NULL;
3590 MMHandleType attrs = 0;
3591 GstElement *subsrc = NULL;
3592 GstElement *subparse = NULL;
3593 gchar *subtitle_uri = NULL;
3594 const gchar *charset = NULL;
3600 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3602 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3604 mainbin = player->pipeline->mainbin;
3606 attrs = MMPLAYER_GET_ATTRS(player);
3608 LOGE("cannot get content attribute");
3609 return MM_ERROR_PLAYER_INTERNAL;
3612 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3613 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3614 LOGE("subtitle uri is not proper filepath.");
3615 return MM_ERROR_PLAYER_INVALID_URI;
3618 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3619 LOGE("failed to get storage info of subtitle path");
3620 return MM_ERROR_PLAYER_INVALID_URI;
3623 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3625 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3626 player->subtitle_language_list = NULL;
3627 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3629 /* create the subtitle source */
3630 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3632 LOGE("failed to create filesrc element");
3635 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3637 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3638 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3640 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3641 LOGW("failed to add queue");
3642 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3643 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3644 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3649 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3651 LOGE("failed to create subparse element");
3655 charset = util_get_charset(subtitle_uri);
3657 LOGD("detected charset is %s", charset);
3658 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3661 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3662 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3664 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3665 LOGW("failed to add subparse");
3666 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3667 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3668 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3672 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3673 LOGW("failed to link subsrc and subparse");
3677 player->play_subtitle = TRUE;
3678 player->adjust_subtitle_pos = 0;
3680 LOGD("play subtitle using subtitle file");
3682 if (player->pipeline->textbin == NULL) {
3683 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3684 LOGE("failed to create text sink bin. continuing without text");
3688 textbin = player->pipeline->textbin;
3690 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3691 LOGW("failed to add textbin");
3693 /* release signal */
3694 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3696 /* release textbin with it's childs */
3697 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3698 MMPLAYER_FREEIF(player->pipeline->textbin);
3699 player->pipeline->textbin = textbin = NULL;
3703 LOGD("link text input selector and textbin ghost pad");
3705 player->textsink_linked = 1;
3706 player->external_text_idx = 0;
3707 LOGI("textsink is linked");
3709 textbin = player->pipeline->textbin;
3710 LOGD("text bin has been created. reuse it.");
3711 player->external_text_idx = 1;
3714 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3715 LOGW("failed to link subparse and textbin");
3719 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3721 LOGE("failed to get sink pad from textsink to probe data");
3725 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3726 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3728 gst_object_unref(pad);
3731 /* create dot. for debugging */
3732 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3735 return MM_ERROR_NONE;
3738 /* release text pipeline resource */
3739 player->textsink_linked = 0;
3741 /* release signal */
3742 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3744 if (player->pipeline->textbin) {
3745 LOGE("remove textbin");
3747 /* release textbin with it's childs */
3748 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3749 MMPLAYER_FREEIF(player->pipeline->textbin);
3750 player->pipeline->textbin = NULL;
3754 /* release subtitle elem */
3755 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3756 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3758 return MM_ERROR_PLAYER_INTERNAL;
3762 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3764 mm_player_t *player = (mm_player_t *)data;
3765 MMMessageParamType msg = {0, };
3766 GstClockTime duration = 0;
3767 gpointer text = NULL;
3768 guint text_size = 0;
3769 gboolean ret = TRUE;
3770 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3774 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3775 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3777 if (player->is_subtitle_force_drop) {
3778 LOGW("subtitle is dropped forcedly.");
3782 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3783 text = mapinfo.data;
3784 text_size = mapinfo.size;
3785 duration = GST_BUFFER_DURATION(buffer);
3787 if (player->set_mode.subtitle_off) {
3788 LOGD("subtitle is OFF.");
3792 if (!text || (text_size == 0)) {
3793 LOGD("There is no subtitle to be displayed.");
3797 msg.data = (void *)text;
3798 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3800 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3802 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3803 gst_buffer_unmap(buffer, &mapinfo);
3810 static GstPadProbeReturn
3811 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3813 mm_player_t *player = (mm_player_t *)u_data;
3814 GstClockTime cur_timestamp = 0;
3815 gint64 adjusted_timestamp = 0;
3816 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3818 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3820 if (player->set_mode.subtitle_off) {
3821 LOGD("subtitle is OFF.");
3825 if (player->adjust_subtitle_pos == 0) {
3826 LOGD("nothing to do");
3830 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3831 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3833 if (adjusted_timestamp < 0) {
3834 LOGD("adjusted_timestamp under zero");
3839 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3840 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3841 GST_TIME_ARGS(cur_timestamp),
3842 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3844 return GST_PAD_PROBE_OK;
3848 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3852 /* check player and subtitlebin are created */
3853 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3854 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3856 if (position == 0) {
3857 LOGD("nothing to do");
3859 return MM_ERROR_NONE;
3863 case MM_PLAYER_POS_FORMAT_TIME:
3865 /* check current postion */
3866 player->adjust_subtitle_pos = position;
3868 LOGD("save adjust_subtitle_pos in player") ;
3874 LOGW("invalid format.");
3876 return MM_ERROR_INVALID_ARGUMENT;
3882 return MM_ERROR_NONE;
3886 * This function is to create audio or video pipeline for playing.
3888 * @param player [in] handle of player
3890 * @return This function returns zero on success.
3895 __mmplayer_gst_create_pipeline(mm_player_t *player)
3897 int ret = MM_ERROR_NONE;
3898 MMPlayerGstElement *mainbin = NULL;
3899 MMHandleType attrs = 0;
3902 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3904 /* get profile attribute */
3905 attrs = MMPLAYER_GET_ATTRS(player);
3907 LOGE("failed to get content attribute");
3911 /* create pipeline handles */
3912 if (player->pipeline) {
3913 LOGE("pipeline should be released before create new one");
3917 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3918 if (player->pipeline == NULL)
3921 /* create mainbin */
3922 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3923 if (mainbin == NULL)
3926 /* create pipeline */
3927 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3928 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3929 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3930 LOGE("failed to create pipeline");
3935 player->pipeline->mainbin = mainbin;
3937 /* create the source and decoder elements */
3938 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3939 ret = __mmplayer_gst_build_es_pipeline(player);
3941 ret = __mmplayer_gst_build_pipeline(player);
3943 if (ret != MM_ERROR_NONE) {
3944 LOGE("failed to create some elements");
3948 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3949 if (__mmplayer_check_subtitle(player)
3950 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3951 LOGE("failed to create text pipeline");
3954 ret = __mmplayer_gst_add_bus_watch(player);
3955 if (ret != MM_ERROR_NONE) {
3956 LOGE("failed to add bus watch");
3961 return MM_ERROR_NONE;
3964 __mmplayer_gst_destroy_pipeline(player);
3965 return MM_ERROR_PLAYER_INTERNAL;
3969 __mmplayer_reset_gapless_state(mm_player_t *player)
3972 MMPLAYER_RETURN_IF_FAIL(player
3974 && player->pipeline->audiobin
3975 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3977 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3984 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
3987 int ret = MM_ERROR_NONE;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
3993 /* cleanup stuffs */
3994 MMPLAYER_FREEIF(player->type);
3995 player->no_more_pad = FALSE;
3996 player->num_dynamic_pad = 0;
3997 player->demux_pad_index = 0;
3999 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4000 player->subtitle_language_list = NULL;
4001 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4003 __mmplayer_reset_gapless_state(player);
4005 if (player->streamer) {
4006 __mm_player_streaming_initialize(player->streamer, FALSE);
4007 __mm_player_streaming_destroy(player->streamer);
4008 player->streamer = NULL;
4011 /* cleanup unlinked mime type */
4012 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4013 MMPLAYER_FREEIF(player->unlinked_video_mime);
4014 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4016 /* cleanup running stuffs */
4017 __mmplayer_cancel_eos_timer(player);
4019 /* cleanup gst stuffs */
4020 if (player->pipeline) {
4021 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4022 GstTagList *tag_list = player->pipeline->tag_list;
4024 /* first we need to disconnect all signal hander */
4025 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4028 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4029 MMPlayerGstElement *videobin = player->pipeline->videobin;
4030 MMPlayerGstElement *textbin = player->pipeline->textbin;
4031 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4032 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4033 gst_object_unref(bus);
4035 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4036 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4037 if (ret != MM_ERROR_NONE) {
4038 LOGE("fail to change state to NULL");
4039 return MM_ERROR_PLAYER_INTERNAL;
4042 LOGW("succeeded in changing state to NULL");
4044 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4047 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4048 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4050 /* free avsysaudiosink
4051 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4052 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4054 MMPLAYER_FREEIF(audiobin);
4055 MMPLAYER_FREEIF(videobin);
4056 MMPLAYER_FREEIF(textbin);
4057 MMPLAYER_FREEIF(mainbin);
4061 gst_tag_list_unref(tag_list);
4063 MMPLAYER_FREEIF(player->pipeline);
4065 MMPLAYER_FREEIF(player->album_art);
4067 if (player->v_stream_caps) {
4068 gst_caps_unref(player->v_stream_caps);
4069 player->v_stream_caps = NULL;
4072 if (player->a_stream_caps) {
4073 gst_caps_unref(player->a_stream_caps);
4074 player->a_stream_caps = NULL;
4077 if (player->s_stream_caps) {
4078 gst_caps_unref(player->s_stream_caps);
4079 player->s_stream_caps = NULL;
4081 __mmplayer_track_destroy(player);
4083 if (player->sink_elements)
4084 g_list_free(player->sink_elements);
4085 player->sink_elements = NULL;
4087 if (player->bufmgr) {
4088 tbm_bufmgr_deinit(player->bufmgr);
4089 player->bufmgr = NULL;
4092 LOGW("finished destroy pipeline");
4100 __mmplayer_gst_realize(mm_player_t *player)
4103 int ret = MM_ERROR_NONE;
4107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4109 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4111 ret = __mmplayer_gst_create_pipeline(player);
4113 LOGE("failed to create pipeline");
4117 /* set pipeline state to READY */
4118 /* NOTE : state change to READY must be performed sync. */
4119 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4120 ret = __mmplayer_gst_set_state(player,
4121 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4123 if (ret != MM_ERROR_NONE) {
4124 /* return error if failed to set state */
4125 LOGE("failed to set READY state");
4129 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4131 /* create dot before error-return. for debugging */
4132 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4140 __mmplayer_gst_unrealize(mm_player_t *player)
4142 int ret = MM_ERROR_NONE;
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4149 MMPLAYER_PRINT_STATE(player);
4151 /* release miscellaneous information */
4152 __mmplayer_release_misc(player);
4154 /* destroy pipeline */
4155 ret = __mmplayer_gst_destroy_pipeline(player);
4156 if (ret != MM_ERROR_NONE) {
4157 LOGE("failed to destory pipeline");
4161 /* release miscellaneous information.
4162 these info needs to be released after pipeline is destroyed. */
4163 __mmplayer_release_misc_post(player);
4165 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4173 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4178 LOGW("set_message_callback is called with invalid player handle");
4179 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4182 player->msg_cb = callback;
4183 player->msg_cb_param = user_param;
4185 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4189 return MM_ERROR_NONE;
4193 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4195 int ret = MM_ERROR_NONE;
4200 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4201 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4202 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4204 memset(data, 0, sizeof(MMPlayerParseProfile));
4206 if (strstr(uri, "es_buff://")) {
4207 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4208 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4209 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4210 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4212 tmp = g_ascii_strdown(uri, strlen(uri));
4213 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4214 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4216 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4218 } else if (strstr(uri, "mms://")) {
4219 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4220 } else if ((path = strstr(uri, "mem://"))) {
4221 ret = __mmplayer_set_mem_uri(data, path, param);
4223 ret = __mmplayer_set_file_uri(data, uri);
4226 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4227 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4228 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4229 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4231 /* dump parse result */
4232 SECURE_LOGW("incoming uri : %s", uri);
4233 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4234 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4242 __mmplayer_can_do_interrupt(mm_player_t *player)
4244 if (!player || !player->pipeline || !player->attrs) {
4245 LOGW("not initialized");
4249 if (player->audio_stream_render_cb) {
4250 LOGW("not support in pcm extraction mode");
4254 /* check if seeking */
4255 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4256 MMMessageParamType msg_param;
4257 memset(&msg_param, 0, sizeof(MMMessageParamType));
4258 msg_param.code = MM_ERROR_PLAYER_SEEK;
4259 player->seek_state = MMPLAYER_SEEK_NONE;
4260 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4264 /* check other thread */
4265 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4266 LOGW("locked already, cmd state : %d", player->cmd);
4268 /* check application command */
4269 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4270 LOGW("playing.. should wait cmd lock then, will be interrupted");
4272 /* lock will be released at mrp_resource_release_cb() */
4273 MMPLAYER_CMD_LOCK(player);
4276 LOGW("nothing to do");
4279 LOGW("can interrupt immediately");
4283 FAILED: /* with CMD UNLOCKED */
4286 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4291 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4294 mm_player_t *player = NULL;
4298 if (user_data == NULL) {
4299 LOGE("- user_data is null");
4302 player = (mm_player_t *)user_data;
4304 /* do something to release resource here.
4305 * player stop and interrupt forwarding */
4306 if (!__mmplayer_can_do_interrupt(player)) {
4307 LOGW("no need to interrupt, so leave");
4309 MMMessageParamType msg = {0, };
4312 player->interrupted_by_resource = TRUE;
4314 /* get last play position */
4315 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4316 LOGW("failed to get play position.");
4318 msg.union_type = MM_MSG_UNION_TIME;
4319 msg.time.elapsed = pos;
4320 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4322 LOGD("video resource conflict so, resource will be freed by unrealizing");
4323 if (_mmplayer_unrealize((MMHandleType)player))
4324 LOGW("failed to unrealize");
4326 /* lock is called in __mmplayer_can_do_interrupt() */
4327 MMPLAYER_CMD_UNLOCK(player);
4330 if (res == player->video_overlay_resource)
4331 player->video_overlay_resource = FALSE;
4333 player->video_decoder_resource = FALSE;
4341 __mmplayer_initialize_video_roi(mm_player_t *player)
4343 player->video_roi.scale_x = 0.0;
4344 player->video_roi.scale_y = 0.0;
4345 player->video_roi.scale_width = 1.0;
4346 player->video_roi.scale_height = 1.0;
4350 _mmplayer_create_player(MMHandleType handle)
4352 int ret = MM_ERROR_PLAYER_INTERNAL;
4353 bool enabled = false;
4355 mm_player_t *player = MM_PLAYER_CAST(handle);
4359 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4361 /* initialize player state */
4362 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4363 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4364 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4365 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4367 /* check current state */
4368 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4370 /* construct attributes */
4371 player->attrs = _mmplayer_construct_attribute(handle);
4373 if (!player->attrs) {
4374 LOGE("Failed to construct attributes");
4378 /* initialize gstreamer with configured parameter */
4379 if (!__mmplayer_init_gstreamer(player)) {
4380 LOGE("Initializing gstreamer failed");
4381 _mmplayer_deconstruct_attribute(handle);
4385 /* create lock. note that g_tread_init() has already called in gst_init() */
4386 g_mutex_init(&player->fsink_lock);
4388 /* create update tag lock */
4389 g_mutex_init(&player->update_tag_lock);
4391 /* create gapless play mutex */
4392 g_mutex_init(&player->gapless_play_thread_mutex);
4394 /* create gapless play cond */
4395 g_cond_init(&player->gapless_play_thread_cond);
4397 /* create gapless play thread */
4398 player->gapless_play_thread =
4399 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4400 if (!player->gapless_play_thread) {
4401 LOGE("failed to create gapless play thread");
4402 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4403 g_mutex_clear(&player->gapless_play_thread_mutex);
4404 g_cond_clear(&player->gapless_play_thread_cond);
4408 player->bus_msg_q = g_queue_new();
4409 if (!player->bus_msg_q) {
4410 LOGE("failed to create queue for bus_msg");
4411 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4415 ret = _mmplayer_initialize_video_capture(player);
4416 if (ret != MM_ERROR_NONE) {
4417 LOGE("failed to initialize video capture");
4421 /* initialize resource manager */
4422 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4423 __resource_release_cb, player, &player->resource_manager)
4424 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4425 LOGE("failed to initialize resource manager");
4426 ret = MM_ERROR_PLAYER_INTERNAL;
4430 /* create video bo lock and cond */
4431 g_mutex_init(&player->video_bo_mutex);
4432 g_cond_init(&player->video_bo_cond);
4434 /* create media stream callback mutex */
4435 g_mutex_init(&player->media_stream_cb_lock);
4437 /* create subtitle info lock and cond */
4438 g_mutex_init(&player->subtitle_info_mutex);
4439 g_cond_init(&player->subtitle_info_cond);
4441 player->streaming_type = STREAMING_SERVICE_NONE;
4443 /* give default value of audio effect setting */
4444 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4445 player->sound.rg_enable = false;
4446 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4448 player->play_subtitle = FALSE;
4449 player->has_closed_caption = FALSE;
4450 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4451 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4452 player->pending_resume = FALSE;
4453 if (player->ini.dump_element_keyword[0][0] == '\0')
4454 player->ini.set_dump_element_flag = FALSE;
4456 player->ini.set_dump_element_flag = TRUE;
4458 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4459 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4460 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4462 /* Set video360 settings to their defaults for just-created player.
4465 player->is_360_feature_enabled = FALSE;
4466 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4467 LOGI("spherical feature info: %d", enabled);
4469 player->is_360_feature_enabled = TRUE;
4471 LOGE("failed to get spherical feature info");
4474 player->is_content_spherical = FALSE;
4475 player->is_video360_enabled = TRUE;
4476 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4477 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4478 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4479 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4480 player->video360_zoom = 1.0f;
4481 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4482 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4484 __mmplayer_initialize_video_roi(player);
4486 /* set player state to null */
4487 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4488 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4492 return MM_ERROR_NONE;
4496 g_mutex_clear(&player->fsink_lock);
4497 /* free update tag lock */
4498 g_mutex_clear(&player->update_tag_lock);
4499 g_queue_free(player->bus_msg_q);
4500 /* free gapless play thread */
4501 if (player->gapless_play_thread) {
4502 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4503 player->gapless_play_thread_exit = TRUE;
4504 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4505 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4507 g_thread_join(player->gapless_play_thread);
4508 player->gapless_play_thread = NULL;
4510 g_mutex_clear(&player->gapless_play_thread_mutex);
4511 g_cond_clear(&player->gapless_play_thread_cond);
4514 /* release attributes */
4515 _mmplayer_deconstruct_attribute(handle);
4523 __mmplayer_init_gstreamer(mm_player_t *player)
4525 static gboolean initialized = FALSE;
4526 static const int max_argc = 50;
4528 gchar **argv = NULL;
4529 gchar **argv2 = NULL;
4535 LOGD("gstreamer already initialized.");
4540 argc = malloc(sizeof(int));
4541 argv = malloc(sizeof(gchar *) * max_argc);
4542 argv2 = malloc(sizeof(gchar *) * max_argc);
4544 if (!argc || !argv || !argv2)
4547 memset(argv, 0, sizeof(gchar *) * max_argc);
4548 memset(argv2, 0, sizeof(gchar *) * max_argc);
4552 argv[0] = g_strdup("mmplayer");
4555 for (i = 0; i < 5; i++) {
4556 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4557 if (strlen(player->ini.gst_param[i]) > 0) {
4558 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4563 /* we would not do fork for scanning plugins */
4564 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4567 /* check disable registry scan */
4568 if (player->ini.skip_rescan) {
4569 argv[*argc] = g_strdup("--gst-disable-registry-update");
4573 /* check disable segtrap */
4574 if (player->ini.disable_segtrap) {
4575 argv[*argc] = g_strdup("--gst-disable-segtrap");
4579 LOGD("initializing gstreamer with following parameter");
4580 LOGD("argc : %d", *argc);
4583 for (i = 0; i < arg_count; i++) {
4585 LOGD("argv[%d] : %s", i, argv2[i]);
4588 /* initializing gstreamer */
4589 if (!gst_init_check(argc, &argv, &err)) {
4590 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4597 for (i = 0; i < arg_count; i++) {
4598 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4599 MMPLAYER_FREEIF(argv2[i]);
4602 MMPLAYER_FREEIF(argv);
4603 MMPLAYER_FREEIF(argv2);
4604 MMPLAYER_FREEIF(argc);
4614 for (i = 0; i < arg_count; i++) {
4615 LOGD("free[%d] : %s", i, argv2[i]);
4616 MMPLAYER_FREEIF(argv2[i]);
4619 MMPLAYER_FREEIF(argv);
4620 MMPLAYER_FREEIF(argv2);
4621 MMPLAYER_FREEIF(argc);
4627 __mmplayer_check_async_state_transition(mm_player_t *player)
4629 GstState element_state = GST_STATE_VOID_PENDING;
4630 GstState element_pending_state = GST_STATE_VOID_PENDING;
4631 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4632 GstElement *element = NULL;
4633 gboolean async = FALSE;
4635 /* check player handle */
4636 MMPLAYER_RETURN_IF_FAIL(player &&
4638 player->pipeline->mainbin &&
4639 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4642 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4644 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4645 LOGD("don't need to check the pipeline state");
4649 MMPLAYER_PRINT_STATE(player);
4651 /* wait for state transition */
4652 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4653 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4655 if (ret == GST_STATE_CHANGE_FAILURE) {
4656 LOGE(" [%s] state : %s pending : %s",
4657 GST_ELEMENT_NAME(element),
4658 gst_element_state_get_name(element_state),
4659 gst_element_state_get_name(element_pending_state));
4661 /* dump state of all element */
4662 __mmplayer_dump_pipeline_state(player);
4667 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4672 _mmplayer_destroy(MMHandleType handle)
4674 mm_player_t *player = MM_PLAYER_CAST(handle);
4678 /* check player handle */
4679 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4681 /* destroy can called at anytime */
4682 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4684 /* check async state transition */
4685 __mmplayer_check_async_state_transition(player);
4687 /* release gapless play thread */
4688 if (player->gapless_play_thread) {
4689 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4690 player->gapless_play_thread_exit = TRUE;
4691 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4692 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4694 LOGD("waitting for gapless play thread exit");
4695 g_thread_join(player->gapless_play_thread);
4696 g_mutex_clear(&player->gapless_play_thread_mutex);
4697 g_cond_clear(&player->gapless_play_thread_cond);
4698 LOGD("gapless play thread released");
4701 _mmplayer_release_video_capture(player);
4703 /* de-initialize resource manager */
4704 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4705 player->resource_manager))
4706 LOGE("failed to deinitialize resource manager");
4708 /* release pipeline */
4709 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4710 LOGE("failed to destory pipeline");
4711 return MM_ERROR_PLAYER_INTERNAL;
4714 g_queue_free(player->bus_msg_q);
4716 /* release subtitle info lock and cond */
4717 g_mutex_clear(&player->subtitle_info_mutex);
4718 g_cond_clear(&player->subtitle_info_cond);
4720 __mmplayer_release_dump_list(player->dump_list);
4722 /* release miscellaneous information */
4723 __mmplayer_release_misc(player);
4725 /* release miscellaneous information.
4726 these info needs to be released after pipeline is destroyed. */
4727 __mmplayer_release_misc_post(player);
4729 /* release attributes */
4730 _mmplayer_deconstruct_attribute(handle);
4733 g_mutex_clear(&player->fsink_lock);
4736 g_mutex_clear(&player->update_tag_lock);
4738 /* release video bo lock and cond */
4739 g_mutex_clear(&player->video_bo_mutex);
4740 g_cond_clear(&player->video_bo_cond);
4742 /* release media stream callback lock */
4743 g_mutex_clear(&player->media_stream_cb_lock);
4747 return MM_ERROR_NONE;
4751 _mmplayer_realize(MMHandleType hplayer)
4753 mm_player_t *player = (mm_player_t *)hplayer;
4756 MMHandleType attrs = 0;
4757 int ret = MM_ERROR_NONE;
4761 /* check player handle */
4762 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4764 /* check current state */
4765 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4767 attrs = MMPLAYER_GET_ATTRS(player);
4769 LOGE("fail to get attributes.");
4770 return MM_ERROR_PLAYER_INTERNAL;
4772 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4773 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4775 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4776 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4778 if (ret != MM_ERROR_NONE) {
4779 LOGE("failed to parse profile");
4784 if (uri && (strstr(uri, "es_buff://"))) {
4785 if (strstr(uri, "es_buff://push_mode"))
4786 player->es_player_push_mode = TRUE;
4788 player->es_player_push_mode = FALSE;
4791 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4792 LOGW("mms protocol is not supported format.");
4793 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4796 if (MMPLAYER_IS_STREAMING(player))
4797 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4799 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4801 player->smooth_streaming = FALSE;
4802 player->videodec_linked = 0;
4803 player->audiodec_linked = 0;
4804 player->textsink_linked = 0;
4805 player->is_external_subtitle_present = FALSE;
4806 player->is_external_subtitle_added_now = FALSE;
4807 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4808 player->video360_metadata.is_spherical = -1;
4809 player->is_openal_plugin_used = FALSE;
4810 player->demux_pad_index = 0;
4811 player->subtitle_language_list = NULL;
4812 player->is_subtitle_force_drop = FALSE;
4813 player->last_multiwin_status = FALSE;
4815 __mmplayer_track_initialize(player);
4816 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4818 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4819 player->streamer = __mm_player_streaming_create();
4820 __mm_player_streaming_initialize(player->streamer, TRUE);
4823 /* realize pipeline */
4824 ret = __mmplayer_gst_realize(player);
4825 if (ret != MM_ERROR_NONE)
4826 LOGE("fail to realize the player.");
4828 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4836 _mmplayer_unrealize(MMHandleType hplayer)
4838 mm_player_t *player = (mm_player_t *)hplayer;
4839 int ret = MM_ERROR_NONE;
4843 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4845 MMPLAYER_CMD_UNLOCK(player);
4846 /* destroy the gst bus msg thread which is created during realize.
4847 this funct have to be called before getting cmd lock. */
4848 __mmplayer_bus_msg_thread_destroy(player);
4849 MMPLAYER_CMD_LOCK(player);
4851 /* check current state */
4852 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4854 /* check async state transition */
4855 __mmplayer_check_async_state_transition(player);
4857 /* unrealize pipeline */
4858 ret = __mmplayer_gst_unrealize(player);
4860 /* set asm stop if success */
4861 if (MM_ERROR_NONE == ret) {
4862 if (!player->interrupted_by_resource) {
4863 if (player->video_decoder_resource != NULL) {
4864 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4865 player->video_decoder_resource);
4866 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4867 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4869 player->video_decoder_resource = NULL;
4872 if (player->video_overlay_resource != NULL) {
4873 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4874 player->video_overlay_resource);
4875 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4876 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4878 player->video_overlay_resource = NULL;
4881 ret = mm_resource_manager_commit(player->resource_manager);
4882 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4883 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4886 LOGE("failed and don't change asm state to stop");
4894 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4896 mm_player_t *player = (mm_player_t *)hplayer;
4898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4900 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4904 _mmplayer_get_state(MMHandleType hplayer, int *state)
4906 mm_player_t *player = (mm_player_t *)hplayer;
4908 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4910 *state = MMPLAYER_CURRENT_STATE(player);
4912 return MM_ERROR_NONE;
4917 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4919 mm_player_t *player = (mm_player_t *)hplayer;
4920 GstElement *vol_element = NULL;
4925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4927 LOGD("volume [L]=%f:[R]=%f",
4928 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4930 /* invalid factor range or not */
4931 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4932 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4933 LOGE("Invalid factor!(valid factor:0~1.0)");
4934 return MM_ERROR_INVALID_ARGUMENT;
4938 /* not support to set other value into each channel */
4939 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4940 return MM_ERROR_INVALID_ARGUMENT;
4942 /* Save volume to handle. Currently the first array element will be saved. */
4943 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4945 /* check pipeline handle */
4946 if (!player->pipeline || !player->pipeline->audiobin) {
4947 LOGD("audiobin is not created yet");
4948 LOGD("but, current stored volume will be set when it's created.");
4950 /* NOTE : stored volume will be used in create_audiobin
4951 * returning MM_ERROR_NONE here makes application to able to
4952 * set volume at anytime.
4954 return MM_ERROR_NONE;
4957 /* setting volume to volume element */
4958 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4961 LOGD("volume is set [%f]", player->sound.volume);
4962 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4967 return MM_ERROR_NONE;
4971 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
4973 mm_player_t *player = (mm_player_t *)hplayer;
4978 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4979 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4981 /* returning stored volume */
4982 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4983 volume->level[i] = player->sound.volume;
4987 return MM_ERROR_NONE;
4991 _mmplayer_set_mute(MMHandleType hplayer, int mute)
4993 mm_player_t *player = (mm_player_t *)hplayer;
4994 GstElement *vol_element = NULL;
4998 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5000 /* mute value shoud 0 or 1 */
5001 if (mute != 0 && mute != 1) {
5002 LOGE("bad mute value");
5004 /* FIXIT : definitly, we need _BAD_PARAM error code */
5005 return MM_ERROR_INVALID_ARGUMENT;
5008 player->sound.mute = mute;
5010 /* just hold mute value if pipeline is not ready */
5011 if (!player->pipeline || !player->pipeline->audiobin) {
5012 LOGD("pipeline is not ready. holding mute value");
5013 return MM_ERROR_NONE;
5016 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5018 /* NOTE : volume will only created when the bt is enabled */
5020 LOGD("mute : %d", mute);
5021 g_object_set(vol_element, "mute", mute, NULL);
5023 LOGD("volume elemnet is not created. using volume in audiosink");
5027 return MM_ERROR_NONE;
5031 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5033 mm_player_t *player = (mm_player_t *)hplayer;
5037 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5038 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5040 /* just hold mute value if pipeline is not ready */
5041 if (!player->pipeline || !player->pipeline->audiobin) {
5042 LOGD("pipeline is not ready. returning stored value");
5043 *pmute = player->sound.mute;
5044 return MM_ERROR_NONE;
5047 *pmute = player->sound.mute;
5051 return MM_ERROR_NONE;
5055 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5057 mm_player_t *player = (mm_player_t *)hplayer;
5061 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5063 player->video_stream_changed_cb = callback;
5064 player->video_stream_changed_cb_user_param = user_param;
5065 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5069 return MM_ERROR_NONE;
5073 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5075 mm_player_t *player = (mm_player_t *)hplayer;
5079 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5081 player->audio_stream_changed_cb = callback;
5082 player->audio_stream_changed_cb_user_param = user_param;
5083 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5087 return MM_ERROR_NONE;
5091 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5093 mm_player_t *player = (mm_player_t *)hplayer;
5097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5099 player->audio_stream_render_cb = callback;
5100 player->audio_stream_cb_user_param = user_param;
5101 player->audio_stream_sink_sync = sync;
5102 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5106 return MM_ERROR_NONE;
5110 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5112 mm_player_t *player = (mm_player_t *)hplayer;
5116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5118 if (callback && !player->bufmgr)
5119 player->bufmgr = tbm_bufmgr_init(-1);
5121 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5122 player->video_stream_cb = callback;
5123 player->video_stream_cb_user_param = user_param;
5125 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5129 return MM_ERROR_NONE;
5133 _mmplayer_start(MMHandleType hplayer)
5135 mm_player_t *player = (mm_player_t *)hplayer;
5136 gint ret = MM_ERROR_NONE;
5140 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5142 /* check current state */
5143 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5145 /* start pipeline */
5146 ret = __mmplayer_gst_start(player);
5147 if (ret != MM_ERROR_NONE)
5148 LOGE("failed to start player.");
5150 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5151 LOGD("force playing start even during buffering");
5152 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5160 /* NOTE: post "not supported codec message" to application
5161 * when one codec is not found during AUTOPLUGGING in MSL.
5162 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5163 * And, if any codec is not found, don't send message here.
5164 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5167 __mmplayer_handle_missed_plugin(mm_player_t *player)
5169 MMMessageParamType msg_param;
5170 memset(&msg_param, 0, sizeof(MMMessageParamType));
5171 gboolean post_msg_direct = FALSE;
5175 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5177 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5178 player->not_supported_codec, player->can_support_codec);
5180 if (player->not_found_demuxer) {
5181 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5182 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5184 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5185 MMPLAYER_FREEIF(msg_param.data);
5187 return MM_ERROR_NONE;
5190 if (player->not_supported_codec) {
5191 if (player->can_support_codec) {
5192 // There is one codec to play
5193 post_msg_direct = TRUE;
5195 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5196 post_msg_direct = TRUE;
5199 if (post_msg_direct) {
5200 MMMessageParamType msg_param;
5201 memset(&msg_param, 0, sizeof(MMMessageParamType));
5203 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5204 LOGW("not found AUDIO codec, posting error code to application.");
5206 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5207 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5208 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5209 LOGW("not found VIDEO codec, posting error code to application.");
5211 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5212 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5215 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5217 MMPLAYER_FREEIF(msg_param.data);
5219 return MM_ERROR_NONE;
5221 // no any supported codec case
5222 LOGW("not found any codec, posting error code to application.");
5224 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5225 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5226 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5228 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5229 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5232 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5234 MMPLAYER_FREEIF(msg_param.data);
5240 return MM_ERROR_NONE;
5244 __mmplayer_check_pipeline(mm_player_t *player)
5246 GstState element_state = GST_STATE_VOID_PENDING;
5247 GstState element_pending_state = GST_STATE_VOID_PENDING;
5249 int ret = MM_ERROR_NONE;
5251 if (!player->gapless.reconfigure)
5254 LOGW("pipeline is under construction.");
5256 MMPLAYER_PLAYBACK_LOCK(player);
5257 MMPLAYER_PLAYBACK_UNLOCK(player);
5259 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5261 /* wait for state transition */
5262 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5263 if (ret == GST_STATE_CHANGE_FAILURE)
5264 LOGE("failed to change pipeline state within %d sec", timeout);
5267 /* NOTE : it should be able to call 'stop' anytime*/
5269 _mmplayer_stop(MMHandleType hplayer)
5271 mm_player_t *player = (mm_player_t *)hplayer;
5272 int ret = MM_ERROR_NONE;
5276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5278 /* check current state */
5279 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5281 /* check pipline building state */
5282 __mmplayer_check_pipeline(player);
5283 __mmplayer_reset_gapless_state(player);
5285 /* NOTE : application should not wait for EOS after calling STOP */
5286 __mmplayer_cancel_eos_timer(player);
5289 player->seek_state = MMPLAYER_SEEK_NONE;
5292 ret = __mmplayer_gst_stop(player);
5294 if (ret != MM_ERROR_NONE)
5295 LOGE("failed to stop player.");
5303 _mmplayer_pause(MMHandleType hplayer)
5305 mm_player_t *player = (mm_player_t *)hplayer;
5306 gint64 pos_nsec = 0;
5307 gboolean async = FALSE;
5308 gint ret = MM_ERROR_NONE;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 /* check current state */
5315 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5317 /* check pipline building state */
5318 __mmplayer_check_pipeline(player);
5320 switch (MMPLAYER_CURRENT_STATE(player)) {
5321 case MM_PLAYER_STATE_READY:
5323 /* check prepare async or not.
5324 * In the case of streaming playback, it's recommned to avoid blocking wait.
5326 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5327 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5329 /* Changing back sync of rtspsrc to async */
5330 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5331 LOGD("async prepare working mode for rtsp");
5337 case MM_PLAYER_STATE_PLAYING:
5339 /* NOTE : store current point to overcome some bad operation
5340 *(returning zero when getting current position in paused state) of some
5343 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5344 LOGW("getting current position failed in paused");
5346 player->last_position = pos_nsec;
5348 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5349 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5350 This causes problem is position calculation during normal pause resume scenarios also.
5351 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5352 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5353 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5354 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5360 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5361 LOGD("doing async pause in case of ms buff src");
5365 /* pause pipeline */
5366 ret = __mmplayer_gst_pause(player, async);
5368 if (ret != MM_ERROR_NONE)
5369 LOGE("failed to pause player. ret : 0x%x", ret);
5371 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5372 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5373 LOGE("failed to update display_rotation");
5381 /* in case of streaming, pause could take long time.*/
5383 _mmplayer_abort_pause(MMHandleType hplayer)
5385 mm_player_t *player = (mm_player_t *)hplayer;
5386 int ret = MM_ERROR_NONE;
5390 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5392 player->pipeline->mainbin,
5393 MM_ERROR_PLAYER_NOT_INITIALIZED);
5395 LOGD("set the pipeline state to READY");
5397 /* set state to READY */
5398 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5399 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5400 if (ret != MM_ERROR_NONE) {
5401 LOGE("fail to change state to READY");
5402 return MM_ERROR_PLAYER_INTERNAL;
5405 LOGD("succeeded in changing state to READY");
5410 _mmplayer_resume(MMHandleType hplayer)
5412 mm_player_t *player = (mm_player_t *)hplayer;
5413 int ret = MM_ERROR_NONE;
5414 gboolean async = FALSE;
5418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5420 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5421 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5422 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5426 /* Changing back sync mode rtspsrc to async */
5427 LOGD("async resume for rtsp case");
5431 /* check current state */
5432 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5434 ret = __mmplayer_gst_resume(player, async);
5435 if (ret != MM_ERROR_NONE)
5436 LOGE("failed to resume player.");
5438 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5439 LOGD("force resume even during buffering");
5440 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5449 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5451 mm_player_t *player = (mm_player_t *)hplayer;
5452 gint64 pos_nsec = 0;
5453 int ret = MM_ERROR_NONE;
5455 signed long long start = 0, stop = 0;
5456 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5459 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5460 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5462 /* The sound of video is not supported under 0.0 and over 2.0. */
5463 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5464 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5467 _mmplayer_set_mute(hplayer, mute);
5469 if (player->playback_rate == rate)
5470 return MM_ERROR_NONE;
5472 /* If the position is reached at start potion during fast backward, EOS is posted.
5473 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5475 player->playback_rate = rate;
5477 current_state = MMPLAYER_CURRENT_STATE(player);
5479 if (current_state != MM_PLAYER_STATE_PAUSED)
5480 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5482 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5484 if ((current_state == MM_PLAYER_STATE_PAUSED)
5485 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5486 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5487 pos_nsec = player->last_position;
5492 stop = GST_CLOCK_TIME_NONE;
5494 start = GST_CLOCK_TIME_NONE;
5498 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5499 player->playback_rate,
5501 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5502 GST_SEEK_TYPE_SET, start,
5503 GST_SEEK_TYPE_SET, stop)) {
5504 LOGE("failed to set speed playback");
5505 return MM_ERROR_PLAYER_SEEK;
5508 LOGD("succeeded to set speed playback as %0.1f", rate);
5512 return MM_ERROR_NONE;;
5516 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5518 mm_player_t *player = (mm_player_t *)hplayer;
5519 int ret = MM_ERROR_NONE;
5523 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5525 /* check pipline building state */
5526 __mmplayer_check_pipeline(player);
5528 ret = __mmplayer_gst_set_position(player, position, FALSE);
5536 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5538 mm_player_t *player = (mm_player_t *)hplayer;
5539 int ret = MM_ERROR_NONE;
5541 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5543 ret = __mmplayer_gst_get_position(player, position);
5549 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5551 mm_player_t *player = (mm_player_t *)hplayer;
5552 int ret = MM_ERROR_NONE;
5554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5555 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5557 *duration = player->duration;
5562 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5564 mm_player_t *player = (mm_player_t *)hplayer;
5565 int ret = MM_ERROR_NONE;
5567 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5569 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5575 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5577 mm_player_t *player = (mm_player_t *)hplayer;
5578 int ret = MM_ERROR_NONE;
5582 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5584 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5592 __mmplayer_is_midi_type(gchar *str_caps)
5594 if ((g_strrstr(str_caps, "audio/midi")) ||
5595 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5596 (g_strrstr(str_caps, "application/x-smaf")) ||
5597 (g_strrstr(str_caps, "audio/x-imelody")) ||
5598 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5599 (g_strrstr(str_caps, "audio/xmf")) ||
5600 (g_strrstr(str_caps, "audio/mxmf"))) {
5609 __mmplayer_is_only_mp3_type(gchar *str_caps)
5611 if (g_strrstr(str_caps, "application/x-id3") ||
5612 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5618 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5620 GstStructure *caps_structure = NULL;
5621 gint samplerate = 0;
5625 MMPLAYER_RETURN_IF_FAIL(player && caps);
5627 caps_structure = gst_caps_get_structure(caps, 0);
5629 /* set stream information */
5630 gst_structure_get_int(caps_structure, "rate", &samplerate);
5631 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5633 gst_structure_get_int(caps_structure, "channels", &channels);
5634 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5636 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5640 __mmplayer_update_content_type_info(mm_player_t *player)
5643 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5645 if (__mmplayer_is_midi_type(player->type)) {
5646 player->bypass_audio_effect = TRUE;
5650 if (!player->streamer) {
5651 LOGD("no need to check streaming type");
5655 if (g_strrstr(player->type, "application/x-hls")) {
5656 /* If it can't know exact type when it parses uri because of redirection case,
5657 * it will be fixed by typefinder or when doing autoplugging.
5659 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5660 player->streamer->is_adaptive_streaming = TRUE;
5661 } else if (g_strrstr(player->type, "application/dash+xml")) {
5662 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5663 player->streamer->is_adaptive_streaming = TRUE;
5666 if (player->streamer->is_adaptive_streaming) {
5667 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5669 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) /* if user did not set the rebuffer value */
5670 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5673 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5678 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5679 GstCaps *caps, gpointer data)
5681 mm_player_t *player = (mm_player_t *)data;
5686 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5688 /* store type string */
5689 MMPLAYER_FREEIF(player->type);
5690 player->type = gst_caps_to_string(caps);
5692 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5693 player, player->type, probability, gst_caps_get_size(caps));
5695 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5696 (g_strrstr(player->type, "audio/x-raw-int"))) {
5697 LOGE("not support media format");
5699 if (player->msg_posted == FALSE) {
5700 MMMessageParamType msg_param;
5701 memset(&msg_param, 0, sizeof(MMMessageParamType));
5703 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5704 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5706 /* don't post more if one was sent already */
5707 player->msg_posted = TRUE;
5712 __mmplayer_update_content_type_info(player);
5714 pad = gst_element_get_static_pad(tf, "src");
5716 LOGE("fail to get typefind src pad.");
5720 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5721 gboolean async = FALSE;
5722 LOGE("failed to autoplug %s", player->type);
5724 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5726 if (async && player->msg_posted == FALSE)
5727 __mmplayer_handle_missed_plugin(player);
5733 gst_object_unref(GST_OBJECT(pad));
5741 __mmplayer_gst_make_decodebin(mm_player_t *player)
5743 GstElement *decodebin = NULL;
5747 /* create decodebin */
5748 decodebin = gst_element_factory_make("decodebin", NULL);
5751 LOGE("fail to create decodebin");
5755 /* raw pad handling signal */
5756 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5757 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5759 /* no-more-pad pad handling signal */
5760 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5761 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5763 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5764 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5766 /* This signal is emitted when a pad for which there is no further possible
5767 decoding is added to the decodebin.*/
5768 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5769 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5771 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5772 before looking for any elements that can handle that stream.*/
5773 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5774 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5776 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5777 before looking for any elements that can handle that stream.*/
5778 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5779 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5781 /* This signal is emitted once decodebin has finished decoding all the data.*/
5782 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5783 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5785 /* This signal is emitted when a element is added to the bin.*/
5786 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5787 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5794 __mmplayer_gst_make_queue2(mm_player_t *player)
5796 GstElement *queue2 = NULL;
5797 gint64 dur_bytes = 0L;
5798 MMPlayerGstElement *mainbin = NULL;
5799 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5802 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5804 mainbin = player->pipeline->mainbin;
5806 queue2 = gst_element_factory_make("queue2", "queue2");
5808 LOGE("failed to create buffering queue element");
5812 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5813 * skip the pull mode(file or ring buffering) setting. */
5814 if (g_strrstr(player->type, "video/mpegts"))
5817 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5818 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5820 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5822 if (dur_bytes > 0) {
5823 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5824 type = MUXED_BUFFER_TYPE_FILE;
5826 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5827 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5833 __mm_player_streaming_set_queue2(player->streamer,
5837 player->http_file_buffering_path,
5838 (guint64)dur_bytes);
5844 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5846 MMPlayerGstElement *mainbin = NULL;
5847 GstElement *decodebin = NULL;
5848 GstElement *queue2 = NULL;
5849 GstPad *sinkpad = NULL;
5850 GstPad *qsrcpad = NULL;
5853 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5855 mainbin = player->pipeline->mainbin;
5857 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5859 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5860 LOGW("need to check: muxed buffer is not null");
5863 queue2 = __mmplayer_gst_make_queue2(player);
5865 LOGE("failed to make queue2");
5869 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5870 LOGE("failed to add buffering queue");
5874 sinkpad = gst_element_get_static_pad(queue2, "sink");
5875 qsrcpad = gst_element_get_static_pad(queue2, "src");
5877 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5878 LOGE("failed to link [%s:%s]-[%s:%s]",
5879 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5883 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5884 LOGE("failed to sync queue2 state with parent");
5888 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5889 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5893 gst_object_unref(GST_OBJECT(sinkpad));
5897 /* create decodebin */
5898 decodebin = __mmplayer_gst_make_decodebin(player);
5900 LOGE("failed to make decodebin");
5904 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5905 LOGE("failed to add decodebin");
5909 /* to force caps on the decodebin element and avoid reparsing stuff by
5910 * typefind. It also avoids a deadlock in the way typefind activates pads in
5911 * the state change */
5912 g_object_set(decodebin, "sink-caps", caps, NULL);
5914 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5916 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5917 LOGE("failed to link [%s:%s]-[%s:%s]",
5918 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5922 gst_object_unref(GST_OBJECT(sinkpad));
5925 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5926 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5928 /* set decodebin property about buffer in streaming playback. *
5929 * in case of HLS/DASH, it does not need to have big buffer *
5930 * because it is kind of adaptive streaming. */
5931 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5932 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5933 gint high_percent = 0;
5935 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5936 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5938 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5940 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5942 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5943 "high-percent", high_percent,
5944 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
5945 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
5946 "max-size-buffers", 0, NULL); // disable or automatic
5949 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
5950 LOGE("failed to sync decodebin state with parent");
5961 gst_object_unref(GST_OBJECT(sinkpad));
5964 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5965 * You need to explicitly set elements to the NULL state before
5966 * dropping the final reference, to allow them to clean up.
5968 gst_element_set_state(queue2, GST_STATE_NULL);
5970 /* And, it still has a parent "player".
5971 * You need to let the parent manage the object instead of unreffing the object directly.
5973 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5974 gst_object_unref(queue2);
5979 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5980 * You need to explicitly set elements to the NULL state before
5981 * dropping the final reference, to allow them to clean up.
5983 gst_element_set_state(decodebin, GST_STATE_NULL);
5985 /* And, it still has a parent "player".
5986 * You need to let the parent manage the object instead of unreffing the object directly.
5989 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
5990 gst_object_unref(decodebin);
5998 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6003 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6005 LOGD("class : %s, mime : %s", factory_class, mime);
6007 /* add missing plugin */
6008 /* NOTE : msl should check missing plugin for image mime type.
6009 * Some motion jpeg clips can have playable audio track.
6010 * So, msl have to play audio after displaying popup written video format not supported.
6012 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6013 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6014 LOGD("not found demuxer");
6015 player->not_found_demuxer = TRUE;
6016 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6022 if (!g_strrstr(factory_class, "Demuxer")) {
6023 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6024 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6025 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6027 /* check that clip have multi tracks or not */
6028 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6029 LOGD("video plugin is already linked");
6031 LOGW("add VIDEO to missing plugin");
6032 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6033 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6035 } else if (g_str_has_prefix(mime, "audio")) {
6036 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6037 LOGD("audio plugin is already linked");
6039 LOGW("add AUDIO to missing plugin");
6040 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6041 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6049 return MM_ERROR_NONE;
6053 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6055 mm_player_t *player = (mm_player_t *)data;
6059 MMPLAYER_RETURN_IF_FAIL(player);
6061 /* remove fakesink. */
6062 if (!__mmplayer_gst_remove_fakesink(player,
6063 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6064 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6065 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6066 * source element are not same. To overcome this situation, this function will called
6067 * several places and several times. Therefore, this is not an error case.
6072 LOGD("[handle: %p] pipeline has completely constructed", player);
6074 if ((player->ini.async_start) &&
6075 (player->msg_posted == FALSE) &&
6076 (player->cmd >= MMPLAYER_COMMAND_START))
6077 __mmplayer_handle_missed_plugin(player);
6079 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6083 __mmplayer_check_profile(void)
6086 static int profile_tv = -1;
6088 if (__builtin_expect(profile_tv != -1, 1))
6091 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6092 switch (*profileName) {
6107 __mmplayer_get_next_uri(mm_player_t *player)
6109 MMPlayerParseProfile profile;
6111 guint num_of_list = 0;
6114 num_of_list = g_list_length(player->uri_info.uri_list);
6115 uri_idx = player->uri_info.uri_idx;
6117 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6118 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6119 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6121 LOGW("next uri does not exist");
6125 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6126 LOGE("failed to parse profile");
6130 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6131 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6132 LOGW("uri type is not supported(%d)", profile.uri_type);
6136 LOGD("success to find next uri %d", uri_idx);
6140 if (uri_idx == num_of_list) {
6141 LOGE("failed to find next uri");
6145 player->uri_info.uri_idx = uri_idx;
6146 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6148 if (mm_attrs_commit_all(player->attrs)) {
6149 LOGE("failed to commit");
6153 SECURE_LOGD("next playback uri: %s", uri);
6158 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6160 #define REPEAT_COUNT_INFINITELY -1
6161 #define REPEAT_COUNT_MIN 2
6163 MMHandleType attrs = 0;
6167 guint num_of_list = 0;
6168 int profile_tv = -1;
6172 LOGD("checking for gapless play option");
6174 if (player->pipeline->textbin) {
6175 LOGE("subtitle path is enabled. gapless play is not supported.");
6179 attrs = MMPLAYER_GET_ATTRS(player);
6181 LOGE("fail to get attributes.");
6185 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6187 /* gapless playback is not supported in case of video at TV profile. */
6188 profile_tv = __mmplayer_check_profile();
6189 if (profile_tv && video) {
6190 LOGW("not support video gapless playback");
6194 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6195 LOGE("failed to get play count");
6197 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6198 LOGE("failed to get gapless mode");
6200 /* check repeat count in case of audio */
6202 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6203 LOGW("gapless is disabled");
6207 num_of_list = g_list_length(player->uri_info.uri_list);
6209 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6211 if (num_of_list == 0) {
6212 /* audio looping path */
6213 if (count >= REPEAT_COUNT_MIN) {
6214 /* decrease play count */
6215 /* we succeeded to rewind. update play count and then wait for next EOS */
6217 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6218 /* commit attribute */
6219 if (mm_attrs_commit_all(attrs))
6220 LOGE("failed to commit attribute");
6222 } else if (count != REPEAT_COUNT_INFINITELY) {
6223 LOGD("there is no next uri and no repeat");
6226 LOGD("looping cnt %d", count);
6228 /* gapless playback path */
6229 if (!__mmplayer_get_next_uri(player)) {
6230 LOGE("failed to get next uri");
6237 LOGE("unable to play gapless path. EOS will be posted soon");
6242 __mmplayer_initialize_gapless_play(mm_player_t *player)
6248 player->smooth_streaming = FALSE;
6249 player->videodec_linked = 0;
6250 player->audiodec_linked = 0;
6251 player->textsink_linked = 0;
6252 player->is_external_subtitle_present = FALSE;
6253 player->is_external_subtitle_added_now = FALSE;
6254 player->not_supported_codec = MISSING_PLUGIN_NONE;
6255 player->can_support_codec = FOUND_PLUGIN_NONE;
6256 player->pending_seek.is_pending = false;
6257 player->pending_seek.pos = 0;
6258 player->msg_posted = FALSE;
6259 player->has_many_types = FALSE;
6260 player->no_more_pad = FALSE;
6261 player->not_found_demuxer = 0;
6262 player->seek_state = MMPLAYER_SEEK_NONE;
6263 player->is_subtitle_force_drop = FALSE;
6264 player->play_subtitle = FALSE;
6265 player->adjust_subtitle_pos = 0;
6267 player->total_bitrate = 0;
6268 player->total_maximum_bitrate = 0;
6270 __mmplayer_track_initialize(player);
6271 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6273 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6274 player->bitrate[i] = 0;
6275 player->maximum_bitrate[i] = 0;
6278 if (player->v_stream_caps) {
6279 gst_caps_unref(player->v_stream_caps);
6280 player->v_stream_caps = NULL;
6283 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6285 /* clean found parsers */
6286 if (player->parsers) {
6287 GList *parsers = player->parsers;
6288 for (; parsers; parsers = g_list_next(parsers)) {
6289 gchar *name = parsers->data;
6290 MMPLAYER_FREEIF(name);
6292 g_list_free(player->parsers);
6293 player->parsers = NULL;
6296 /* clean found audio decoders */
6297 if (player->audio_decoders) {
6298 GList *a_dec = player->audio_decoders;
6299 for (; a_dec; a_dec = g_list_next(a_dec)) {
6300 gchar *name = a_dec->data;
6301 MMPLAYER_FREEIF(name);
6303 g_list_free(player->audio_decoders);
6304 player->audio_decoders = NULL;
6311 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6313 MMPlayerGstElement *mainbin = NULL;
6314 MMMessageParamType msg_param = {0,};
6315 GstElement *element = NULL;
6316 MMHandleType attrs = 0;
6318 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6322 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6323 LOGE("player is not initialized");
6327 mainbin = player->pipeline->mainbin;
6328 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6330 attrs = MMPLAYER_GET_ATTRS(player);
6332 LOGE("fail to get attributes");
6336 /* Initialize Player values */
6337 __mmplayer_initialize_gapless_play(player);
6339 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6341 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6342 LOGE("failed to parse profile");
6343 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6347 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6348 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6349 LOGE("dash or hls is not supportable");
6350 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6354 element = __mmplayer_gst_create_source(player);
6356 LOGE("no source element was created");
6360 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6361 LOGE("failed to add source element to pipeline");
6362 gst_object_unref(GST_OBJECT(element));
6367 /* take source element */
6368 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6369 mainbin[MMPLAYER_M_SRC].gst = element;
6373 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6374 if (player->streamer == NULL) {
6375 player->streamer = __mm_player_streaming_create();
6376 __mm_player_streaming_initialize(player->streamer, TRUE);
6379 elem_idx = MMPLAYER_M_TYPEFIND;
6380 element = gst_element_factory_make("typefind", "typefinder");
6381 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6382 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6384 elem_idx = MMPLAYER_M_AUTOPLUG;
6385 element = __mmplayer_gst_make_decodebin(player);
6388 /* check autoplug element is OK */
6390 LOGE("can not create element(%d)", elem_idx);
6394 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6395 LOGE("failed to add sinkbin to pipeline");
6396 gst_object_unref(GST_OBJECT(element));
6401 mainbin[elem_idx].id = elem_idx;
6402 mainbin[elem_idx].gst = element;
6404 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6405 LOGE("Failed to link src - autoplug(or typefind)");
6409 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6410 LOGE("Failed to change state of src element");
6414 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6415 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6416 LOGE("Failed to change state of decodebin");
6420 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6421 LOGE("Failed to change state of src element");
6426 player->gapless.stream_changed = TRUE;
6427 player->gapless.running = TRUE;
6433 MMPLAYER_PLAYBACK_UNLOCK(player);
6435 if (!player->msg_posted) {
6436 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6437 player->msg_posted = TRUE;
6444 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6446 mm_player_selector_t *selector = &player->selector[type];
6447 MMPlayerGstElement *sinkbin = NULL;
6448 enum MainElementID selectorId = MMPLAYER_M_NUM;
6449 enum MainElementID sinkId = MMPLAYER_M_NUM;
6450 GstPad *srcpad = NULL;
6451 GstPad *sinkpad = NULL;
6452 gboolean send_notice = FALSE;
6455 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6457 LOGD("type %d", type);
6460 case MM_PLAYER_TRACK_TYPE_AUDIO:
6461 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6462 sinkId = MMPLAYER_A_BIN;
6463 sinkbin = player->pipeline->audiobin;
6465 case MM_PLAYER_TRACK_TYPE_VIDEO:
6466 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6467 sinkId = MMPLAYER_V_BIN;
6468 sinkbin = player->pipeline->videobin;
6471 case MM_PLAYER_TRACK_TYPE_TEXT:
6472 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6473 sinkId = MMPLAYER_T_BIN;
6474 sinkbin = player->pipeline->textbin;
6477 LOGE("requested type is not supportable");
6482 if (player->pipeline->mainbin[selectorId].gst) {
6485 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6487 if (selector->event_probe_id != 0)
6488 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6489 selector->event_probe_id = 0;
6491 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6492 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6494 if (srcpad && sinkpad) {
6495 /* after getting drained signal there is no data flows, so no need to do pad_block */
6496 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6497 gst_pad_unlink(srcpad, sinkpad);
6499 /* send custom event to sink pad to handle it at video sink */
6501 LOGD("send custom event to sinkpad");
6502 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6503 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6504 gst_pad_send_event(sinkpad, event);
6508 gst_object_unref(sinkpad);
6511 gst_object_unref(srcpad);
6514 LOGD("selector release");
6516 /* release and unref requests pad from the selector */
6517 for (n = 0; n < selector->channels->len; n++) {
6518 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6519 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6521 g_ptr_array_set_size(selector->channels, 0);
6523 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6524 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6526 player->pipeline->mainbin[selectorId].gst = NULL;
6534 __mmplayer_deactivate_old_path(mm_player_t *player)
6537 MMPLAYER_RETURN_IF_FAIL(player);
6539 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6540 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6541 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6542 LOGE("deactivate selector error");
6546 __mmplayer_track_destroy(player);
6547 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6549 if (player->streamer) {
6550 __mm_player_streaming_initialize(player->streamer, FALSE);
6551 __mm_player_streaming_destroy(player->streamer);
6552 player->streamer = NULL;
6555 MMPLAYER_PLAYBACK_LOCK(player);
6556 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6563 if (!player->msg_posted) {
6564 MMMessageParamType msg = {0,};
6567 msg.code = MM_ERROR_PLAYER_INTERNAL;
6568 LOGE("gapless_uri_play> deactivate error");
6570 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6571 player->msg_posted = TRUE;
6577 _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char *file_path)
6579 int result = MM_ERROR_NONE;
6580 mm_player_t *player = (mm_player_t *)hplayer;
6583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6586 player->http_file_buffering_path = (gchar *)file_path;
6587 LOGD("temp file path: %s", player->http_file_buffering_path);
6594 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6596 int result = MM_ERROR_NONE;
6597 mm_player_t *player = (mm_player_t *)hplayer;
6600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6602 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6603 if (mm_attrs_commit_all(player->attrs)) {
6604 LOGE("failed to commit the original uri.");
6605 result = MM_ERROR_PLAYER_INTERNAL;
6607 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6608 LOGE("failed to add the original uri in the uri list.");
6616 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6618 mm_player_t *player = (mm_player_t *)hplayer;
6619 guint num_of_list = 0;
6623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6624 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6626 if (player->pipeline && player->pipeline->textbin) {
6627 LOGE("subtitle path is enabled.");
6628 return MM_ERROR_PLAYER_INVALID_STATE;
6631 num_of_list = g_list_length(player->uri_info.uri_list);
6633 if (is_first_path) {
6634 if (num_of_list == 0) {
6635 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6636 LOGD("add original path : %s", uri);
6638 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6639 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6641 LOGD("change original path : %s", uri);
6644 MMHandleType attrs = 0;
6645 attrs = MMPLAYER_GET_ATTRS(player);
6647 if (num_of_list == 0) {
6648 char *original_uri = NULL;
6651 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6653 if (!original_uri) {
6654 LOGE("there is no original uri.");
6655 return MM_ERROR_PLAYER_INVALID_STATE;
6658 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6659 player->uri_info.uri_idx = 0;
6661 LOGD("add original path at first : %s", original_uri);
6665 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6666 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6670 return MM_ERROR_NONE;
6674 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6676 mm_player_t *player = (mm_player_t *)hplayer;
6677 char *next_uri = NULL;
6678 guint num_of_list = 0;
6681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6683 num_of_list = g_list_length(player->uri_info.uri_list);
6685 if (num_of_list > 0) {
6686 gint uri_idx = player->uri_info.uri_idx;
6688 if (uri_idx < num_of_list-1)
6693 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6694 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6696 *uri = g_strdup(next_uri);
6700 return MM_ERROR_NONE;
6704 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6705 GstCaps *caps, gpointer data)
6707 mm_player_t *player = (mm_player_t *)data;
6708 const gchar *klass = NULL;
6709 const gchar *mime = NULL;
6710 gchar *caps_str = NULL;
6712 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6713 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6714 caps_str = gst_caps_to_string(caps);
6716 LOGW("unknown type of caps : %s from %s",
6717 caps_str, GST_ELEMENT_NAME(elem));
6719 MMPLAYER_FREEIF(caps_str);
6721 /* There is no available codec. */
6722 __mmplayer_check_not_supported_codec(player, klass, mime);
6726 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6727 GstCaps *caps, gpointer data)
6729 mm_player_t *player = (mm_player_t *)data;
6730 const char *mime = NULL;
6731 gboolean ret = TRUE;
6733 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6734 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6736 if (g_str_has_prefix(mime, "audio")) {
6737 GstStructure *caps_structure = NULL;
6738 gint samplerate = 0;
6740 gchar *caps_str = NULL;
6742 caps_structure = gst_caps_get_structure(caps, 0);
6743 gst_structure_get_int(caps_structure, "rate", &samplerate);
6744 gst_structure_get_int(caps_structure, "channels", &channels);
6746 if ((channels > 0 && samplerate == 0)) {
6747 LOGD("exclude audio...");
6751 caps_str = gst_caps_to_string(caps);
6752 /* set it directly because not sent by TAG */
6753 if (g_strrstr(caps_str, "mobile-xmf"))
6754 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6755 MMPLAYER_FREEIF(caps_str);
6756 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6757 MMMessageParamType msg_param;
6758 memset(&msg_param, 0, sizeof(MMMessageParamType));
6759 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6760 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6761 LOGD("video file is not supported on this device");
6763 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6764 LOGD("already video linked");
6767 LOGD("found new stream");
6774 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6776 int ret = MM_ERROR_NONE;
6778 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6780 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6781 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6783 LOGD("audio codec type: %d", codec_type);
6784 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6785 /* sw codec will be skipped */
6786 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6787 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6788 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6789 ret = MM_ERROR_PLAYER_INTERNAL;
6793 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6794 /* hw codec will be skipped */
6795 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6796 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6797 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6798 ret = MM_ERROR_PLAYER_INTERNAL;
6803 /* set stream information */
6804 if (!player->audiodec_linked)
6805 __mmplayer_set_audio_attrs(player, caps);
6807 /* update codec info */
6808 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6809 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6810 player->audiodec_linked = 1;
6812 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6814 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6816 LOGD("video codec type: %d", codec_type);
6817 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6818 /* sw codec is skipped */
6819 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6820 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6821 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6822 ret = MM_ERROR_PLAYER_INTERNAL;
6826 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6827 /* hw codec is skipped */
6828 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6829 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6830 ret = MM_ERROR_PLAYER_INTERNAL;
6835 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6836 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6838 /* mark video decoder for acquire */
6839 if (player->video_decoder_resource == NULL) {
6840 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6841 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6842 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6843 &player->video_decoder_resource)
6844 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6845 LOGE("could not mark video_decoder resource for acquire");
6846 ret = MM_ERROR_PLAYER_INTERNAL;
6850 LOGW("video decoder resource is already acquired, skip it.");
6851 ret = MM_ERROR_PLAYER_INTERNAL;
6855 player->interrupted_by_resource = FALSE;
6856 /* acquire resources for video playing */
6857 if (mm_resource_manager_commit(player->resource_manager)
6858 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6859 LOGE("could not acquire resources for video decoding");
6860 ret = MM_ERROR_PLAYER_INTERNAL;
6865 /* update codec info */
6866 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6867 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6868 player->videodec_linked = 1;
6876 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6877 GstCaps *caps, GstElementFactory *factory, gpointer data)
6879 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6880 We are defining our own and will be removed when it actually exposed */
6882 GST_AUTOPLUG_SELECT_TRY,
6883 GST_AUTOPLUG_SELECT_EXPOSE,
6884 GST_AUTOPLUG_SELECT_SKIP
6885 } GstAutoplugSelectResult;
6887 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6888 mm_player_t *player = (mm_player_t *)data;
6890 gchar *factory_name = NULL;
6891 gchar *caps_str = NULL;
6892 const gchar *klass = NULL;
6895 factory_name = GST_OBJECT_NAME(factory);
6896 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6897 caps_str = gst_caps_to_string(caps);
6899 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6901 /* store type string */
6902 if (player->type == NULL) {
6903 player->type = gst_caps_to_string(caps);
6904 __mmplayer_update_content_type_info(player);
6907 /* filtering exclude keyword */
6908 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6909 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6910 LOGW("skipping [%s] by exculde keyword [%s]",
6911 factory_name, player->ini.exclude_element_keyword[idx]);
6913 result = GST_AUTOPLUG_SELECT_SKIP;
6918 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6919 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6920 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6921 factory_name, player->ini.unsupported_codec_keyword[idx]);
6922 result = GST_AUTOPLUG_SELECT_SKIP;
6927 /* exclude webm format */
6928 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6929 * because webm format is not supportable.
6930 * If webm is disabled in "autoplug-continue", there is no state change
6931 * failure or error because the decodebin will expose the pad directly.
6932 * It make MSL invoke _prepare_async_callback.
6933 * So, we need to disable webm format in "autoplug-select" */
6934 if (caps_str && strstr(caps_str, "webm")) {
6935 LOGW("webm is not supported");
6936 result = GST_AUTOPLUG_SELECT_SKIP;
6940 /* check factory class for filtering */
6941 /* NOTE : msl don't need to use image plugins.
6942 * So, those plugins should be skipped for error handling.
6944 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6945 LOGD("skipping [%s] by not required", factory_name);
6946 result = GST_AUTOPLUG_SELECT_SKIP;
6950 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6951 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6952 // TO CHECK : subtitle if needed, add subparse exception.
6953 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
6954 result = GST_AUTOPLUG_SELECT_SKIP;
6958 if (g_strrstr(factory_name, "mpegpsdemux")) {
6959 LOGD("skipping PS container - not support");
6960 result = GST_AUTOPLUG_SELECT_SKIP;
6964 if (g_strrstr(factory_name, "mssdemux"))
6965 player->smooth_streaming = TRUE;
6967 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6968 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6971 GstStructure *str = NULL;
6972 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6974 /* don't make video because of not required */
6975 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6976 (!player->set_mode.media_packet_video_stream)) {
6977 LOGD("no need video decoding, expose pad");
6978 result = GST_AUTOPLUG_SELECT_EXPOSE;
6982 /* get w/h for omx state-tune */
6983 /* FIXME: deprecated? */
6984 str = gst_caps_get_structure(caps, 0);
6985 gst_structure_get_int(str, "width", &width);
6988 if (player->v_stream_caps) {
6989 gst_caps_unref(player->v_stream_caps);
6990 player->v_stream_caps = NULL;
6993 player->v_stream_caps = gst_caps_copy(caps);
6994 LOGD("take caps for video state tune");
6995 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
6999 if (g_strrstr(klass, "Codec/Decoder")) {
7000 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7001 LOGD("skipping %s codec", factory_name);
7002 result = GST_AUTOPLUG_SELECT_SKIP;
7008 MMPLAYER_FREEIF(caps_str);
7014 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7017 //mm_player_t *player = (mm_player_t *)data;
7018 GstCaps *caps = NULL;
7020 LOGD("[Decodebin2] pad-removed signal");
7022 caps = gst_pad_query_caps(new_pad, NULL);
7024 LOGW("query caps is NULL");
7028 gchar *caps_str = NULL;
7029 caps_str = gst_caps_to_string(caps);
7031 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7033 MMPLAYER_FREEIF(caps_str);
7034 gst_caps_unref(caps);
7038 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7040 mm_player_t *player = (mm_player_t *)data;
7041 GstIterator *iter = NULL;
7042 GValue item = { 0, };
7044 gboolean done = FALSE;
7045 gboolean is_all_drained = TRUE;
7048 MMPLAYER_RETURN_IF_FAIL(player);
7050 LOGD("__mmplayer_gst_decode_drained");
7052 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7053 LOGW("Fail to get cmd lock");
7057 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7058 !__mmplayer_verify_gapless_play_path(player)) {
7059 LOGD("decoding is finished.");
7060 __mmplayer_reset_gapless_state(player);
7061 MMPLAYER_CMD_UNLOCK(player);
7065 player->gapless.reconfigure = TRUE;
7067 /* check decodebin src pads whether they received EOS or not */
7068 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7071 switch (gst_iterator_next(iter, &item)) {
7072 case GST_ITERATOR_OK:
7073 pad = g_value_get_object(&item);
7074 if (pad && !GST_PAD_IS_EOS(pad)) {
7075 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7076 is_all_drained = FALSE;
7079 g_value_reset(&item);
7081 case GST_ITERATOR_RESYNC:
7082 gst_iterator_resync(iter);
7084 case GST_ITERATOR_ERROR:
7085 case GST_ITERATOR_DONE:
7090 g_value_unset(&item);
7091 gst_iterator_free(iter);
7093 if (!is_all_drained) {
7094 LOGD("Wait util the all pads get EOS.");
7095 MMPLAYER_CMD_UNLOCK(player);
7100 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7101 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7103 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7104 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7105 __mmplayer_deactivate_old_path(player);
7106 MMPLAYER_CMD_UNLOCK(player);
7112 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7114 mm_player_t *player = (mm_player_t *)data;
7115 const gchar *klass = NULL;
7116 gchar *factory_name = NULL;
7118 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7119 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7121 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7123 if (__mmplayer_add_dump_buffer_probe(player, element))
7124 LOGD("add buffer probe");
7127 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7128 gchar *selected = NULL;
7129 selected = g_strdup(GST_ELEMENT_NAME(element));
7130 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7134 if (g_strrstr(klass, "Parser")) {
7135 gchar *selected = NULL;
7137 selected = g_strdup(factory_name);
7138 player->parsers = g_list_append(player->parsers, selected);
7141 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7142 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7143 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7145 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7146 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7148 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7149 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7150 "max-video-width", player->adaptive_info.limit.width,
7151 "max-video-height", player->adaptive_info.limit.height, NULL);
7153 } else if (g_strrstr(klass, "Demuxer")) {
7154 //LOGD("plugged element is demuxer. take it");
7155 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7156 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7159 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7160 int surface_type = 0;
7162 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7165 // to support trust-zone only
7166 if (g_strrstr(factory_name, "asfdemux")) {
7167 LOGD("set file-location %s", player->profile.uri);
7168 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7169 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7170 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7171 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7172 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7173 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7174 (__mmplayer_is_only_mp3_type(player->type))) {
7175 LOGD("[mpegaudioparse] set streaming pull mode.");
7176 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7178 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7179 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7182 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7183 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7184 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7186 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7187 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7189 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7190 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7191 (MMPLAYER_IS_DASH_STREAMING(player))) {
7192 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7193 __mm_player_streaming_set_multiqueue(player->streamer, element);
7194 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7203 __mmplayer_release_misc(mm_player_t *player)
7206 bool cur_mode = player->set_mode.rich_audio;
7209 MMPLAYER_RETURN_IF_FAIL(player);
7211 player->video_stream_cb = NULL;
7212 player->video_stream_cb_user_param = NULL;
7213 player->video_stream_prerolled = false;
7215 player->audio_stream_render_cb = NULL;
7216 player->audio_stream_cb_user_param = NULL;
7217 player->audio_stream_sink_sync = false;
7219 player->video_stream_changed_cb = NULL;
7220 player->video_stream_changed_cb_user_param = NULL;
7222 player->audio_stream_changed_cb = NULL;
7223 player->audio_stream_changed_cb_user_param = NULL;
7225 player->sent_bos = FALSE;
7226 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7228 player->seek_state = MMPLAYER_SEEK_NONE;
7230 player->total_bitrate = 0;
7231 player->total_maximum_bitrate = 0;
7233 player->not_found_demuxer = 0;
7235 player->last_position = 0;
7236 player->duration = 0;
7237 player->http_content_size = 0;
7238 player->not_supported_codec = MISSING_PLUGIN_NONE;
7239 player->can_support_codec = FOUND_PLUGIN_NONE;
7240 player->pending_seek.is_pending = false;
7241 player->pending_seek.pos = 0;
7242 player->msg_posted = FALSE;
7243 player->has_many_types = FALSE;
7244 player->is_subtitle_force_drop = FALSE;
7245 player->play_subtitle = FALSE;
7246 player->adjust_subtitle_pos = 0;
7247 player->last_multiwin_status = FALSE;
7248 player->has_closed_caption = FALSE;
7249 player->set_mode.media_packet_video_stream = false;
7250 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7251 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7253 player->set_mode.rich_audio = cur_mode;
7255 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7256 player->bitrate[i] = 0;
7257 player->maximum_bitrate[i] = 0;
7260 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7262 /* remove media stream cb(appsrc cb) */
7263 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7264 player->media_stream_buffer_status_cb[i] = NULL;
7265 player->media_stream_seek_data_cb[i] = NULL;
7266 player->buffer_cb_user_param[i] = NULL;
7267 player->seek_cb_user_param[i] = NULL;
7269 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7271 /* free memory related to audio effect */
7272 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7274 if (player->adaptive_info.var_list) {
7275 g_list_free_full(player->adaptive_info.var_list, g_free);
7276 player->adaptive_info.var_list = NULL;
7279 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7280 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7281 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7283 /* Reset video360 settings to their defaults in case if the pipeline is to be
7286 player->video360_metadata.is_spherical = -1;
7287 player->is_openal_plugin_used = FALSE;
7289 player->is_content_spherical = FALSE;
7290 player->is_video360_enabled = TRUE;
7291 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7292 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7293 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7294 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7295 player->video360_zoom = 1.0f;
7296 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7297 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7299 player->sound.rg_enable = false;
7301 __mmplayer_initialize_video_roi(player);
7306 __mmplayer_release_misc_post(mm_player_t *player)
7308 char *original_uri = NULL;
7311 /* player->pipeline is already released before. */
7313 MMPLAYER_RETURN_IF_FAIL(player);
7315 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7317 /* clean found parsers */
7318 if (player->parsers) {
7319 GList *parsers = player->parsers;
7320 for (; parsers; parsers = g_list_next(parsers)) {
7321 gchar *name = parsers->data;
7322 MMPLAYER_FREEIF(name);
7324 g_list_free(player->parsers);
7325 player->parsers = NULL;
7328 /* clean found audio decoders */
7329 if (player->audio_decoders) {
7330 GList *a_dec = player->audio_decoders;
7331 for (; a_dec; a_dec = g_list_next(a_dec)) {
7332 gchar *name = a_dec->data;
7333 MMPLAYER_FREEIF(name);
7335 g_list_free(player->audio_decoders);
7336 player->audio_decoders = NULL;
7339 /* clean the uri list except original uri */
7340 if (player->uri_info.uri_list) {
7341 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7343 if (player->attrs) {
7344 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7345 LOGD("restore original uri = %s", original_uri);
7347 if (mm_attrs_commit_all(player->attrs))
7348 LOGE("failed to commit the original uri.");
7351 GList *uri_list = player->uri_info.uri_list;
7352 for (; uri_list; uri_list = g_list_next(uri_list)) {
7353 gchar *uri = uri_list->data;
7354 MMPLAYER_FREEIF(uri);
7356 g_list_free(player->uri_info.uri_list);
7357 player->uri_info.uri_list = NULL;
7360 /* clear the audio stream buffer list */
7361 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7363 /* clear the video stream bo list */
7364 __mmplayer_video_stream_destroy_bo_list(player);
7365 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7367 if (player->profile.input_mem.buf) {
7368 free(player->profile.input_mem.buf);
7369 player->profile.input_mem.buf = NULL;
7371 player->profile.input_mem.len = 0;
7372 player->profile.input_mem.offset = 0;
7374 player->uri_info.uri_idx = 0;
7379 __mmplayer_check_subtitle(mm_player_t *player)
7381 MMHandleType attrs = 0;
7382 char *subtitle_uri = NULL;
7386 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7388 /* get subtitle attribute */
7389 attrs = MMPLAYER_GET_ATTRS(player);
7393 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7394 if (!subtitle_uri || !strlen(subtitle_uri))
7397 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7398 player->is_external_subtitle_present = TRUE;
7406 __mmplayer_cancel_eos_timer(mm_player_t *player)
7408 MMPLAYER_RETURN_IF_FAIL(player);
7410 if (player->eos_timer) {
7411 LOGD("cancel eos timer");
7412 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7413 player->eos_timer = 0;
7420 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7424 MMPLAYER_RETURN_IF_FAIL(player);
7425 MMPLAYER_RETURN_IF_FAIL(sink);
7427 player->sink_elements = g_list_append(player->sink_elements, sink);
7433 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7437 MMPLAYER_RETURN_IF_FAIL(player);
7438 MMPLAYER_RETURN_IF_FAIL(sink);
7440 player->sink_elements = g_list_remove(player->sink_elements, sink);
7446 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7447 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7449 MMPlayerSignalItem *item = NULL;
7452 MMPLAYER_RETURN_IF_FAIL(player);
7454 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7455 LOGE("invalid signal type [%d]", type);
7459 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7461 LOGE("cannot connect signal [%s]", signal);
7466 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7467 player->signals[type] = g_list_append(player->signals[type], item);
7473 /* NOTE : be careful with calling this api. please refer to below glib comment
7474 * glib comment : Note that there is a bug in GObject that makes this function much
7475 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7476 * will no longer be called, but, the signal handler is not currently disconnected.
7477 * If the instance is itself being freed at the same time than this doesn't matter,
7478 * since the signal will automatically be removed, but if instance persists,
7479 * then the signal handler will leak. You should not remove the signal yourself
7480 * because in a future versions of GObject, the handler will automatically be
7483 * It's possible to work around this problem in a way that will continue to work
7484 * with future versions of GObject by checking that the signal handler is still
7485 * connected before disconnected it:
7487 * if (g_signal_handler_is_connected(instance, id))
7488 * g_signal_handler_disconnect(instance, id);
7491 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7493 GList *sig_list = NULL;
7494 MMPlayerSignalItem *item = NULL;
7498 MMPLAYER_RETURN_IF_FAIL(player);
7500 LOGD("release signals type : %d", type);
7502 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7503 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7504 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7505 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7506 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7507 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7511 sig_list = player->signals[type];
7513 for (; sig_list; sig_list = sig_list->next) {
7514 item = sig_list->data;
7516 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7517 if (g_signal_handler_is_connected(item->obj, item->sig))
7518 g_signal_handler_disconnect(item->obj, item->sig);
7521 MMPLAYER_FREEIF(item);
7524 g_list_free(player->signals[type]);
7525 player->signals[type] = NULL;
7533 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7535 mm_player_t *player = 0;
7536 int prev_display_surface_type = 0;
7537 void *prev_display_overlay = NULL;
7541 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7542 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7544 player = MM_PLAYER_CAST(handle);
7546 /* check video sinkbin is created */
7547 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7548 LOGE("Videosink is already created");
7549 return MM_ERROR_NONE;
7552 LOGD("videosink element is not yet ready");
7554 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7555 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7557 return MM_ERROR_INVALID_ARGUMENT;
7560 /* load previous attributes */
7561 if (player->attrs) {
7562 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7563 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7564 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7565 if (prev_display_surface_type == surface_type) {
7566 LOGD("incoming display surface type is same as previous one, do nothing..");
7568 return MM_ERROR_NONE;
7571 LOGE("failed to load attributes");
7573 return MM_ERROR_PLAYER_INTERNAL;
7576 /* videobin is not created yet, so we just set attributes related to display surface */
7577 LOGD("store display attribute for given surface type(%d)", surface_type);
7578 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7579 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7580 if (mm_attrs_commit_all(player->attrs)) {
7581 LOGE("failed to commit attribute");
7583 return MM_ERROR_PLAYER_INTERNAL;
7587 return MM_ERROR_NONE;
7590 /* Note : if silent is true, then subtitle would not be displayed. :*/
7592 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7594 mm_player_t *player = (mm_player_t *)hplayer;
7598 /* check player handle */
7599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7601 player->set_mode.subtitle_off = silent;
7603 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7607 return MM_ERROR_NONE;
7611 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7613 MMPlayerGstElement *mainbin = NULL;
7614 MMPlayerGstElement *textbin = NULL;
7615 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7616 GstState current_state = GST_STATE_VOID_PENDING;
7617 GstState element_state = GST_STATE_VOID_PENDING;
7618 GstState element_pending_state = GST_STATE_VOID_PENDING;
7620 GstEvent *event = NULL;
7621 int result = MM_ERROR_NONE;
7623 GstClock *curr_clock = NULL;
7624 GstClockTime base_time, start_time, curr_time;
7629 /* check player handle */
7630 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7632 player->pipeline->mainbin &&
7633 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7635 mainbin = player->pipeline->mainbin;
7636 textbin = player->pipeline->textbin;
7638 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7640 // sync clock with current pipeline
7641 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7642 curr_time = gst_clock_get_time(curr_clock);
7644 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7645 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7647 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7648 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7650 if (current_state > GST_STATE_READY) {
7651 // sync state with current pipeline
7652 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7653 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7654 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7656 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7657 if (GST_STATE_CHANGE_FAILURE == ret) {
7658 LOGE("fail to state change.");
7659 result = MM_ERROR_PLAYER_INTERNAL;
7663 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7664 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7667 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7668 gst_object_unref(curr_clock);
7671 // seek to current position
7672 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7673 result = MM_ERROR_PLAYER_INVALID_STATE;
7674 LOGE("gst_element_query_position failed, invalid state");
7678 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7679 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);
7681 __mmplayer_gst_send_event_to_sink(player, event);
7683 result = MM_ERROR_PLAYER_INTERNAL;
7684 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7688 /* sync state with current pipeline */
7689 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7690 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7691 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7693 return MM_ERROR_NONE;
7696 /* release text pipeline resource */
7697 player->textsink_linked = 0;
7699 /* release signal */
7700 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7702 /* release textbin with it's childs */
7703 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7704 MMPLAYER_FREEIF(player->pipeline->textbin);
7705 player->pipeline->textbin = NULL;
7707 /* release subtitle elem */
7708 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7709 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7715 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7717 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7718 GstState current_state = GST_STATE_VOID_PENDING;
7720 MMHandleType attrs = 0;
7721 MMPlayerGstElement *mainbin = NULL;
7722 MMPlayerGstElement *textbin = NULL;
7724 gchar *subtitle_uri = NULL;
7725 int result = MM_ERROR_NONE;
7726 const gchar *charset = NULL;
7730 /* check player handle */
7731 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7733 player->pipeline->mainbin &&
7734 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7735 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7737 mainbin = player->pipeline->mainbin;
7738 textbin = player->pipeline->textbin;
7740 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7741 if (current_state < GST_STATE_READY) {
7742 result = MM_ERROR_PLAYER_INVALID_STATE;
7743 LOGE("Pipeline is not in proper state");
7747 attrs = MMPLAYER_GET_ATTRS(player);
7749 LOGE("cannot get content attribute");
7750 result = MM_ERROR_PLAYER_INTERNAL;
7754 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7755 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7756 LOGE("subtitle uri is not proper filepath");
7757 result = MM_ERROR_PLAYER_INVALID_URI;
7761 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7762 LOGE("failed to get storage info of subtitle path");
7763 result = MM_ERROR_PLAYER_INVALID_URI;
7767 LOGD("old subtitle file path is [%s]", subtitle_uri);
7768 LOGD("new subtitle file path is [%s]", filepath);
7770 if (!strcmp(filepath, subtitle_uri)) {
7771 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7774 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7775 if (mm_attrs_commit_all(player->attrs)) {
7776 LOGE("failed to commit.");
7781 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7782 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7783 player->subtitle_language_list = NULL;
7784 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7786 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7787 if (ret != GST_STATE_CHANGE_SUCCESS) {
7788 LOGE("failed to change state of textbin to READY");
7789 result = MM_ERROR_PLAYER_INTERNAL;
7793 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7794 if (ret != GST_STATE_CHANGE_SUCCESS) {
7795 LOGE("failed to change state of subparse to READY");
7796 result = MM_ERROR_PLAYER_INTERNAL;
7800 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7801 if (ret != GST_STATE_CHANGE_SUCCESS) {
7802 LOGE("failed to change state of filesrc to READY");
7803 result = MM_ERROR_PLAYER_INTERNAL;
7807 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7809 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7811 charset = util_get_charset(filepath);
7813 LOGD("detected charset is %s", charset);
7814 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7817 result = _mmplayer_sync_subtitle_pipeline(player);
7824 /* API to switch between external subtitles */
7826 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7828 int result = MM_ERROR_NONE;
7829 mm_player_t *player = (mm_player_t *)hplayer;
7834 /* check player handle */
7835 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7837 /* filepath can be null in idle state */
7839 /* check file path */
7840 if ((path = strstr(filepath, "file://")))
7841 result = util_exist_file_path(path + 7);
7843 result = util_exist_file_path(filepath);
7845 if (result != MM_ERROR_NONE) {
7846 LOGE("invalid subtitle path 0x%X", result);
7847 return result; /* file not found or permission denied */
7851 if (!player->pipeline) {
7853 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7854 if (mm_attrs_commit_all(player->attrs)) {
7855 LOGE("failed to commit"); /* subtitle path will not be created */
7856 return MM_ERROR_PLAYER_INTERNAL;
7859 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7860 /* check filepath */
7861 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7863 if (!__mmplayer_check_subtitle(player)) {
7864 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7865 if (mm_attrs_commit_all(player->attrs)) {
7866 LOGE("failed to commit");
7867 return MM_ERROR_PLAYER_INTERNAL;
7870 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7871 LOGE("fail to create text pipeline");
7872 return MM_ERROR_PLAYER_INTERNAL;
7875 result = _mmplayer_sync_subtitle_pipeline(player);
7877 result = __mmplayer_change_external_subtitle_language(player, filepath);
7880 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7881 player->is_external_subtitle_added_now = TRUE;
7883 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7884 if (!player->subtitle_language_list) {
7885 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7886 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7887 LOGW("subtitle language list is not updated yet");
7889 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7897 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7899 int result = MM_ERROR_NONE;
7900 gchar *change_pad_name = NULL;
7901 GstPad *sinkpad = NULL;
7902 MMPlayerGstElement *mainbin = NULL;
7903 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7904 GstCaps *caps = NULL;
7905 gint total_track_num = 0;
7909 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7910 MM_ERROR_PLAYER_NOT_INITIALIZED);
7912 LOGD("Change Track(%d) to %d", type, index);
7914 mainbin = player->pipeline->mainbin;
7916 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7917 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7918 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7919 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7921 /* Changing Video Track is not supported. */
7922 LOGE("Track Type Error");
7926 if (mainbin[elem_idx].gst == NULL) {
7927 result = MM_ERROR_PLAYER_NO_OP;
7928 LOGD("Req track doesn't exist");
7932 total_track_num = player->selector[type].total_track_num;
7933 if (total_track_num <= 0) {
7934 result = MM_ERROR_PLAYER_NO_OP;
7935 LOGD("Language list is not available");
7939 if ((index < 0) || (index >= total_track_num)) {
7940 result = MM_ERROR_INVALID_ARGUMENT;
7941 LOGD("Not a proper index : %d", index);
7945 /*To get the new pad from the selector*/
7946 change_pad_name = g_strdup_printf("sink_%u", index);
7947 if (change_pad_name == NULL) {
7948 result = MM_ERROR_PLAYER_INTERNAL;
7949 LOGD("Pad does not exists");
7953 LOGD("new active pad name: %s", change_pad_name);
7955 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7956 if (sinkpad == NULL) {
7957 LOGD("sinkpad is NULL");
7958 result = MM_ERROR_PLAYER_INTERNAL;
7962 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
7963 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7965 caps = gst_pad_get_current_caps(sinkpad);
7966 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7969 gst_object_unref(sinkpad);
7971 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7972 __mmplayer_set_audio_attrs(player, caps);
7975 MMPLAYER_FREEIF(change_pad_name);
7980 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7982 int result = MM_ERROR_NONE;
7983 mm_player_t *player = NULL;
7984 MMPlayerGstElement *mainbin = NULL;
7986 gint current_active_index = 0;
7988 GstState current_state = GST_STATE_VOID_PENDING;
7989 GstEvent *event = NULL;
7994 player = (mm_player_t *)hplayer;
7995 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7997 if (!player->pipeline) {
7998 LOGE("Track %d pre setting -> %d", type, index);
8000 player->selector[type].active_pad_index = index;
8004 mainbin = player->pipeline->mainbin;
8006 current_active_index = player->selector[type].active_pad_index;
8008 /*If index is same as running index no need to change the pad*/
8009 if (current_active_index == index)
8012 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8013 result = MM_ERROR_PLAYER_INVALID_STATE;
8017 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8018 if (current_state < GST_STATE_PAUSED) {
8019 result = MM_ERROR_PLAYER_INVALID_STATE;
8020 LOGW("Pipeline not in porper state");
8024 result = __mmplayer_change_selector_pad(player, type, index);
8025 if (result != MM_ERROR_NONE) {
8026 LOGE("change selector pad error");
8030 player->selector[type].active_pad_index = index;
8032 if (current_state == GST_STATE_PLAYING) {
8033 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8034 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8035 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8037 __mmplayer_gst_send_event_to_sink(player, event);
8039 result = MM_ERROR_PLAYER_INTERNAL;
8049 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8051 mm_player_t *player = (mm_player_t *)hplayer;
8055 /* check player handle */
8056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8058 *silent = player->set_mode.subtitle_off;
8060 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8064 return MM_ERROR_NONE;
8068 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8070 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8071 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8073 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8074 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8078 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8079 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8080 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8081 mm_player_dump_t *dump_s;
8082 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8083 if (dump_s == NULL) {
8084 LOGE("malloc fail");
8088 dump_s->dump_element_file = NULL;
8089 dump_s->dump_pad = NULL;
8090 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8092 if (dump_s->dump_pad) {
8093 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8094 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]);
8095 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8096 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);
8097 /* add list for removed buffer probe and close FILE */
8098 player->dump_list = g_list_append(player->dump_list, dump_s);
8099 LOGD("%s sink pad added buffer probe for dump", factory_name);
8102 MMPLAYER_FREEIF(dump_s);
8103 LOGE("failed to get %s sink pad added", factory_name);
8110 static GstPadProbeReturn
8111 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8113 FILE *dump_data = (FILE *)u_data;
8115 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8116 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8118 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8120 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8122 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8124 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8126 return GST_PAD_PROBE_OK;
8130 __mmplayer_release_dump_list(GList *dump_list)
8132 GList *d_list = dump_list;
8137 for (; d_list; d_list = g_list_next(d_list)) {
8138 mm_player_dump_t *dump_s = d_list->data;
8139 if (dump_s->dump_pad) {
8140 if (dump_s->probe_handle_id)
8141 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8143 if (dump_s->dump_element_file) {
8144 fclose(dump_s->dump_element_file);
8145 dump_s->dump_element_file = NULL;
8147 MMPLAYER_FREEIF(dump_s);
8149 g_list_free(dump_list);
8154 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8156 mm_player_t *player = (mm_player_t *)hplayer;
8160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8161 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8163 *exist = (bool)player->has_closed_caption;
8167 return MM_ERROR_NONE;
8171 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8175 // LOGD("unref internal gst buffer %p", buffer);
8176 gst_buffer_unref((GstBuffer *)buffer);
8183 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8185 mm_player_t *player = (mm_player_t *)hplayer;
8189 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8190 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8192 if (MMPLAYER_IS_STREAMING(player))
8193 *timeout = (int)player->ini.live_state_change_timeout;
8195 *timeout = (int)player->ini.localplayback_state_change_timeout;
8197 LOGD("timeout = %d", *timeout);
8200 return MM_ERROR_NONE;
8204 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8206 mm_player_t *player = (mm_player_t *)hplayer;
8210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8211 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8213 *num = player->video_num_buffers;
8214 *extra_num = player->video_extra_num_buffers;
8216 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8219 return MM_ERROR_NONE;
8223 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8227 MMPLAYER_RETURN_IF_FAIL(player);
8229 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8231 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8232 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8233 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8234 player->storage_info[i].id = -1;
8235 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8237 if (path_type != MMPLAYER_PATH_MAX)
8246 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8248 int ret = MM_ERROR_NONE;
8249 mm_player_t *player = (mm_player_t *)hplayer;
8250 MMMessageParamType msg_param = {0, };
8253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8255 LOGW("state changed storage %d:%d", id, state);
8257 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8258 return MM_ERROR_NONE;
8260 /* FIXME: text path should be handled seperately. */
8261 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8262 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8263 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8264 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8265 LOGW("external storage is removed");
8267 if (player->msg_posted == FALSE) {
8268 memset(&msg_param, 0, sizeof(MMMessageParamType));
8269 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8270 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8271 player->msg_posted = TRUE;
8274 /* unrealize the player */
8275 ret = _mmplayer_unrealize(hplayer);
8276 if (ret != MM_ERROR_NONE)
8277 LOGE("failed to unrealize");
8285 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8287 int ret = MM_ERROR_NONE;
8288 mm_player_t *player = (mm_player_t *)hplayer;
8289 int idx = 0, total = 0;
8290 gchar *result = NULL, *tmp = NULL;
8293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8294 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8296 total = *num = g_list_length(player->adaptive_info.var_list);
8298 LOGW("There is no stream variant info.");
8302 result = g_strdup("");
8303 for (idx = 0 ; idx < total ; idx++) {
8304 VariantData *v_data = NULL;
8305 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8308 gchar data[64] = {0};
8309 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8311 tmp = g_strconcat(result, data, NULL);
8315 LOGW("There is no variant data in %d", idx);
8320 *var_info = (char *)result;
8322 LOGD("variant info %d:%s", *num, *var_info);
8328 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8330 int ret = MM_ERROR_NONE;
8331 mm_player_t *player = (mm_player_t *)hplayer;
8334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8336 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8338 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8339 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8340 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8342 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8343 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8344 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8345 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8347 /* FIXME: seek to current position for applying new variant limitation */
8356 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8358 int ret = MM_ERROR_NONE;
8359 mm_player_t *player = (mm_player_t *)hplayer;
8362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8363 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8365 *bandwidth = player->adaptive_info.limit.bandwidth;
8366 *width = player->adaptive_info.limit.width;
8367 *height = player->adaptive_info.limit.height;
8369 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8376 _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8378 int ret = MM_ERROR_NONE;
8379 mm_player_t *player = (mm_player_t *)hplayer;
8382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8384 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8385 LOGW("buffer_ms will not be applied.");
8387 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8389 if (player->streamer == NULL) {
8390 player->streamer = __mm_player_streaming_create();
8391 __mm_player_streaming_initialize(player->streamer, TRUE);
8395 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8397 if (rebuffer_ms >= 0)
8398 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8406 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8408 int ret = MM_ERROR_NONE;
8409 mm_player_t *player = (mm_player_t *)hplayer;
8412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8413 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8415 if (player->streamer == NULL) {
8416 player->streamer = __mm_player_streaming_create();
8417 __mm_player_streaming_initialize(player->streamer, TRUE);
8420 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8421 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8423 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8430 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8432 #define IDX_FIRST_SW_CODEC 0
8433 mm_player_t *player = (mm_player_t *)hplayer;
8434 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8435 MMHandleType attrs = 0;
8438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8440 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8441 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8442 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8444 switch (stream_type) {
8445 case MM_PLAYER_STREAM_TYPE_AUDIO:
8446 /* to support audio codec selection, codec info have to be added in ini file as below.
8447 audio codec element hw = xxxx
8448 audio codec element sw = avdec */
8449 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8450 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8451 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8452 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8453 LOGE("There is no audio codec info for codec_type %d", codec_type);
8454 return MM_ERROR_PLAYER_NO_OP;
8457 case MM_PLAYER_STREAM_TYPE_VIDEO:
8458 /* to support video codec selection, codec info have to be added in ini file as below.
8459 video codec element hw = omx
8460 video codec element sw = avdec */
8461 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8462 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8463 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8464 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8465 LOGE("There is no video codec info for codec_type %d", codec_type);
8466 return MM_ERROR_PLAYER_NO_OP;
8470 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8471 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8475 LOGD("update %s codec_type to %d", attr_name, codec_type);
8477 attrs = MMPLAYER_GET_ATTRS(player);
8478 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8480 if (mm_attrs_commit_all(player->attrs)) {
8481 LOGE("failed to commit codec_type attributes");
8482 return MM_ERROR_PLAYER_INTERNAL;
8486 return MM_ERROR_NONE;
8490 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8492 mm_player_t *player = (mm_player_t *)hplayer;
8493 GstElement *rg_vol_element = NULL;
8497 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8499 player->sound.rg_enable = enabled;
8501 /* just hold rgvolume enable value if pipeline is not ready */
8502 if (!player->pipeline || !player->pipeline->audiobin) {
8503 LOGD("pipeline is not ready. holding rgvolume enable value");
8504 return MM_ERROR_NONE;
8507 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8509 if (!rg_vol_element) {
8510 LOGD("rgvolume element is not created");
8511 return MM_ERROR_PLAYER_INTERNAL;
8515 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8517 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8521 return MM_ERROR_NONE;
8525 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8527 mm_player_t *player = (mm_player_t *)hplayer;
8528 GstElement *rg_vol_element = NULL;
8529 gboolean enable = FALSE;
8533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8534 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8536 /* just hold enable_rg value if pipeline is not ready */
8537 if (!player->pipeline || !player->pipeline->audiobin) {
8538 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8539 *enabled = player->sound.rg_enable;
8540 return MM_ERROR_NONE;
8543 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8545 if (!rg_vol_element) {
8546 LOGD("rgvolume element is not created");
8547 return MM_ERROR_PLAYER_INTERNAL;
8550 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8551 *enabled = (bool)enable;
8555 return MM_ERROR_NONE;
8559 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8561 mm_player_t *player = (mm_player_t *)hplayer;
8562 MMHandleType attrs = 0;
8563 void *handle = NULL;
8564 int ret = MM_ERROR_NONE;
8568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8570 attrs = MMPLAYER_GET_ATTRS(player);
8571 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8573 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8575 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8576 return MM_ERROR_PLAYER_INTERNAL;
8579 player->video_roi.scale_x = scale_x;
8580 player->video_roi.scale_y = scale_y;
8581 player->video_roi.scale_width = scale_width;
8582 player->video_roi.scale_height = scale_height;
8584 /* check video sinkbin is created */
8585 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8586 return MM_ERROR_NONE;
8588 if (!gst_video_overlay_set_video_roi_area(
8589 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8590 scale_x, scale_y, scale_width, scale_height))
8591 ret = MM_ERROR_PLAYER_INTERNAL;
8593 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8594 scale_x, scale_y, scale_width, scale_height);
8602 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8604 mm_player_t *player = (mm_player_t *)hplayer;
8605 int ret = MM_ERROR_NONE;
8609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8610 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8612 *scale_x = player->video_roi.scale_x;
8613 *scale_y = player->video_roi.scale_y;
8614 *scale_width = player->video_roi.scale_width;
8615 *scale_height = player->video_roi.scale_height;
8617 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8618 *scale_x, *scale_y, *scale_width, *scale_height);
8624 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8626 gboolean ret = FALSE;
8627 gint64 dur_nsec = 0;
8628 LOGD("try to update duration");
8630 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8631 player->duration = dur_nsec;
8632 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8636 if (player->duration < 0) {
8637 LOGW("duration is Non-Initialized !!!");
8638 player->duration = 0;
8641 /* update streaming service type */
8642 player->streaming_type = __mmplayer_get_stream_service_type(player);
8644 /* check duration is OK */
8645 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8646 /* FIXIT : find another way to get duration here. */
8647 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8653 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8655 /* update audio params
8656 NOTE : We need original audio params and it can be only obtained from src pad of audio
8657 decoder. Below code only valid when we are not using 'resampler' just before
8658 'audioconverter'. */
8659 GstCaps *caps_a = NULL;
8661 gint samplerate = 0, channels = 0;
8662 GstStructure *p = NULL;
8664 LOGD("try to update audio attrs");
8666 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8667 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8669 pad = gst_element_get_static_pad(
8670 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8673 LOGW("failed to get pad from audiosink");
8677 caps_a = gst_pad_get_current_caps(pad);
8679 LOGW("not ready to get audio caps");
8680 gst_object_unref(pad);
8684 p = gst_caps_get_structure(caps_a, 0);
8686 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8688 gst_structure_get_int(p, "rate", &samplerate);
8689 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8691 gst_structure_get_int(p, "channels", &channels);
8692 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8694 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8696 gst_caps_unref(caps_a);
8697 gst_object_unref(pad);
8703 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8705 LOGD("try to update video attrs");
8707 GstCaps *caps_v = NULL;
8711 GstStructure *p = NULL;
8713 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8714 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8716 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8718 LOGD("no videosink sink pad");
8722 caps_v = gst_pad_get_current_caps(pad);
8723 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8724 if (!caps_v && player->v_stream_caps) {
8725 caps_v = player->v_stream_caps;
8726 gst_caps_ref(caps_v);
8730 LOGD("no negitiated caps from videosink");
8731 gst_object_unref(pad);
8735 p = gst_caps_get_structure(caps_v, 0);
8736 gst_structure_get_int(p, "width", &width);
8737 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8739 gst_structure_get_int(p, "height", &height);
8740 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8742 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8744 SECURE_LOGD("width : %d height : %d", width, height);
8746 gst_caps_unref(caps_v);
8747 gst_object_unref(pad);
8750 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8751 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8758 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8760 gboolean ret = FALSE;
8761 guint64 data_size = 0;
8765 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8766 if (!player->duration)
8769 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8770 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8771 if (stat(path, &sb) == 0)
8772 data_size = (guint64)sb.st_size;
8774 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8775 data_size = player->http_content_size;
8778 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8781 guint64 bitrate = 0;
8782 guint64 msec_dur = 0;
8784 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8786 bitrate = data_size * 8 * 1000 / msec_dur;
8787 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8788 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8792 LOGD("player duration is less than 0");
8796 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8797 if (player->total_bitrate) {
8798 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8807 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8809 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8810 data->uri_type = uri_type;
8814 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8816 int ret = MM_ERROR_PLAYER_INVALID_URI;
8818 char *buffer = NULL;
8819 char *seperator = strchr(path, ',');
8820 char ext[100] = {0,}, size[100] = {0,};
8823 if ((buffer = strstr(path, "ext="))) {
8824 buffer += strlen("ext=");
8826 if (strlen(buffer)) {
8827 strncpy(ext, buffer, 99);
8829 if ((seperator = strchr(ext, ','))
8830 || (seperator = strchr(ext, ' '))
8831 || (seperator = strchr(ext, '\0'))) {
8832 seperator[0] = '\0';
8837 if ((buffer = strstr(path, "size="))) {
8838 buffer += strlen("size=");
8840 if (strlen(buffer) > 0) {
8841 strncpy(size, buffer, 99);
8843 if ((seperator = strchr(size, ','))
8844 || (seperator = strchr(size, ' '))
8845 || (seperator = strchr(size, '\0'))) {
8846 seperator[0] = '\0';
8849 mem_size = atoi(size);
8854 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8856 if (mem_size && param) {
8857 if (data->input_mem.buf)
8858 free(data->input_mem.buf);
8859 data->input_mem.buf = malloc(mem_size);
8861 if (data->input_mem.buf) {
8862 memcpy(data->input_mem.buf, param, mem_size);
8863 data->input_mem.len = mem_size;
8864 ret = MM_ERROR_NONE;
8866 LOGE("failed to alloc mem %d", mem_size);
8867 ret = MM_ERROR_PLAYER_INTERNAL;
8870 data->input_mem.offset = 0;
8871 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8878 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8880 gchar *location = NULL;
8883 int ret = MM_ERROR_NONE;
8885 if ((path = strstr(uri, "file://"))) {
8886 location = g_filename_from_uri(uri, NULL, &err);
8887 if (!location || (err != NULL)) {
8888 LOGE("Invalid URI '%s' for filesrc: %s", path,
8889 (err != NULL) ? err->message : "unknown error");
8893 MMPLAYER_FREEIF(location);
8895 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8896 return MM_ERROR_PLAYER_INVALID_URI;
8898 LOGD("path from uri: %s", location);
8901 path = (location != NULL) ? (location) : ((char *)uri);
8904 ret = util_exist_file_path(path);
8906 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8907 if (ret == MM_ERROR_NONE) {
8908 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8909 if (util_is_sdp_file(path)) {
8910 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8911 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8913 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8915 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8916 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8918 LOGE("invalid uri, could not play..");
8919 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8922 MMPLAYER_FREEIF(location);
8927 static MMPlayerVideoStreamDataType *
8928 __mmplayer_create_stream_from_pad(GstPad *pad)
8930 GstCaps *caps = NULL;
8931 GstStructure *structure = NULL;
8932 unsigned int fourcc = 0;
8933 const gchar *string_format = NULL;
8934 MMPlayerVideoStreamDataType *stream = NULL;
8936 MMPixelFormatType format;
8938 caps = gst_pad_get_current_caps(pad);
8940 LOGE("Caps is NULL.");
8944 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8945 structure = gst_caps_get_structure(caps, 0);
8946 gst_structure_get_int(structure, "width", &width);
8947 gst_structure_get_int(structure, "height", &height);
8948 string_format = gst_structure_get_string(structure, "format");
8950 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8951 format = util_get_pixtype(fourcc);
8952 gst_caps_unref(caps);
8955 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8956 LOGE("Wrong condition!!");
8960 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
8962 LOGE("failed to alloc mem for video data");
8966 stream->width = width;
8967 stream->height = height;
8968 stream->format = format;
8974 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8976 unsigned int pitch = 0;
8978 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8980 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8981 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8982 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8983 stream->stride[index] = pitch;
8984 stream->elevation[index] = stream->height;
8989 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
8991 if (stream->format == MM_PIXEL_FORMAT_I420) {
8992 int ret = TBM_SURFACE_ERROR_NONE;
8993 tbm_surface_h surface;
8994 tbm_surface_info_s info;
8996 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
8998 ret = tbm_surface_get_info(surface, &info);
8999 if (ret != TBM_SURFACE_ERROR_NONE) {
9000 tbm_surface_destroy(surface);
9004 tbm_surface_destroy(surface);
9005 stream->stride[0] = info.planes[0].stride;
9006 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9007 stream->stride[1] = info.planes[1].stride;
9008 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9009 stream->stride[2] = info.planes[2].stride;
9010 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9011 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9012 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9013 stream->stride[0] = stream->width * 4;
9014 stream->elevation[0] = stream->height;
9015 stream->bo_size = stream->stride[0] * stream->height;
9017 LOGE("Not support format %d", stream->format);
9025 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9027 tbm_bo_handle thandle;
9029 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9030 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9031 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9035 unsigned char *src = NULL;
9036 unsigned char *dest = NULL;
9037 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9039 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9041 LOGE("fail to gst_memory_map");
9045 if (!mapinfo.data) {
9046 LOGE("data pointer is wrong");
9050 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9051 if (!stream->bo[0]) {
9052 LOGE("Fail to tbm_bo_alloc!!");
9056 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9058 LOGE("thandle pointer is wrong");
9062 if (stream->format == MM_PIXEL_FORMAT_I420) {
9063 src_stride[0] = GST_ROUND_UP_4(stream->width);
9064 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9065 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9066 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9069 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9070 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9072 for (i = 0; i < 3; i++) {
9073 src = mapinfo.data + src_offset[i];
9074 dest = thandle.ptr + dest_offset[i];
9079 for (j = 0; j < stream->height >> k; j++) {
9080 memcpy(dest, src, stream->width>>k);
9081 src += src_stride[i];
9082 dest += stream->stride[i];
9085 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9086 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9088 LOGE("Not support format %d", stream->format);
9092 tbm_bo_unmap(stream->bo[0]);
9093 gst_memory_unmap(mem, &mapinfo);
9099 tbm_bo_unmap(stream->bo[0]);
9102 gst_memory_unmap(mem, &mapinfo);
9108 __mmplayer_set_pause_state(mm_player_t *player)
9110 if (player->sent_bos)
9113 /* rtsp case, get content attrs by GstMessage */
9114 if (MMPLAYER_IS_RTSP_STREAMING(player))
9117 /* it's first time to update all content attrs. */
9118 __mmplayer_update_content_attrs(player, ATTR_ALL);
9122 __mmplayer_set_playing_state(mm_player_t *player)
9124 gchar *audio_codec = NULL;
9126 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9127 /* initialize because auto resume is done well. */
9128 player->resumed_by_rewind = FALSE;
9129 player->playback_rate = 1.0;
9132 if (player->sent_bos)
9135 /* try to get content metadata */
9137 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9138 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9139 * legacy mmfw-player api
9141 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9143 if ((player->cmd == MMPLAYER_COMMAND_START)
9144 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9145 __mmplayer_handle_missed_plugin(player);
9148 /* check audio codec field is set or not
9149 * we can get it from typefinder or codec's caps.
9151 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9153 /* The codec format can't be sent for audio only case like amr, mid etc.
9154 * Because, parser don't make related TAG.
9155 * So, if it's not set yet, fill it with found data.
9158 if (g_strrstr(player->type, "audio/midi"))
9159 audio_codec = "MIDI";
9160 else if (g_strrstr(player->type, "audio/x-amr"))
9161 audio_codec = "AMR";
9162 else if (g_strrstr(player->type, "audio/mpeg")
9163 && !g_strrstr(player->type, "mpegversion= (int)1"))
9164 audio_codec = "AAC";
9166 audio_codec = "unknown";
9168 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9170 if (mm_attrs_commit_all(player->attrs))
9171 LOGE("failed to update attributes");
9173 LOGD("set audio codec type with caps");