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 #define ESTIMATED_BUFFER_UNIT (1 * 1024 * 1024)
1347 gint init_buffering_time = 0;
1348 guint buffer_bytes = 0;
1349 gint64 dur_bytes = 0L;
1352 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1353 player->pipeline->mainbin && player->streamer, FALSE);
1355 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1356 buffer_bytes = (guint)(init_buffering_time / 1000) * ESTIMATED_BUFFER_UNIT;
1358 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1359 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1361 init_buffering_time = (init_buffering_time != 0) ? init_buffering_time : player->ini.http_buffering_time;
1363 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1364 LOGE("fail to get duration.");
1366 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1367 * use file information was already set on Q2 when it was created. */
1368 __mm_player_streaming_set_queue2(player->streamer,
1369 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1370 TRUE, /* use_buffering */
1372 init_buffering_time,
1373 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1375 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1382 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1384 mm_player_t *player = NULL;
1385 GstElement *video_selector = NULL;
1386 GstElement *audio_selector = NULL;
1387 GstElement *text_selector = NULL;
1390 player = (mm_player_t *)data;
1392 LOGD("no-more-pad signal handling");
1394 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1395 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1396 LOGW("player is shutting down");
1400 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1401 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1402 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1403 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1404 LOGE("failed to set queue2 buffering");
1409 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1410 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1411 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1413 /* create video path followed by video-select */
1414 if (video_selector && !audio_selector && !text_selector)
1415 player->no_more_pad = TRUE;
1417 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1420 /* create audio path followed by audio-select */
1421 if (audio_selector && !text_selector)
1422 player->no_more_pad = TRUE;
1424 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1427 /* create text path followed by text-select */
1428 __mmplayer_create_text_sink_path(player, text_selector);
1431 if (player->gapless.reconfigure) {
1432 player->gapless.reconfigure = FALSE;
1433 MMPLAYER_PLAYBACK_UNLOCK(player);
1440 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1442 gboolean ret = FALSE;
1443 GstElement *pipeline = NULL;
1444 GstPad *sinkpad = NULL;
1447 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1450 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1452 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1454 LOGE("failed to get pad from sinkbin");
1460 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1461 LOGE("failed to link sinkbin for reusing");
1462 goto EXIT; /* exit either pass or fail */
1466 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1467 LOGE("failed to set state(READY) to sinkbin");
1472 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1473 LOGE("failed to add sinkbin to pipeline");
1478 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1479 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1484 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1485 LOGE("failed to set state(PAUSED) to sinkbin");
1494 gst_object_unref(GST_OBJECT(sinkpad));
1502 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1504 mm_player_t *player = NULL;
1505 MMHandleType attrs = 0;
1506 GstCaps *caps = NULL;
1507 gchar *caps_str = NULL;
1508 GstStructure *str = NULL;
1509 const gchar *name = NULL;
1510 GstElement *sinkbin = NULL;
1511 gboolean reusing = FALSE;
1512 gboolean caps_ret = TRUE;
1513 gchar *sink_pad_name = "sink";
1516 player = (mm_player_t *)data;
1519 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1520 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1522 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1526 caps_str = gst_caps_to_string(caps);
1528 /* LOGD("detected mimetype : %s", name); */
1529 if (strstr(name, "audio")) {
1530 if (player->pipeline->audiobin == NULL) {
1531 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1532 LOGE("failed to create audiobin. continuing without audio");
1536 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1537 LOGD("creating audiobin success");
1540 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1541 LOGD("reusing audiobin");
1542 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1544 } else if (strstr(name, "video")) {
1545 /* 1. zero copy is updated at _decode_pad_added()
1546 * 2. NULL surface type is handled in _decode_pad_added() */
1547 LOGD("zero copy %d", player->set_mode.video_zc);
1548 if (player->pipeline->videobin == NULL) {
1549 int surface_type = 0;
1550 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1551 LOGD("display_surface_type (%d)", surface_type);
1553 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1554 LOGD("mark video overlay for acquire");
1555 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1556 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1557 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1558 &player->video_overlay_resource)
1559 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1560 LOGE("could not mark video_overlay resource for acquire");
1565 player->interrupted_by_resource = FALSE;
1567 if (mm_resource_manager_commit(player->resource_manager) !=
1568 MM_RESOURCE_MANAGER_ERROR_NONE) {
1569 LOGE("could not acquire resources for video playing");
1573 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1574 LOGE("failed to create videobin. continuing without video");
1578 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1579 LOGD("creating videosink bin success");
1582 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1583 LOGD("re-using videobin");
1584 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1586 } else if (strstr(name, "text")) {
1587 if (player->pipeline->textbin == NULL) {
1588 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1589 LOGE("failed to create text sink bin. continuing without text");
1593 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1594 player->textsink_linked = 1;
1595 LOGD("creating textsink bin success");
1597 if (!player->textsink_linked) {
1598 LOGD("re-using textbin");
1600 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1601 player->textsink_linked = 1;
1603 /* linked textbin exist which means that the external subtitle path exist already */
1604 LOGW("ignoring internal subtutle since external subtitle is available");
1607 sink_pad_name = "text_sink";
1609 LOGW("unknown mime type %s, ignoring it", name);
1613 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1616 LOGD("[handle: %p] success to create and link sink bin", player);
1618 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1619 * streaming task. if the task blocked, then buffer will not flow to the next element
1620 *(autoplugging element). so this is special hack for streaming. please try to remove it
1622 /* dec stream count. we can remove fakesink if it's zero */
1623 if (player->num_dynamic_pad)
1624 player->num_dynamic_pad--;
1626 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1628 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1629 __mmplayer_pipeline_complete(NULL, player);
1633 MMPLAYER_FREEIF(caps_str);
1636 gst_caps_unref(caps);
1638 /* flusing out new attributes */
1639 if (mm_attrs_commit_all(attrs))
1640 LOGE("failed to comit attributes");
1646 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1648 int required_angle = 0; /* Angle required for straight view */
1649 int rotation_angle = 0;
1651 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1652 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1654 /* Counter clockwise */
1655 switch (orientation) {
1660 required_angle = 270;
1663 required_angle = 180;
1666 required_angle = 90;
1670 rotation_angle = display_angle + required_angle;
1671 if (rotation_angle >= 360)
1672 rotation_angle -= 360;
1674 /* chech if supported or not */
1675 if (rotation_angle % 90) {
1676 LOGD("not supported rotation angle = %d", rotation_angle);
1680 switch (rotation_angle) {
1682 *value = MM_DISPLAY_ROTATION_NONE;
1685 *value = MM_DISPLAY_ROTATION_90;
1688 *value = MM_DISPLAY_ROTATION_180;
1691 *value = MM_DISPLAY_ROTATION_270;
1695 LOGD("setting rotation property value : %d", *value);
1701 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1703 /* check video sinkbin is created */
1704 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1706 player->pipeline->videobin &&
1707 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1708 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1709 MM_ERROR_PLAYER_NOT_INITIALIZED);
1711 return MM_ERROR_NONE;
1715 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1717 int display_rotation = 0;
1718 gchar *org_orient = NULL;
1719 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1722 LOGE("cannot get content attribute");
1723 return MM_ERROR_PLAYER_INTERNAL;
1726 if (display_angle) {
1727 /* update user roation */
1728 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1730 /* Counter clockwise */
1731 switch (display_rotation) {
1732 case MM_DISPLAY_ROTATION_NONE:
1735 case MM_DISPLAY_ROTATION_90:
1736 *display_angle = 90;
1738 case MM_DISPLAY_ROTATION_180:
1739 *display_angle = 180;
1741 case MM_DISPLAY_ROTATION_270:
1742 *display_angle = 270;
1745 LOGW("wrong angle type : %d", display_rotation);
1748 LOGD("check user angle: %d", *display_angle);
1752 /* Counter clockwise */
1753 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1756 if (!strcmp(org_orient, "rotate-90"))
1758 else if (!strcmp(org_orient, "rotate-180"))
1760 else if (!strcmp(org_orient, "rotate-270"))
1763 LOGD("original rotation is %s", org_orient);
1765 LOGD("content_video_orientation get fail");
1768 LOGD("check orientation: %d", *orientation);
1771 return MM_ERROR_NONE;
1775 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1777 int rotation_value = 0;
1778 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1779 int display_angle = 0;
1782 /* check video sinkbin is created */
1783 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1786 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1788 /* get rotation value to set */
1789 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1790 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1791 LOGD("set video param : rotate %d", rotation_value);
1795 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1797 MMHandleType attrs = 0;
1801 /* check video sinkbin is created */
1802 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1805 attrs = MMPLAYER_GET_ATTRS(player);
1806 MMPLAYER_RETURN_IF_FAIL(attrs);
1808 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1809 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1810 LOGD("set video param : visible %d", visible);
1814 __mmplayer_video_param_set_display_method(mm_player_t *player)
1816 MMHandleType attrs = 0;
1817 int display_method = 0;
1820 /* check video sinkbin is created */
1821 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1824 attrs = MMPLAYER_GET_ATTRS(player);
1825 MMPLAYER_RETURN_IF_FAIL(attrs);
1827 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1828 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1829 LOGD("set video param : method %d", display_method);
1833 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1835 MMHandleType attrs = 0;
1836 void *handle = NULL;
1839 /* check video sinkbin is created */
1840 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1841 LOGW("There is no video sink");
1845 attrs = MMPLAYER_GET_ATTRS(player);
1846 MMPLAYER_RETURN_IF_FAIL(attrs);
1847 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1849 gst_video_overlay_set_video_roi_area(
1850 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1851 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1852 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1853 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1858 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1860 MMHandleType attrs = 0;
1861 void *handle = NULL;
1865 int win_roi_width = 0;
1866 int win_roi_height = 0;
1869 /* check video sinkbin is created */
1870 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1871 LOGW("There is no video sink");
1875 attrs = MMPLAYER_GET_ATTRS(player);
1876 MMPLAYER_RETURN_IF_FAIL(attrs);
1878 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1881 /* It should be set after setting window */
1882 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1883 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1884 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1885 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1887 /* After setting window handle, set display roi area */
1888 gst_video_overlay_set_display_roi_area(
1889 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1890 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1891 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1892 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1897 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1899 MMHandleType attrs = 0;
1900 void *handle = NULL;
1902 /* check video sinkbin is created */
1903 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1906 attrs = MMPLAYER_GET_ATTRS(player);
1907 MMPLAYER_RETURN_IF_FAIL(attrs);
1909 /* common case if using overlay surface */
1910 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1913 /* default is using wl_surface_id */
1914 unsigned int wl_surface_id = 0;
1915 wl_surface_id = *(int *)handle;
1916 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1917 gst_video_overlay_set_wl_window_wl_surface_id(
1918 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1921 /* FIXIT : is it error case? */
1922 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1927 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1929 gboolean update_all_param = FALSE;
1932 /* check video sinkbin is created */
1933 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1934 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1936 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1937 LOGE("can not find tizenwlsink");
1938 return MM_ERROR_PLAYER_INTERNAL;
1941 LOGD("param_name : %s", param_name);
1942 if (!g_strcmp0(param_name, "update_all_param"))
1943 update_all_param = TRUE;
1945 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1946 __mmplayer_video_param_set_display_overlay(player);
1947 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1948 __mmplayer_video_param_set_display_method(player);
1949 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1950 __mmplayer_video_param_set_display_visible(player);
1951 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1952 __mmplayer_video_param_set_display_rotation(player);
1953 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1954 __mmplayer_video_param_set_roi_area(player);
1955 if (update_all_param)
1956 __mmplayer_video_param_set_video_roi_area(player);
1958 return MM_ERROR_NONE;
1962 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1964 MMHandleType attrs = 0;
1965 int surface_type = 0;
1966 int ret = MM_ERROR_NONE;
1970 /* check video sinkbin is created */
1971 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1972 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1974 attrs = MMPLAYER_GET_ATTRS(player);
1976 LOGE("cannot get content attribute");
1977 return MM_ERROR_PLAYER_INTERNAL;
1979 LOGD("param_name : %s", param_name);
1981 /* update display surface */
1982 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1983 LOGD("check display surface type attribute: %d", surface_type);
1985 /* configuring display */
1986 switch (surface_type) {
1987 case MM_DISPLAY_SURFACE_OVERLAY:
1989 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1990 if (ret != MM_ERROR_NONE)
1998 return MM_ERROR_NONE;
2002 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2004 gboolean disable_overlay = FALSE;
2005 mm_player_t *player = (mm_player_t *)hplayer;
2006 int ret = MM_ERROR_NONE;
2009 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2010 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2011 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2012 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2014 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2015 LOGW("Display control is not supported");
2016 return MM_ERROR_PLAYER_INTERNAL;
2019 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2021 if (audio_only == (bool)disable_overlay) {
2022 LOGE("It's the same with current setting: (%d)", audio_only);
2023 return MM_ERROR_NONE;
2027 LOGE("disable overlay");
2028 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2030 /* release overlay resource */
2031 if (player->video_overlay_resource != NULL) {
2032 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2033 player->video_overlay_resource);
2034 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2035 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2038 player->video_overlay_resource = NULL;
2041 ret = mm_resource_manager_commit(player->resource_manager);
2042 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2043 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2047 /* mark video overlay for acquire */
2048 if (player->video_overlay_resource == NULL) {
2049 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2050 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2051 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2052 &player->video_overlay_resource);
2053 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2054 LOGE("could not prepare for video_overlay resource");
2059 player->interrupted_by_resource = FALSE;
2060 /* acquire resources for video overlay */
2061 ret = mm_resource_manager_commit(player->resource_manager);
2062 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2063 LOGE("could not acquire resources for video playing");
2067 LOGD("enable overlay");
2068 __mmplayer_video_param_set_display_overlay(player);
2069 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2074 return MM_ERROR_NONE;
2078 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2080 mm_player_t *player = (mm_player_t *)hplayer;
2081 gboolean disable_overlay = FALSE;
2085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2086 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2087 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2088 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2089 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2091 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2092 LOGW("Display control is not supported");
2093 return MM_ERROR_PLAYER_INTERNAL;
2096 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2098 *paudio_only = (bool)disable_overlay;
2100 LOGD("audio_only : %d", *paudio_only);
2104 return MM_ERROR_NONE;
2108 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2110 GList *bucket = element_bucket;
2111 MMPlayerGstElement *element = NULL;
2112 MMPlayerGstElement *prv_element = NULL;
2113 gint successful_link_count = 0;
2117 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2119 prv_element = (MMPlayerGstElement *)bucket->data;
2120 bucket = bucket->next;
2122 for (; bucket; bucket = bucket->next) {
2123 element = (MMPlayerGstElement *)bucket->data;
2125 if (element && element->gst) {
2126 if (prv_element && prv_element->gst) {
2127 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2128 LOGD("linking [%s] to [%s] success",
2129 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2130 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2131 successful_link_count++;
2133 LOGD("linking [%s] to [%s] failed",
2134 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2135 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2141 prv_element = element;
2146 return successful_link_count;
2150 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2152 GList *bucket = element_bucket;
2153 MMPlayerGstElement *element = NULL;
2154 int successful_add_count = 0;
2158 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2159 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2161 for (; bucket; bucket = bucket->next) {
2162 element = (MMPlayerGstElement *)bucket->data;
2164 if (element && element->gst) {
2165 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2166 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2167 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2168 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2171 successful_add_count++;
2177 return successful_add_count;
2181 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mm_player_t *player = (mm_player_t *)data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2218 if (player->video_stream_changed_cb) {
2219 LOGE("call the video stream changed cb");
2220 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2223 LOGW("invalid caps info");
2228 gst_caps_unref(caps);
2236 * This function is to create audio pipeline for playing.
2238 * @param player [in] handle of player
2240 * @return This function returns zero on success.
2242 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2244 /* macro for code readability. just for sinkbin-creation functions */
2245 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2247 x_bin[x_id].id = x_id;\
2248 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2249 if (!x_bin[x_id].gst) {\
2250 LOGE("failed to create %s", x_factory);\
2253 if (x_player->ini.set_dump_element_flag)\
2254 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2257 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2261 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2266 MMPLAYER_RETURN_IF_FAIL(player);
2268 if (player->audio_stream_buff_list) {
2269 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2270 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2273 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2274 __mmplayer_audio_stream_send_data(player, tmp);
2276 MMPLAYER_FREEIF(tmp->pcm_data);
2277 MMPLAYER_FREEIF(tmp);
2280 g_list_free(player->audio_stream_buff_list);
2281 player->audio_stream_buff_list = NULL;
2288 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2290 MMPlayerAudioStreamDataType audio_stream = { 0, };
2293 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2295 audio_stream.bitrate = a_buffer->bitrate;
2296 audio_stream.channel = a_buffer->channel;
2297 audio_stream.depth = a_buffer->depth;
2298 audio_stream.is_little_endian = a_buffer->is_little_endian;
2299 audio_stream.channel_mask = a_buffer->channel_mask;
2300 audio_stream.data_size = a_buffer->data_size;
2301 audio_stream.data = a_buffer->pcm_data;
2303 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2304 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2310 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2312 mm_player_t *player = (mm_player_t *)data;
2316 gint endianness = 0;
2317 guint64 channel_mask = 0;
2318 void *a_data = NULL;
2320 mm_player_audio_stream_buff_t *a_buffer = NULL;
2321 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2325 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2327 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2328 a_data = mapinfo.data;
2329 a_size = mapinfo.size;
2331 GstCaps *caps = gst_pad_get_current_caps(pad);
2332 GstStructure *structure = gst_caps_get_structure(caps, 0);
2334 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2335 gst_structure_get_int(structure, "rate", &rate);
2336 gst_structure_get_int(structure, "channels", &channel);
2337 gst_structure_get_int(structure, "depth", &depth);
2338 gst_structure_get_int(structure, "endianness", &endianness);
2339 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2340 gst_caps_unref(GST_CAPS(caps));
2342 /* In case of the sync is false, use buffer list. *
2343 * The num of buffer list depends on the num of audio channels */
2344 if (player->audio_stream_buff_list) {
2345 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2346 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2348 if (channel_mask == tmp->channel_mask) {
2349 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2350 if (tmp->data_size + a_size < tmp->buff_size) {
2351 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2352 tmp->data_size += a_size;
2354 /* send data to client */
2355 __mmplayer_audio_stream_send_data(player, tmp);
2357 if (a_size > tmp->buff_size) {
2358 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2359 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2360 if (tmp->pcm_data == NULL) {
2361 LOGE("failed to realloc data.");
2364 tmp->buff_size = a_size;
2366 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2367 memcpy(tmp->pcm_data, a_data, a_size);
2368 tmp->data_size = a_size;
2373 LOGE("data is empty in list.");
2379 /* create new audio stream data */
2380 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2381 if (a_buffer == NULL) {
2382 LOGE("failed to alloc data.");
2385 a_buffer->bitrate = rate;
2386 a_buffer->channel = channel;
2387 a_buffer->depth = depth;
2388 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2389 a_buffer->channel_mask = channel_mask;
2390 a_buffer->data_size = a_size;
2392 if (!player->audio_stream_sink_sync) {
2393 /* If sync is FALSE, use buffer list to reduce the IPC. */
2394 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2395 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2396 if (a_buffer->pcm_data == NULL) {
2397 LOGE("failed to alloc data.");
2398 MMPLAYER_FREEIF(a_buffer);
2401 memcpy(a_buffer->pcm_data, a_data, a_size);
2402 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2403 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2405 /* If sync is TRUE, send data directly. */
2406 a_buffer->pcm_data = a_data;
2407 __mmplayer_audio_stream_send_data(player, a_buffer);
2408 MMPLAYER_FREEIF(a_buffer);
2412 gst_buffer_unmap(buffer, &mapinfo);
2417 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2419 mm_player_t *player = (mm_player_t *)data;
2420 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2421 GstPad *sinkpad = NULL;
2422 GstElement *queue = NULL, *sink = NULL;
2425 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2427 queue = gst_element_factory_make("queue", NULL);
2428 if (queue == NULL) {
2429 LOGD("fail make queue");
2433 sink = gst_element_factory_make("fakesink", NULL);
2435 LOGD("fail make fakesink");
2439 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2441 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2442 LOGW("failed to link queue & sink");
2446 sinkpad = gst_element_get_static_pad(queue, "sink");
2448 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2449 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2453 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2455 gst_object_unref(sinkpad);
2456 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2457 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2459 gst_element_set_state(sink, GST_STATE_PAUSED);
2460 gst_element_set_state(queue, GST_STATE_PAUSED);
2462 __mmplayer_add_signal_connection(player,
2464 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2466 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2473 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2475 gst_object_unref(GST_OBJECT(queue));
2479 gst_object_unref(GST_OBJECT(sink));
2483 gst_object_unref(GST_OBJECT(sinkpad));
2491 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2493 #define MAX_PROPS_LEN 128
2494 gint latency_mode = 0;
2495 gchar *stream_type = NULL;
2496 gchar *latency = NULL;
2498 gchar stream_props[MAX_PROPS_LEN] = {0,};
2499 GstStructure *props = NULL;
2502 * It should be set after player creation through attribute.
2503 * But, it can not be changed during playing.
2506 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2508 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2509 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2512 LOGE("stream_type is null.");
2514 if (player->sound.focus_id)
2515 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2516 stream_type, stream_id, player->sound.focus_id);
2518 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2519 stream_type, stream_id);
2520 props = gst_structure_from_string(stream_props, NULL);
2521 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2522 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2523 stream_type, stream_id, player->sound.focus_id, stream_props);
2524 gst_structure_free(props);
2527 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2529 switch (latency_mode) {
2530 case AUDIO_LATENCY_MODE_LOW:
2531 latency = g_strndup("low", 3);
2533 case AUDIO_LATENCY_MODE_MID:
2534 latency = g_strndup("mid", 3);
2536 case AUDIO_LATENCY_MODE_HIGH:
2537 latency = g_strndup("high", 4);
2541 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2545 LOGD("audiosink property - latency=%s", latency);
2547 MMPLAYER_FREEIF(latency);
2553 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2555 MMPlayerGstElement *audiobin = NULL;
2558 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2560 audiobin = player->pipeline->audiobin;
2562 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2563 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2564 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2566 if (player->video360_yaw_radians <= M_PI &&
2567 player->video360_yaw_radians >= -M_PI &&
2568 player->video360_pitch_radians <= M_PI_2 &&
2569 player->video360_pitch_radians >= -M_PI_2) {
2570 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2571 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2572 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2573 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2574 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2575 "source-orientation-y", player->video360_metadata.init_view_heading,
2576 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2583 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2585 MMPlayerGstElement *audiobin = NULL;
2586 MMHandleType attrs = 0;
2587 GList *element_bucket = NULL;
2588 GstCaps *acaps = NULL;
2589 GstPad *sink_pad = NULL;
2592 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2593 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2595 audiobin = player->pipeline->audiobin;
2596 attrs = MMPLAYER_GET_ATTRS(player);
2599 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2601 /* replaygain volume */
2602 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2603 if (player->sound.rg_enable)
2604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2606 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2609 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2611 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2612 gchar *dst_format = NULL;
2614 int dst_samplerate = 0;
2615 int dst_channels = 0;
2616 GstCaps *caps = NULL;
2617 char *caps_str = NULL;
2619 /* get conf. values */
2620 mm_attrs_multiple_get(player->attrs, NULL,
2621 "pcm_audioformat", &dst_format, &dst_len,
2622 "pcm_extraction_samplerate", &dst_samplerate,
2623 "pcm_extraction_channels", &dst_channels,
2626 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2629 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2630 caps = gst_caps_new_simple("audio/x-raw",
2631 "format", G_TYPE_STRING, dst_format,
2632 "rate", G_TYPE_INT, dst_samplerate,
2633 "channels", G_TYPE_INT, dst_channels,
2636 caps_str = gst_caps_to_string(caps);
2637 LOGD("new caps : %s", caps_str);
2639 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2642 gst_caps_unref(caps);
2643 MMPLAYER_FREEIF(caps_str);
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2649 /* raw pad handling signal, audiosink will be added after getting signal */
2650 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2651 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2655 /* normal playback */
2658 /* for logical volume control */
2659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2662 if (player->sound.mute) {
2663 LOGD("mute enabled");
2664 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2667 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2669 /* audio effect element. if audio effect is enabled */
2670 if ((strcmp(player->ini.audioeffect_element, ""))
2672 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2675 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2677 if ((!player->bypass_audio_effect)
2678 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2679 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2680 if (!_mmplayer_audio_effect_custom_apply(player))
2681 LOGI("apply audio effect(custom) setting success");
2685 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2686 && (player->set_mode.rich_audio))
2687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2690 /* create audio sink */
2691 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2692 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2693 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2695 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2696 if (player->is_360_feature_enabled &&
2697 player->is_content_spherical &&
2699 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2700 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2701 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2703 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2707 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2708 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2709 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2710 gst_caps_unref(acaps);
2712 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2714 player->is_openal_plugin_used = TRUE;
2716 if (player->is_360_feature_enabled && player->is_content_spherical)
2717 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2721 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2722 (player->videodec_linked && player->ini.use_system_clock)) {
2723 LOGD("system clock will be used.");
2724 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2727 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2728 __mmplayer_gst_set_pulsesink_property(player, attrs);
2729 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2730 __mmplayer_gst_set_openalsink_property(player);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2736 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2737 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2738 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2739 gst_object_unref(GST_OBJECT(sink_pad));
2741 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2744 *bucket = element_bucket;
2747 return MM_ERROR_NONE;
2750 g_list_free(element_bucket);
2754 return MM_ERROR_PLAYER_INTERNAL;
2758 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2760 MMPlayerGstElement *first_element = NULL;
2761 MMPlayerGstElement *audiobin = NULL;
2763 GstPad *ghostpad = NULL;
2764 GList *element_bucket = NULL;
2768 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2771 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2773 LOGE("failed to allocate memory for audiobin");
2774 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2778 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2779 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2780 if (!audiobin[MMPLAYER_A_BIN].gst) {
2781 LOGE("failed to create audiobin");
2786 player->pipeline->audiobin = audiobin;
2788 /* create audio filters and audiosink */
2789 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2792 /* adding created elements to bin */
2793 LOGD("adding created elements to bin");
2794 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2797 /* linking elements in the bucket by added order. */
2798 LOGD("Linking elements in the bucket by added order.");
2799 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2802 /* get first element's sinkpad for creating ghostpad */
2803 first_element = (MMPlayerGstElement *)element_bucket->data;
2804 if (!first_element) {
2805 LOGE("failed to get first elem");
2809 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2811 LOGE("failed to get pad from first element of audiobin");
2815 ghostpad = gst_ghost_pad_new("sink", pad);
2817 LOGE("failed to create ghostpad");
2821 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2822 LOGE("failed to add ghostpad to audiobin");
2826 gst_object_unref(pad);
2828 g_list_free(element_bucket);
2831 return MM_ERROR_NONE;
2834 LOGD("ERROR : releasing audiobin");
2837 gst_object_unref(GST_OBJECT(pad));
2840 gst_object_unref(GST_OBJECT(ghostpad));
2843 g_list_free(element_bucket);
2845 /* release element which are not added to bin */
2846 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2847 /* NOTE : skip bin */
2848 if (audiobin[i].gst) {
2849 GstObject *parent = NULL;
2850 parent = gst_element_get_parent(audiobin[i].gst);
2853 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2854 audiobin[i].gst = NULL;
2856 gst_object_unref(GST_OBJECT(parent));
2860 /* release audiobin with it's childs */
2861 if (audiobin[MMPLAYER_A_BIN].gst)
2862 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2864 MMPLAYER_FREEIF(audiobin);
2866 player->pipeline->audiobin = NULL;
2868 return MM_ERROR_PLAYER_INTERNAL;
2872 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2874 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2878 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2880 int ret = MM_ERROR_NONE;
2882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2883 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2885 MMPLAYER_VIDEO_BO_LOCK(player);
2887 if (player->video_bo_list) {
2888 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2889 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2890 if (tmp && tmp->bo == bo) {
2892 LOGD("release bo %p", bo);
2893 tbm_bo_unref(tmp->bo);
2894 MMPLAYER_VIDEO_BO_UNLOCK(player);
2895 MMPLAYER_VIDEO_BO_SIGNAL(player);
2900 /* hw codec is running or the list was reset for DRC. */
2901 LOGW("there is no bo list.");
2903 MMPLAYER_VIDEO_BO_UNLOCK(player);
2905 LOGW("failed to find bo %p", bo);
2910 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2915 MMPLAYER_RETURN_IF_FAIL(player);
2917 MMPLAYER_VIDEO_BO_LOCK(player);
2918 if (player->video_bo_list) {
2919 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2920 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2921 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2924 tbm_bo_unref(tmp->bo);
2928 g_list_free(player->video_bo_list);
2929 player->video_bo_list = NULL;
2931 player->video_bo_size = 0;
2932 MMPLAYER_VIDEO_BO_UNLOCK(player);
2939 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2942 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2943 gboolean ret = TRUE;
2945 /* check DRC, if it is, destroy the prev bo list to create again */
2946 if (player->video_bo_size != size) {
2947 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2948 __mmplayer_video_stream_destroy_bo_list(player);
2949 player->video_bo_size = size;
2952 MMPLAYER_VIDEO_BO_LOCK(player);
2954 if ((!player->video_bo_list) ||
2955 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2957 /* create bo list */
2959 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2961 if (player->video_bo_list) {
2962 /* if bo list did not created all, try it again. */
2963 idx = g_list_length(player->video_bo_list);
2964 LOGD("bo list exist(len: %d)", idx);
2967 for (; idx < player->ini.num_of_video_bo; idx++) {
2968 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2970 LOGE("Fail to alloc bo_info.");
2973 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2975 LOGE("Fail to tbm_bo_alloc.");
2976 MMPLAYER_FREEIF(bo_info);
2979 bo_info->used = FALSE;
2980 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2983 /* update video num buffers */
2984 player->video_num_buffers = idx;
2985 if (idx == player->ini.num_of_video_bo)
2986 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2989 MMPLAYER_VIDEO_BO_UNLOCK(player);
2993 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2997 /* get bo from list*/
2998 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2999 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3000 if (tmp && (tmp->used == FALSE)) {
3001 LOGD("found bo %p to use", tmp->bo);
3003 MMPLAYER_VIDEO_BO_UNLOCK(player);
3004 return tbm_bo_ref(tmp->bo);
3008 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3009 MMPLAYER_VIDEO_BO_UNLOCK(player);
3013 if (player->ini.video_bo_timeout <= 0) {
3014 MMPLAYER_VIDEO_BO_WAIT(player);
3016 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3017 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3024 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3026 mm_player_t *player = (mm_player_t *)data;
3028 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3030 /* send prerolled pkt */
3031 player->video_stream_prerolled = false;
3033 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3035 /* not to send prerolled pkt again */
3036 player->video_stream_prerolled = true;
3040 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3042 mm_player_t *player = (mm_player_t *)data;
3043 MMPlayerVideoStreamDataType *stream = NULL;
3044 GstMemory *mem = NULL;
3047 MMPLAYER_RETURN_IF_FAIL(player);
3048 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3050 if (player->video_stream_prerolled) {
3051 player->video_stream_prerolled = false;
3052 LOGD("skip the prerolled pkt not to send it again");
3056 /* clear stream data structure */
3057 stream = __mmplayer_create_stream_from_pad(pad);
3059 LOGE("failed to alloc stream");
3063 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3065 /* set size and timestamp */
3066 mem = gst_buffer_peek_memory(buffer, 0);
3067 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3068 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3070 /* check zero-copy */
3071 if (player->set_mode.video_zc &&
3072 player->set_mode.media_packet_video_stream &&
3073 gst_is_tizen_memory(mem)) {
3074 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3075 stream->internal_buffer = gst_buffer_ref(buffer);
3076 } else { /* sw codec */
3077 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3080 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3084 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3085 LOGE("failed to send video stream data.");
3092 LOGE("release video stream resource.");
3093 if (gst_is_tizen_memory(mem)) {
3095 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3097 tbm_bo_unref(stream->bo[i]);
3100 /* unref gst buffer */
3101 if (stream->internal_buffer)
3102 gst_buffer_unref(stream->internal_buffer);
3105 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3107 MMPLAYER_FREEIF(stream);
3112 __mmplayer_gst_set_video360_property(mm_player_t *player)
3114 MMPlayerGstElement *videobin = NULL;
3117 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3119 videobin = player->pipeline->videobin;
3121 /* Set spatial media metadata and/or user settings to the element.
3123 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3124 "projection-type", player->video360_metadata.projection_type, NULL);
3126 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3127 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3129 if (player->video360_metadata.full_pano_width_pixels &&
3130 player->video360_metadata.full_pano_height_pixels &&
3131 player->video360_metadata.cropped_area_image_width &&
3132 player->video360_metadata.cropped_area_image_height) {
3133 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3134 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3135 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3136 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3137 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3138 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3139 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3143 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3144 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3145 "horizontal-fov", player->video360_horizontal_fov,
3146 "vertical-fov", player->video360_vertical_fov, NULL);
3149 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3150 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3151 "zoom", 1.0f / player->video360_zoom, NULL);
3154 if (player->video360_yaw_radians <= M_PI &&
3155 player->video360_yaw_radians >= -M_PI &&
3156 player->video360_pitch_radians <= M_PI_2 &&
3157 player->video360_pitch_radians >= -M_PI_2) {
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3160 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3161 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3162 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3163 "pose-yaw", player->video360_metadata.init_view_heading,
3164 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3167 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3168 "passthrough", !player->is_video360_enabled, NULL);
3175 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3177 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3178 GList *element_bucket = NULL;
3181 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3183 /* create video360 filter */
3184 if (player->is_360_feature_enabled && player->is_content_spherical) {
3185 LOGD("create video360 element");
3186 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3187 __mmplayer_gst_set_video360_property(player);
3191 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3192 LOGD("skip creating the videoconv and rotator");
3193 return MM_ERROR_NONE;
3196 /* in case of sw codec & overlay surface type, except 360 playback.
3197 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3198 LOGD("create video converter: %s", video_csc);
3199 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3201 /* set video rotator */
3202 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3205 *bucket = element_bucket;
3207 return MM_ERROR_NONE;
3209 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3210 g_list_free(element_bucket);
3214 return MM_ERROR_PLAYER_INTERNAL;
3218 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3220 gchar *factory_name = NULL;
3222 switch (surface_type) {
3223 case MM_DISPLAY_SURFACE_OVERLAY:
3224 if (strlen(player->ini.videosink_element_overlay) > 0)
3225 factory_name = player->ini.videosink_element_overlay;
3227 case MM_DISPLAY_SURFACE_REMOTE:
3228 case MM_DISPLAY_SURFACE_NULL:
3229 if (strlen(player->ini.videosink_element_fake) > 0)
3230 factory_name = player->ini.videosink_element_fake;
3233 LOGE("unidentified surface type");
3237 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3238 return factory_name;
3242 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3244 gchar *factory_name = NULL;
3245 MMPlayerGstElement *videobin = NULL;
3250 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3252 videobin = player->pipeline->videobin;
3253 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3255 attrs = MMPLAYER_GET_ATTRS(player);
3257 LOGE("cannot get content attribute");
3258 return MM_ERROR_PLAYER_INTERNAL;
3261 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3262 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3263 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3265 /* support shard memory with S/W codec on HawkP */
3266 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3267 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3268 "use-tbm", use_tbm, NULL);
3272 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3273 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3276 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3278 LOGD("disable last-sample");
3279 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3282 if (player->set_mode.media_packet_video_stream) {
3284 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3285 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3286 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3288 __mmplayer_add_signal_connection(player,
3289 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3290 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3292 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3295 __mmplayer_add_signal_connection(player,
3296 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3297 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3299 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3303 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3304 return MM_ERROR_PLAYER_INTERNAL;
3306 if (videobin[MMPLAYER_V_SINK].gst) {
3307 GstPad *sink_pad = NULL;
3308 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3310 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3311 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3312 gst_object_unref(GST_OBJECT(sink_pad));
3314 LOGE("failed to get sink pad from videosink");
3318 return MM_ERROR_NONE;
3323 * - video overlay surface(arm/x86) : tizenwlsink
3326 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3329 GList *element_bucket = NULL;
3330 MMPlayerGstElement *first_element = NULL;
3331 MMPlayerGstElement *videobin = NULL;
3332 gchar *videosink_factory_name = NULL;
3335 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3338 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3340 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3342 player->pipeline->videobin = videobin;
3345 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3346 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3347 if (!videobin[MMPLAYER_V_BIN].gst) {
3348 LOGE("failed to create videobin");
3352 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3355 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3356 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3358 /* additional setting for sink plug-in */
3359 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3360 LOGE("failed to set video property");
3364 /* store it as it's sink element */
3365 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3367 /* adding created elements to bin */
3368 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3369 LOGE("failed to add elements");
3373 /* Linking elements in the bucket by added order */
3374 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3375 LOGE("failed to link elements");
3379 /* get first element's sinkpad for creating ghostpad */
3380 first_element = (MMPlayerGstElement *)element_bucket->data;
3381 if (!first_element) {
3382 LOGE("failed to get first element from bucket");
3386 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3388 LOGE("failed to get pad from first element");
3392 /* create ghostpad */
3393 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3394 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3395 LOGE("failed to add ghostpad to videobin");
3398 gst_object_unref(pad);
3400 /* done. free allocated variables */
3401 g_list_free(element_bucket);
3405 return MM_ERROR_NONE;
3408 LOGE("ERROR : releasing videobin");
3409 g_list_free(element_bucket);
3412 gst_object_unref(GST_OBJECT(pad));
3414 /* release videobin with it's childs */
3415 if (videobin[MMPLAYER_V_BIN].gst)
3416 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3418 MMPLAYER_FREEIF(videobin);
3419 player->pipeline->videobin = NULL;
3421 return MM_ERROR_PLAYER_INTERNAL;
3425 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3427 GList *element_bucket = NULL;
3428 MMPlayerGstElement *textbin = player->pipeline->textbin;
3430 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3431 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3432 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3433 "signal-handoffs", FALSE,
3436 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3437 __mmplayer_add_signal_connection(player,
3438 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3439 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3441 G_CALLBACK(__mmplayer_update_subtitle),
3444 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3445 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3447 if (!player->play_subtitle) {
3448 LOGD("add textbin sink as sink element of whole pipeline.");
3449 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3452 /* adding created elements to bin */
3453 LOGD("adding created elements to bin");
3454 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3455 LOGE("failed to add elements");
3459 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3460 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3461 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3463 /* linking elements in the bucket by added order. */
3464 LOGD("Linking elements in the bucket by added order.");
3465 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3466 LOGE("failed to link elements");
3470 /* done. free allocated variables */
3471 g_list_free(element_bucket);
3473 if (textbin[MMPLAYER_T_QUEUE].gst) {
3475 GstPad *ghostpad = NULL;
3477 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3479 LOGE("failed to get sink pad of text queue");
3483 ghostpad = gst_ghost_pad_new("text_sink", pad);
3484 gst_object_unref(pad);
3487 LOGE("failed to create ghostpad of textbin");
3491 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3492 LOGE("failed to add ghostpad to textbin");
3493 gst_object_unref(ghostpad);
3498 return MM_ERROR_NONE;
3501 g_list_free(element_bucket);
3503 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3504 LOGE("remove textbin sink from sink list");
3505 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3508 /* release element at __mmplayer_gst_create_text_sink_bin */
3509 return MM_ERROR_PLAYER_INTERNAL;
3513 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3515 MMPlayerGstElement *textbin = NULL;
3516 GList *element_bucket = NULL;
3517 int surface_type = 0;
3522 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3525 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3527 LOGE("failed to allocate memory for textbin");
3528 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3532 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3533 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3534 if (!textbin[MMPLAYER_T_BIN].gst) {
3535 LOGE("failed to create textbin");
3540 player->pipeline->textbin = textbin;
3543 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3544 LOGD("surface type for subtitle : %d", surface_type);
3545 switch (surface_type) {
3546 case MM_DISPLAY_SURFACE_OVERLAY:
3547 case MM_DISPLAY_SURFACE_NULL:
3548 case MM_DISPLAY_SURFACE_REMOTE:
3549 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3550 LOGE("failed to make plain text elements");
3561 return MM_ERROR_NONE;
3565 LOGD("ERROR : releasing textbin");
3567 g_list_free(element_bucket);
3569 /* release signal */
3570 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3572 /* release element which are not added to bin */
3573 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3574 /* NOTE : skip bin */
3575 if (textbin[i].gst) {
3576 GstObject *parent = NULL;
3577 parent = gst_element_get_parent(textbin[i].gst);
3580 gst_object_unref(GST_OBJECT(textbin[i].gst));
3581 textbin[i].gst = NULL;
3583 gst_object_unref(GST_OBJECT(parent));
3588 /* release textbin with it's childs */
3589 if (textbin[MMPLAYER_T_BIN].gst)
3590 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3592 MMPLAYER_FREEIF(player->pipeline->textbin);
3593 player->pipeline->textbin = NULL;
3596 return MM_ERROR_PLAYER_INTERNAL;
3600 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3602 MMPlayerGstElement *mainbin = NULL;
3603 MMPlayerGstElement *textbin = NULL;
3604 MMHandleType attrs = 0;
3605 GstElement *subsrc = NULL;
3606 GstElement *subparse = NULL;
3607 gchar *subtitle_uri = NULL;
3608 const gchar *charset = NULL;
3614 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3616 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3618 mainbin = player->pipeline->mainbin;
3620 attrs = MMPLAYER_GET_ATTRS(player);
3622 LOGE("cannot get content attribute");
3623 return MM_ERROR_PLAYER_INTERNAL;
3626 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3627 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3628 LOGE("subtitle uri is not proper filepath.");
3629 return MM_ERROR_PLAYER_INVALID_URI;
3632 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3633 LOGE("failed to get storage info of subtitle path");
3634 return MM_ERROR_PLAYER_INVALID_URI;
3637 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3639 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3640 player->subtitle_language_list = NULL;
3641 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3643 /* create the subtitle source */
3644 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3646 LOGE("failed to create filesrc element");
3649 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3651 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3652 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3654 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3655 LOGW("failed to add queue");
3656 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3657 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3658 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3663 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3665 LOGE("failed to create subparse element");
3669 charset = util_get_charset(subtitle_uri);
3671 LOGD("detected charset is %s", charset);
3672 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3675 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3676 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3678 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3679 LOGW("failed to add subparse");
3680 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3681 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3682 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3686 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3687 LOGW("failed to link subsrc and subparse");
3691 player->play_subtitle = TRUE;
3692 player->adjust_subtitle_pos = 0;
3694 LOGD("play subtitle using subtitle file");
3696 if (player->pipeline->textbin == NULL) {
3697 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3698 LOGE("failed to create text sink bin. continuing without text");
3702 textbin = player->pipeline->textbin;
3704 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3705 LOGW("failed to add textbin");
3707 /* release signal */
3708 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3710 /* release textbin with it's childs */
3711 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3712 MMPLAYER_FREEIF(player->pipeline->textbin);
3713 player->pipeline->textbin = textbin = NULL;
3717 LOGD("link text input selector and textbin ghost pad");
3719 player->textsink_linked = 1;
3720 player->external_text_idx = 0;
3721 LOGI("textsink is linked");
3723 textbin = player->pipeline->textbin;
3724 LOGD("text bin has been created. reuse it.");
3725 player->external_text_idx = 1;
3728 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3729 LOGW("failed to link subparse and textbin");
3733 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3735 LOGE("failed to get sink pad from textsink to probe data");
3739 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3740 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3742 gst_object_unref(pad);
3745 /* create dot. for debugging */
3746 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3749 return MM_ERROR_NONE;
3752 /* release text pipeline resource */
3753 player->textsink_linked = 0;
3755 /* release signal */
3756 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3758 if (player->pipeline->textbin) {
3759 LOGE("remove textbin");
3761 /* release textbin with it's childs */
3762 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3763 MMPLAYER_FREEIF(player->pipeline->textbin);
3764 player->pipeline->textbin = NULL;
3768 /* release subtitle elem */
3769 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3770 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3772 return MM_ERROR_PLAYER_INTERNAL;
3776 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3778 mm_player_t *player = (mm_player_t *)data;
3779 MMMessageParamType msg = {0, };
3780 GstClockTime duration = 0;
3781 gpointer text = NULL;
3782 guint text_size = 0;
3783 gboolean ret = TRUE;
3784 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3788 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3789 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3791 if (player->is_subtitle_force_drop) {
3792 LOGW("subtitle is dropped forcedly.");
3796 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3797 text = mapinfo.data;
3798 text_size = mapinfo.size;
3799 duration = GST_BUFFER_DURATION(buffer);
3801 if (player->set_mode.subtitle_off) {
3802 LOGD("subtitle is OFF.");
3806 if (!text || (text_size == 0)) {
3807 LOGD("There is no subtitle to be displayed.");
3811 msg.data = (void *)text;
3812 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3814 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3816 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3817 gst_buffer_unmap(buffer, &mapinfo);
3824 static GstPadProbeReturn
3825 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3827 mm_player_t *player = (mm_player_t *)u_data;
3828 GstClockTime cur_timestamp = 0;
3829 gint64 adjusted_timestamp = 0;
3830 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3832 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3834 if (player->set_mode.subtitle_off) {
3835 LOGD("subtitle is OFF.");
3839 if (player->adjust_subtitle_pos == 0) {
3840 LOGD("nothing to do");
3844 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3845 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3847 if (adjusted_timestamp < 0) {
3848 LOGD("adjusted_timestamp under zero");
3853 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3854 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3855 GST_TIME_ARGS(cur_timestamp),
3856 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3858 return GST_PAD_PROBE_OK;
3862 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3866 /* check player and subtitlebin are created */
3867 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3868 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3870 if (position == 0) {
3871 LOGD("nothing to do");
3873 return MM_ERROR_NONE;
3877 case MM_PLAYER_POS_FORMAT_TIME:
3879 /* check current postion */
3880 player->adjust_subtitle_pos = position;
3882 LOGD("save adjust_subtitle_pos in player") ;
3888 LOGW("invalid format.");
3890 return MM_ERROR_INVALID_ARGUMENT;
3896 return MM_ERROR_NONE;
3900 * This function is to create audio or video pipeline for playing.
3902 * @param player [in] handle of player
3904 * @return This function returns zero on success.
3909 __mmplayer_gst_create_pipeline(mm_player_t *player)
3911 int ret = MM_ERROR_NONE;
3912 MMPlayerGstElement *mainbin = NULL;
3913 MMHandleType attrs = 0;
3916 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3918 /* get profile attribute */
3919 attrs = MMPLAYER_GET_ATTRS(player);
3921 LOGE("failed to get content attribute");
3925 /* create pipeline handles */
3926 if (player->pipeline) {
3927 LOGE("pipeline should be released before create new one");
3931 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3932 if (player->pipeline == NULL)
3935 /* create mainbin */
3936 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3937 if (mainbin == NULL)
3940 /* create pipeline */
3941 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3942 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3943 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3944 LOGE("failed to create pipeline");
3949 player->pipeline->mainbin = mainbin;
3951 /* create the source and decoder elements */
3952 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3953 ret = __mmplayer_gst_build_es_pipeline(player);
3955 ret = __mmplayer_gst_build_pipeline(player);
3957 if (ret != MM_ERROR_NONE) {
3958 LOGE("failed to create some elements");
3962 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3963 if (__mmplayer_check_subtitle(player)
3964 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3965 LOGE("failed to create text pipeline");
3968 ret = __mmplayer_gst_add_bus_watch(player);
3969 if (ret != MM_ERROR_NONE) {
3970 LOGE("failed to add bus watch");
3975 return MM_ERROR_NONE;
3978 __mmplayer_gst_destroy_pipeline(player);
3979 return MM_ERROR_PLAYER_INTERNAL;
3983 __mmplayer_reset_gapless_state(mm_player_t *player)
3986 MMPLAYER_RETURN_IF_FAIL(player
3988 && player->pipeline->audiobin
3989 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3991 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3998 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4001 int ret = MM_ERROR_NONE;
4005 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4007 /* cleanup stuffs */
4008 MMPLAYER_FREEIF(player->type);
4009 player->no_more_pad = FALSE;
4010 player->num_dynamic_pad = 0;
4011 player->demux_pad_index = 0;
4013 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4014 player->subtitle_language_list = NULL;
4015 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4017 __mmplayer_reset_gapless_state(player);
4019 if (player->streamer) {
4020 __mm_player_streaming_deinitialize(player->streamer);
4021 __mm_player_streaming_destroy(player->streamer);
4022 player->streamer = NULL;
4025 /* cleanup unlinked mime type */
4026 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4027 MMPLAYER_FREEIF(player->unlinked_video_mime);
4028 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4030 /* cleanup running stuffs */
4031 __mmplayer_cancel_eos_timer(player);
4033 /* cleanup gst stuffs */
4034 if (player->pipeline) {
4035 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4036 GstTagList *tag_list = player->pipeline->tag_list;
4038 /* first we need to disconnect all signal hander */
4039 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4042 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4043 MMPlayerGstElement *videobin = player->pipeline->videobin;
4044 MMPlayerGstElement *textbin = player->pipeline->textbin;
4045 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4046 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4047 gst_object_unref(bus);
4049 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4050 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4051 if (ret != MM_ERROR_NONE) {
4052 LOGE("fail to change state to NULL");
4053 return MM_ERROR_PLAYER_INTERNAL;
4056 LOGW("succeeded in changing state to NULL");
4058 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4061 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4062 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4064 /* free avsysaudiosink
4065 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4066 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4068 MMPLAYER_FREEIF(audiobin);
4069 MMPLAYER_FREEIF(videobin);
4070 MMPLAYER_FREEIF(textbin);
4071 MMPLAYER_FREEIF(mainbin);
4075 gst_tag_list_unref(tag_list);
4077 MMPLAYER_FREEIF(player->pipeline);
4079 MMPLAYER_FREEIF(player->album_art);
4081 if (player->v_stream_caps) {
4082 gst_caps_unref(player->v_stream_caps);
4083 player->v_stream_caps = NULL;
4086 if (player->a_stream_caps) {
4087 gst_caps_unref(player->a_stream_caps);
4088 player->a_stream_caps = NULL;
4091 if (player->s_stream_caps) {
4092 gst_caps_unref(player->s_stream_caps);
4093 player->s_stream_caps = NULL;
4095 __mmplayer_track_destroy(player);
4097 if (player->sink_elements)
4098 g_list_free(player->sink_elements);
4099 player->sink_elements = NULL;
4101 if (player->bufmgr) {
4102 tbm_bufmgr_deinit(player->bufmgr);
4103 player->bufmgr = NULL;
4106 LOGW("finished destroy pipeline");
4114 __mmplayer_gst_realize(mm_player_t *player)
4117 int ret = MM_ERROR_NONE;
4121 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4123 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4125 ret = __mmplayer_gst_create_pipeline(player);
4127 LOGE("failed to create pipeline");
4131 /* set pipeline state to READY */
4132 /* NOTE : state change to READY must be performed sync. */
4133 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4134 ret = __mmplayer_gst_set_state(player,
4135 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4137 if (ret != MM_ERROR_NONE) {
4138 /* return error if failed to set state */
4139 LOGE("failed to set READY state");
4143 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4145 /* create dot before error-return. for debugging */
4146 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4154 __mmplayer_gst_unrealize(mm_player_t *player)
4156 int ret = MM_ERROR_NONE;
4160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4162 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4163 MMPLAYER_PRINT_STATE(player);
4165 /* release miscellaneous information */
4166 __mmplayer_release_misc(player);
4168 /* destroy pipeline */
4169 ret = __mmplayer_gst_destroy_pipeline(player);
4170 if (ret != MM_ERROR_NONE) {
4171 LOGE("failed to destory pipeline");
4175 /* release miscellaneous information.
4176 these info needs to be released after pipeline is destroyed. */
4177 __mmplayer_release_misc_post(player);
4179 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4187 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4192 LOGW("set_message_callback is called with invalid player handle");
4193 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4196 player->msg_cb = callback;
4197 player->msg_cb_param = user_param;
4199 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4203 return MM_ERROR_NONE;
4207 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4209 int ret = MM_ERROR_NONE;
4214 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4215 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4216 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4218 memset(data, 0, sizeof(MMPlayerParseProfile));
4220 if (strstr(uri, "es_buff://")) {
4221 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4222 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4223 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4224 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4226 tmp = g_ascii_strdown(uri, strlen(uri));
4227 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4228 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4230 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4232 } else if (strstr(uri, "mms://")) {
4233 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4234 } else if ((path = strstr(uri, "mem://"))) {
4235 ret = __mmplayer_set_mem_uri(data, path, param);
4237 ret = __mmplayer_set_file_uri(data, uri);
4240 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4241 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4242 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4243 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4245 /* dump parse result */
4246 SECURE_LOGW("incoming uri : %s", uri);
4247 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4248 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4256 __mmplayer_can_do_interrupt(mm_player_t *player)
4258 if (!player || !player->pipeline || !player->attrs) {
4259 LOGW("not initialized");
4263 if (player->audio_stream_render_cb) {
4264 LOGW("not support in pcm extraction mode");
4268 /* check if seeking */
4269 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4270 MMMessageParamType msg_param;
4271 memset(&msg_param, 0, sizeof(MMMessageParamType));
4272 msg_param.code = MM_ERROR_PLAYER_SEEK;
4273 player->seek_state = MMPLAYER_SEEK_NONE;
4274 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4278 /* check other thread */
4279 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4280 LOGW("locked already, cmd state : %d", player->cmd);
4282 /* check application command */
4283 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4284 LOGW("playing.. should wait cmd lock then, will be interrupted");
4286 /* lock will be released at mrp_resource_release_cb() */
4287 MMPLAYER_CMD_LOCK(player);
4290 LOGW("nothing to do");
4293 LOGW("can interrupt immediately");
4297 FAILED: /* with CMD UNLOCKED */
4300 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4305 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4308 mm_player_t *player = NULL;
4312 if (user_data == NULL) {
4313 LOGE("- user_data is null");
4316 player = (mm_player_t *)user_data;
4318 /* do something to release resource here.
4319 * player stop and interrupt forwarding */
4320 if (!__mmplayer_can_do_interrupt(player)) {
4321 LOGW("no need to interrupt, so leave");
4323 MMMessageParamType msg = {0, };
4326 player->interrupted_by_resource = TRUE;
4328 /* get last play position */
4329 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4330 LOGW("failed to get play position.");
4332 msg.union_type = MM_MSG_UNION_TIME;
4333 msg.time.elapsed = pos;
4334 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4336 LOGD("video resource conflict so, resource will be freed by unrealizing");
4337 if (_mmplayer_unrealize((MMHandleType)player))
4338 LOGW("failed to unrealize");
4340 /* lock is called in __mmplayer_can_do_interrupt() */
4341 MMPLAYER_CMD_UNLOCK(player);
4344 if (res == player->video_overlay_resource)
4345 player->video_overlay_resource = FALSE;
4347 player->video_decoder_resource = FALSE;
4355 __mmplayer_initialize_video_roi(mm_player_t *player)
4357 player->video_roi.scale_x = 0.0;
4358 player->video_roi.scale_y = 0.0;
4359 player->video_roi.scale_width = 1.0;
4360 player->video_roi.scale_height = 1.0;
4364 _mmplayer_create_player(MMHandleType handle)
4366 int ret = MM_ERROR_PLAYER_INTERNAL;
4367 bool enabled = false;
4369 mm_player_t *player = MM_PLAYER_CAST(handle);
4373 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4375 /* initialize player state */
4376 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4377 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4378 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4379 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4381 /* check current state */
4382 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4384 /* construct attributes */
4385 player->attrs = _mmplayer_construct_attribute(handle);
4387 if (!player->attrs) {
4388 LOGE("Failed to construct attributes");
4392 /* initialize gstreamer with configured parameter */
4393 if (!__mmplayer_init_gstreamer(player)) {
4394 LOGE("Initializing gstreamer failed");
4395 _mmplayer_deconstruct_attribute(handle);
4399 /* create lock. note that g_tread_init() has already called in gst_init() */
4400 g_mutex_init(&player->fsink_lock);
4402 /* create update tag lock */
4403 g_mutex_init(&player->update_tag_lock);
4405 /* create gapless play mutex */
4406 g_mutex_init(&player->gapless_play_thread_mutex);
4408 /* create gapless play cond */
4409 g_cond_init(&player->gapless_play_thread_cond);
4411 /* create gapless play thread */
4412 player->gapless_play_thread =
4413 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4414 if (!player->gapless_play_thread) {
4415 LOGE("failed to create gapless play thread");
4416 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4417 g_mutex_clear(&player->gapless_play_thread_mutex);
4418 g_cond_clear(&player->gapless_play_thread_cond);
4422 player->bus_msg_q = g_queue_new();
4423 if (!player->bus_msg_q) {
4424 LOGE("failed to create queue for bus_msg");
4425 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4429 ret = _mmplayer_initialize_video_capture(player);
4430 if (ret != MM_ERROR_NONE) {
4431 LOGE("failed to initialize video capture");
4435 /* initialize resource manager */
4436 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4437 __resource_release_cb, player, &player->resource_manager)
4438 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4439 LOGE("failed to initialize resource manager");
4440 ret = MM_ERROR_PLAYER_INTERNAL;
4444 /* create video bo lock and cond */
4445 g_mutex_init(&player->video_bo_mutex);
4446 g_cond_init(&player->video_bo_cond);
4448 /* create media stream callback mutex */
4449 g_mutex_init(&player->media_stream_cb_lock);
4451 /* create subtitle info lock and cond */
4452 g_mutex_init(&player->subtitle_info_mutex);
4453 g_cond_init(&player->subtitle_info_cond);
4455 player->streaming_type = STREAMING_SERVICE_NONE;
4457 /* give default value of audio effect setting */
4458 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4459 player->sound.rg_enable = false;
4460 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4462 player->play_subtitle = FALSE;
4463 player->has_closed_caption = FALSE;
4464 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4465 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4466 player->pending_resume = FALSE;
4467 if (player->ini.dump_element_keyword[0][0] == '\0')
4468 player->ini.set_dump_element_flag = FALSE;
4470 player->ini.set_dump_element_flag = TRUE;
4472 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4473 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4474 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4476 /* Set video360 settings to their defaults for just-created player.
4479 player->is_360_feature_enabled = FALSE;
4480 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4481 LOGI("spherical feature info: %d", enabled);
4483 player->is_360_feature_enabled = TRUE;
4485 LOGE("failed to get spherical feature info");
4488 player->is_content_spherical = FALSE;
4489 player->is_video360_enabled = TRUE;
4490 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4491 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4492 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4493 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4494 player->video360_zoom = 1.0f;
4495 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4496 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4498 __mmplayer_initialize_video_roi(player);
4500 /* set player state to null */
4501 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4502 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4506 return MM_ERROR_NONE;
4510 g_mutex_clear(&player->fsink_lock);
4511 /* free update tag lock */
4512 g_mutex_clear(&player->update_tag_lock);
4513 g_queue_free(player->bus_msg_q);
4514 /* free gapless play thread */
4515 if (player->gapless_play_thread) {
4516 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4517 player->gapless_play_thread_exit = TRUE;
4518 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4519 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4521 g_thread_join(player->gapless_play_thread);
4522 player->gapless_play_thread = NULL;
4524 g_mutex_clear(&player->gapless_play_thread_mutex);
4525 g_cond_clear(&player->gapless_play_thread_cond);
4528 /* release attributes */
4529 _mmplayer_deconstruct_attribute(handle);
4537 __mmplayer_init_gstreamer(mm_player_t *player)
4539 static gboolean initialized = FALSE;
4540 static const int max_argc = 50;
4542 gchar **argv = NULL;
4543 gchar **argv2 = NULL;
4549 LOGD("gstreamer already initialized.");
4554 argc = malloc(sizeof(int));
4555 argv = malloc(sizeof(gchar *) * max_argc);
4556 argv2 = malloc(sizeof(gchar *) * max_argc);
4558 if (!argc || !argv || !argv2)
4561 memset(argv, 0, sizeof(gchar *) * max_argc);
4562 memset(argv2, 0, sizeof(gchar *) * max_argc);
4566 argv[0] = g_strdup("mmplayer");
4569 for (i = 0; i < 5; i++) {
4570 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4571 if (strlen(player->ini.gst_param[i]) > 0) {
4572 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4577 /* we would not do fork for scanning plugins */
4578 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4581 /* check disable registry scan */
4582 if (player->ini.skip_rescan) {
4583 argv[*argc] = g_strdup("--gst-disable-registry-update");
4587 /* check disable segtrap */
4588 if (player->ini.disable_segtrap) {
4589 argv[*argc] = g_strdup("--gst-disable-segtrap");
4593 LOGD("initializing gstreamer with following parameter");
4594 LOGD("argc : %d", *argc);
4597 for (i = 0; i < arg_count; i++) {
4599 LOGD("argv[%d] : %s", i, argv2[i]);
4602 /* initializing gstreamer */
4603 if (!gst_init_check(argc, &argv, &err)) {
4604 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4611 for (i = 0; i < arg_count; i++) {
4612 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4613 MMPLAYER_FREEIF(argv2[i]);
4616 MMPLAYER_FREEIF(argv);
4617 MMPLAYER_FREEIF(argv2);
4618 MMPLAYER_FREEIF(argc);
4628 for (i = 0; i < arg_count; i++) {
4629 LOGD("free[%d] : %s", i, argv2[i]);
4630 MMPLAYER_FREEIF(argv2[i]);
4633 MMPLAYER_FREEIF(argv);
4634 MMPLAYER_FREEIF(argv2);
4635 MMPLAYER_FREEIF(argc);
4641 __mmplayer_check_async_state_transition(mm_player_t *player)
4643 GstState element_state = GST_STATE_VOID_PENDING;
4644 GstState element_pending_state = GST_STATE_VOID_PENDING;
4645 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4646 GstElement *element = NULL;
4647 gboolean async = FALSE;
4649 /* check player handle */
4650 MMPLAYER_RETURN_IF_FAIL(player &&
4652 player->pipeline->mainbin &&
4653 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4656 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4658 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4659 LOGD("don't need to check the pipeline state");
4663 MMPLAYER_PRINT_STATE(player);
4665 /* wait for state transition */
4666 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4667 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4669 if (ret == GST_STATE_CHANGE_FAILURE) {
4670 LOGE(" [%s] state : %s pending : %s",
4671 GST_ELEMENT_NAME(element),
4672 gst_element_state_get_name(element_state),
4673 gst_element_state_get_name(element_pending_state));
4675 /* dump state of all element */
4676 __mmplayer_dump_pipeline_state(player);
4681 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4686 _mmplayer_destroy(MMHandleType handle)
4688 mm_player_t *player = MM_PLAYER_CAST(handle);
4692 /* check player handle */
4693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4695 /* destroy can called at anytime */
4696 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4698 /* check async state transition */
4699 __mmplayer_check_async_state_transition(player);
4701 /* release gapless play thread */
4702 if (player->gapless_play_thread) {
4703 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4704 player->gapless_play_thread_exit = TRUE;
4705 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4706 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4708 LOGD("waitting for gapless play thread exit");
4709 g_thread_join(player->gapless_play_thread);
4710 g_mutex_clear(&player->gapless_play_thread_mutex);
4711 g_cond_clear(&player->gapless_play_thread_cond);
4712 LOGD("gapless play thread released");
4715 _mmplayer_release_video_capture(player);
4717 /* de-initialize resource manager */
4718 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4719 player->resource_manager))
4720 LOGE("failed to deinitialize resource manager");
4722 /* release pipeline */
4723 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4724 LOGE("failed to destory pipeline");
4725 return MM_ERROR_PLAYER_INTERNAL;
4728 g_queue_free(player->bus_msg_q);
4730 /* release subtitle info lock and cond */
4731 g_mutex_clear(&player->subtitle_info_mutex);
4732 g_cond_clear(&player->subtitle_info_cond);
4734 __mmplayer_release_dump_list(player->dump_list);
4736 /* release miscellaneous information */
4737 __mmplayer_release_misc(player);
4739 /* release miscellaneous information.
4740 these info needs to be released after pipeline is destroyed. */
4741 __mmplayer_release_misc_post(player);
4743 /* release attributes */
4744 _mmplayer_deconstruct_attribute(handle);
4747 g_mutex_clear(&player->fsink_lock);
4750 g_mutex_clear(&player->update_tag_lock);
4752 /* release video bo lock and cond */
4753 g_mutex_clear(&player->video_bo_mutex);
4754 g_cond_clear(&player->video_bo_cond);
4756 /* release media stream callback lock */
4757 g_mutex_clear(&player->media_stream_cb_lock);
4761 return MM_ERROR_NONE;
4765 _mmplayer_realize(MMHandleType hplayer)
4767 mm_player_t *player = (mm_player_t *)hplayer;
4770 MMHandleType attrs = 0;
4771 int ret = MM_ERROR_NONE;
4775 /* check player handle */
4776 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4778 /* check current state */
4779 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4781 attrs = MMPLAYER_GET_ATTRS(player);
4783 LOGE("fail to get attributes.");
4784 return MM_ERROR_PLAYER_INTERNAL;
4786 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4787 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4789 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4790 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4792 if (ret != MM_ERROR_NONE) {
4793 LOGE("failed to parse profile");
4798 if (uri && (strstr(uri, "es_buff://"))) {
4799 if (strstr(uri, "es_buff://push_mode"))
4800 player->es_player_push_mode = TRUE;
4802 player->es_player_push_mode = FALSE;
4805 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4806 LOGW("mms protocol is not supported format.");
4807 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4810 if (MMPLAYER_IS_STREAMING(player))
4811 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4813 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4815 player->smooth_streaming = FALSE;
4816 player->videodec_linked = 0;
4817 player->audiodec_linked = 0;
4818 player->textsink_linked = 0;
4819 player->is_external_subtitle_present = FALSE;
4820 player->is_external_subtitle_added_now = FALSE;
4821 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4822 player->video360_metadata.is_spherical = -1;
4823 player->is_openal_plugin_used = FALSE;
4824 player->demux_pad_index = 0;
4825 player->subtitle_language_list = NULL;
4826 player->is_subtitle_force_drop = FALSE;
4827 player->last_multiwin_status = FALSE;
4829 __mmplayer_track_initialize(player);
4830 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4832 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4833 player->streamer = __mm_player_streaming_create();
4834 __mm_player_streaming_initialize(player->streamer);
4837 /* realize pipeline */
4838 ret = __mmplayer_gst_realize(player);
4839 if (ret != MM_ERROR_NONE)
4840 LOGE("fail to realize the player.");
4842 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4850 _mmplayer_unrealize(MMHandleType hplayer)
4852 mm_player_t *player = (mm_player_t *)hplayer;
4853 int ret = MM_ERROR_NONE;
4857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4859 MMPLAYER_CMD_UNLOCK(player);
4860 /* destroy the gst bus msg thread which is created during realize.
4861 this funct have to be called before getting cmd lock. */
4862 __mmplayer_bus_msg_thread_destroy(player);
4863 MMPLAYER_CMD_LOCK(player);
4865 /* check current state */
4866 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4868 /* check async state transition */
4869 __mmplayer_check_async_state_transition(player);
4871 /* unrealize pipeline */
4872 ret = __mmplayer_gst_unrealize(player);
4874 /* set asm stop if success */
4875 if (MM_ERROR_NONE == ret) {
4876 if (!player->interrupted_by_resource) {
4877 if (player->video_decoder_resource != NULL) {
4878 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4879 player->video_decoder_resource);
4880 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4881 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4883 player->video_decoder_resource = NULL;
4886 if (player->video_overlay_resource != NULL) {
4887 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4888 player->video_overlay_resource);
4889 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4890 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4892 player->video_overlay_resource = NULL;
4895 ret = mm_resource_manager_commit(player->resource_manager);
4896 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4897 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4900 LOGE("failed and don't change asm state to stop");
4908 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4910 mm_player_t *player = (mm_player_t *)hplayer;
4912 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4914 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4918 _mmplayer_get_state(MMHandleType hplayer, int *state)
4920 mm_player_t *player = (mm_player_t *)hplayer;
4922 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4924 *state = MMPLAYER_CURRENT_STATE(player);
4926 return MM_ERROR_NONE;
4931 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4933 mm_player_t *player = (mm_player_t *)hplayer;
4934 GstElement *vol_element = NULL;
4939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4941 LOGD("volume [L]=%f:[R]=%f",
4942 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4944 /* invalid factor range or not */
4945 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4946 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4947 LOGE("Invalid factor!(valid factor:0~1.0)");
4948 return MM_ERROR_INVALID_ARGUMENT;
4952 /* not support to set other value into each channel */
4953 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4954 return MM_ERROR_INVALID_ARGUMENT;
4956 /* Save volume to handle. Currently the first array element will be saved. */
4957 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4959 /* check pipeline handle */
4960 if (!player->pipeline || !player->pipeline->audiobin) {
4961 LOGD("audiobin is not created yet");
4962 LOGD("but, current stored volume will be set when it's created.");
4964 /* NOTE : stored volume will be used in create_audiobin
4965 * returning MM_ERROR_NONE here makes application to able to
4966 * set volume at anytime.
4968 return MM_ERROR_NONE;
4971 /* setting volume to volume element */
4972 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4975 LOGD("volume is set [%f]", player->sound.volume);
4976 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4981 return MM_ERROR_NONE;
4985 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
4987 mm_player_t *player = (mm_player_t *)hplayer;
4992 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4993 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
4995 /* returning stored volume */
4996 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
4997 volume->level[i] = player->sound.volume;
5001 return MM_ERROR_NONE;
5005 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5007 mm_player_t *player = (mm_player_t *)hplayer;
5008 GstElement *vol_element = NULL;
5012 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5014 /* mute value shoud 0 or 1 */
5015 if (mute != 0 && mute != 1) {
5016 LOGE("bad mute value");
5018 /* FIXIT : definitly, we need _BAD_PARAM error code */
5019 return MM_ERROR_INVALID_ARGUMENT;
5022 player->sound.mute = mute;
5024 /* just hold mute value if pipeline is not ready */
5025 if (!player->pipeline || !player->pipeline->audiobin) {
5026 LOGD("pipeline is not ready. holding mute value");
5027 return MM_ERROR_NONE;
5030 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5032 /* NOTE : volume will only created when the bt is enabled */
5034 LOGD("mute : %d", mute);
5035 g_object_set(vol_element, "mute", mute, NULL);
5037 LOGD("volume elemnet is not created. using volume in audiosink");
5041 return MM_ERROR_NONE;
5045 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5047 mm_player_t *player = (mm_player_t *)hplayer;
5051 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5052 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5054 /* just hold mute value if pipeline is not ready */
5055 if (!player->pipeline || !player->pipeline->audiobin) {
5056 LOGD("pipeline is not ready. returning stored value");
5057 *pmute = player->sound.mute;
5058 return MM_ERROR_NONE;
5061 *pmute = player->sound.mute;
5065 return MM_ERROR_NONE;
5069 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5071 mm_player_t *player = (mm_player_t *)hplayer;
5075 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5077 player->video_stream_changed_cb = callback;
5078 player->video_stream_changed_cb_user_param = user_param;
5079 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5083 return MM_ERROR_NONE;
5087 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5089 mm_player_t *player = (mm_player_t *)hplayer;
5093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5095 player->audio_stream_changed_cb = callback;
5096 player->audio_stream_changed_cb_user_param = user_param;
5097 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5101 return MM_ERROR_NONE;
5105 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5107 mm_player_t *player = (mm_player_t *)hplayer;
5111 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5113 player->audio_stream_render_cb = callback;
5114 player->audio_stream_cb_user_param = user_param;
5115 player->audio_stream_sink_sync = sync;
5116 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5120 return MM_ERROR_NONE;
5124 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5126 mm_player_t *player = (mm_player_t *)hplayer;
5130 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5132 if (callback && !player->bufmgr)
5133 player->bufmgr = tbm_bufmgr_init(-1);
5135 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5136 player->video_stream_cb = callback;
5137 player->video_stream_cb_user_param = user_param;
5139 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5143 return MM_ERROR_NONE;
5147 _mmplayer_start(MMHandleType hplayer)
5149 mm_player_t *player = (mm_player_t *)hplayer;
5150 gint ret = MM_ERROR_NONE;
5154 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5156 /* check current state */
5157 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5159 /* start pipeline */
5160 ret = __mmplayer_gst_start(player);
5161 if (ret != MM_ERROR_NONE)
5162 LOGE("failed to start player.");
5164 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5165 LOGD("force playing start even during buffering");
5166 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5174 /* NOTE: post "not supported codec message" to application
5175 * when one codec is not found during AUTOPLUGGING in MSL.
5176 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5177 * And, if any codec is not found, don't send message here.
5178 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5181 __mmplayer_handle_missed_plugin(mm_player_t *player)
5183 MMMessageParamType msg_param;
5184 memset(&msg_param, 0, sizeof(MMMessageParamType));
5185 gboolean post_msg_direct = FALSE;
5189 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5191 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5192 player->not_supported_codec, player->can_support_codec);
5194 if (player->not_found_demuxer) {
5195 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5196 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5198 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5199 MMPLAYER_FREEIF(msg_param.data);
5201 return MM_ERROR_NONE;
5204 if (player->not_supported_codec) {
5205 if (player->can_support_codec) {
5206 // There is one codec to play
5207 post_msg_direct = TRUE;
5209 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5210 post_msg_direct = TRUE;
5213 if (post_msg_direct) {
5214 MMMessageParamType msg_param;
5215 memset(&msg_param, 0, sizeof(MMMessageParamType));
5217 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5218 LOGW("not found AUDIO codec, posting error code to application.");
5220 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5221 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5222 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5223 LOGW("not found VIDEO codec, posting error code to application.");
5225 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5226 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5229 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5231 MMPLAYER_FREEIF(msg_param.data);
5233 return MM_ERROR_NONE;
5235 // no any supported codec case
5236 LOGW("not found any codec, posting error code to application.");
5238 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5239 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5240 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5242 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5243 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5246 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5248 MMPLAYER_FREEIF(msg_param.data);
5254 return MM_ERROR_NONE;
5258 __mmplayer_check_pipeline(mm_player_t *player)
5260 GstState element_state = GST_STATE_VOID_PENDING;
5261 GstState element_pending_state = GST_STATE_VOID_PENDING;
5263 int ret = MM_ERROR_NONE;
5265 if (!player->gapless.reconfigure)
5268 LOGW("pipeline is under construction.");
5270 MMPLAYER_PLAYBACK_LOCK(player);
5271 MMPLAYER_PLAYBACK_UNLOCK(player);
5273 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5275 /* wait for state transition */
5276 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5277 if (ret == GST_STATE_CHANGE_FAILURE)
5278 LOGE("failed to change pipeline state within %d sec", timeout);
5281 /* NOTE : it should be able to call 'stop' anytime*/
5283 _mmplayer_stop(MMHandleType hplayer)
5285 mm_player_t *player = (mm_player_t *)hplayer;
5286 int ret = MM_ERROR_NONE;
5290 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5292 /* check current state */
5293 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5295 /* check pipline building state */
5296 __mmplayer_check_pipeline(player);
5297 __mmplayer_reset_gapless_state(player);
5299 /* NOTE : application should not wait for EOS after calling STOP */
5300 __mmplayer_cancel_eos_timer(player);
5303 player->seek_state = MMPLAYER_SEEK_NONE;
5306 ret = __mmplayer_gst_stop(player);
5308 if (ret != MM_ERROR_NONE)
5309 LOGE("failed to stop player.");
5317 _mmplayer_pause(MMHandleType hplayer)
5319 mm_player_t *player = (mm_player_t *)hplayer;
5320 gint64 pos_nsec = 0;
5321 gboolean async = FALSE;
5322 gint ret = MM_ERROR_NONE;
5326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5328 /* check current state */
5329 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5331 /* check pipline building state */
5332 __mmplayer_check_pipeline(player);
5334 switch (MMPLAYER_CURRENT_STATE(player)) {
5335 case MM_PLAYER_STATE_READY:
5337 /* check prepare async or not.
5338 * In the case of streaming playback, it's recommned to avoid blocking wait.
5340 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5341 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5343 /* Changing back sync of rtspsrc to async */
5344 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5345 LOGD("async prepare working mode for rtsp");
5351 case MM_PLAYER_STATE_PLAYING:
5353 /* NOTE : store current point to overcome some bad operation
5354 *(returning zero when getting current position in paused state) of some
5357 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5358 LOGW("getting current position failed in paused");
5360 player->last_position = pos_nsec;
5362 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5363 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5364 This causes problem is position calculation during normal pause resume scenarios also.
5365 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5366 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5367 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5368 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5374 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5375 LOGD("doing async pause in case of ms buff src");
5379 /* pause pipeline */
5380 ret = __mmplayer_gst_pause(player, async);
5382 if (ret != MM_ERROR_NONE)
5383 LOGE("failed to pause player. ret : 0x%x", ret);
5385 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5386 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5387 LOGE("failed to update display_rotation");
5395 /* in case of streaming, pause could take long time.*/
5397 _mmplayer_abort_pause(MMHandleType hplayer)
5399 mm_player_t *player = (mm_player_t *)hplayer;
5400 int ret = MM_ERROR_NONE;
5404 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5406 player->pipeline->mainbin,
5407 MM_ERROR_PLAYER_NOT_INITIALIZED);
5409 LOGD("set the pipeline state to READY");
5411 /* set state to READY */
5412 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5413 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5414 if (ret != MM_ERROR_NONE) {
5415 LOGE("fail to change state to READY");
5416 return MM_ERROR_PLAYER_INTERNAL;
5419 LOGD("succeeded in changing state to READY");
5424 _mmplayer_resume(MMHandleType hplayer)
5426 mm_player_t *player = (mm_player_t *)hplayer;
5427 int ret = MM_ERROR_NONE;
5428 gboolean async = FALSE;
5432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5434 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5435 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5436 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5440 /* Changing back sync mode rtspsrc to async */
5441 LOGD("async resume for rtsp case");
5445 /* check current state */
5446 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5448 ret = __mmplayer_gst_resume(player, async);
5449 if (ret != MM_ERROR_NONE)
5450 LOGE("failed to resume player.");
5452 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5453 LOGD("force resume even during buffering");
5454 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5463 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5465 mm_player_t *player = (mm_player_t *)hplayer;
5466 gint64 pos_nsec = 0;
5467 int ret = MM_ERROR_NONE;
5469 signed long long start = 0, stop = 0;
5470 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5473 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5474 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5476 /* The sound of video is not supported under 0.0 and over 2.0. */
5477 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5478 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5481 _mmplayer_set_mute(hplayer, mute);
5483 if (player->playback_rate == rate)
5484 return MM_ERROR_NONE;
5486 /* If the position is reached at start potion during fast backward, EOS is posted.
5487 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5489 player->playback_rate = rate;
5491 current_state = MMPLAYER_CURRENT_STATE(player);
5493 if (current_state != MM_PLAYER_STATE_PAUSED)
5494 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5496 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5498 if ((current_state == MM_PLAYER_STATE_PAUSED)
5499 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5500 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5501 pos_nsec = player->last_position;
5506 stop = GST_CLOCK_TIME_NONE;
5508 start = GST_CLOCK_TIME_NONE;
5512 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5513 player->playback_rate,
5515 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5516 GST_SEEK_TYPE_SET, start,
5517 GST_SEEK_TYPE_SET, stop)) {
5518 LOGE("failed to set speed playback");
5519 return MM_ERROR_PLAYER_SEEK;
5522 LOGD("succeeded to set speed playback as %0.1f", rate);
5526 return MM_ERROR_NONE;;
5530 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5532 mm_player_t *player = (mm_player_t *)hplayer;
5533 int ret = MM_ERROR_NONE;
5537 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5539 /* check pipline building state */
5540 __mmplayer_check_pipeline(player);
5542 ret = __mmplayer_gst_set_position(player, position, FALSE);
5550 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5552 mm_player_t *player = (mm_player_t *)hplayer;
5553 int ret = MM_ERROR_NONE;
5555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5557 ret = __mmplayer_gst_get_position(player, position);
5563 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5565 mm_player_t *player = (mm_player_t *)hplayer;
5566 int ret = MM_ERROR_NONE;
5568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5569 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5571 *duration = player->duration;
5576 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5578 mm_player_t *player = (mm_player_t *)hplayer;
5579 int ret = MM_ERROR_NONE;
5581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5583 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5589 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5591 mm_player_t *player = (mm_player_t *)hplayer;
5592 int ret = MM_ERROR_NONE;
5596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5598 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5606 __mmplayer_is_midi_type(gchar *str_caps)
5608 if ((g_strrstr(str_caps, "audio/midi")) ||
5609 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5610 (g_strrstr(str_caps, "application/x-smaf")) ||
5611 (g_strrstr(str_caps, "audio/x-imelody")) ||
5612 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5613 (g_strrstr(str_caps, "audio/xmf")) ||
5614 (g_strrstr(str_caps, "audio/mxmf"))) {
5623 __mmplayer_is_only_mp3_type(gchar *str_caps)
5625 if (g_strrstr(str_caps, "application/x-id3") ||
5626 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5632 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5634 GstStructure *caps_structure = NULL;
5635 gint samplerate = 0;
5639 MMPLAYER_RETURN_IF_FAIL(player && caps);
5641 caps_structure = gst_caps_get_structure(caps, 0);
5643 /* set stream information */
5644 gst_structure_get_int(caps_structure, "rate", &samplerate);
5645 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5647 gst_structure_get_int(caps_structure, "channels", &channels);
5648 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5650 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5654 __mmplayer_update_content_type_info(mm_player_t *player)
5657 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5659 if (__mmplayer_is_midi_type(player->type)) {
5660 player->bypass_audio_effect = TRUE;
5661 } else if (g_strrstr(player->type, "application/x-hls")) {
5662 /* If it can't know exact type when it parses uri because of redirection case,
5663 * it will be fixed by typefinder or when doing autoplugging.
5665 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5666 if (player->streamer) {
5667 player->streamer->is_adaptive_streaming = TRUE;
5668 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5669 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5671 } else if (g_strrstr(player->type, "application/dash+xml")) {
5672 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5673 if (player->streamer) {
5674 player->streamer->is_adaptive_streaming = TRUE;
5675 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5679 LOGD("uri type : %d", player->profile.uri_type);
5684 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5685 GstCaps *caps, gpointer data)
5687 mm_player_t *player = (mm_player_t *)data;
5692 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5694 /* store type string */
5695 MMPLAYER_FREEIF(player->type);
5696 player->type = gst_caps_to_string(caps);
5698 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5699 player, player->type, probability, gst_caps_get_size(caps));
5701 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5702 (g_strrstr(player->type, "audio/x-raw-int"))) {
5703 LOGE("not support media format");
5705 if (player->msg_posted == FALSE) {
5706 MMMessageParamType msg_param;
5707 memset(&msg_param, 0, sizeof(MMMessageParamType));
5709 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5710 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5712 /* don't post more if one was sent already */
5713 player->msg_posted = TRUE;
5718 __mmplayer_update_content_type_info(player);
5720 pad = gst_element_get_static_pad(tf, "src");
5722 LOGE("fail to get typefind src pad.");
5726 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5727 gboolean async = FALSE;
5728 LOGE("failed to autoplug %s", player->type);
5730 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5732 if (async && player->msg_posted == FALSE)
5733 __mmplayer_handle_missed_plugin(player);
5739 gst_object_unref(GST_OBJECT(pad));
5747 __mmplayer_gst_make_decodebin(mm_player_t *player)
5749 GstElement *decodebin = NULL;
5753 /* create decodebin */
5754 decodebin = gst_element_factory_make("decodebin", NULL);
5757 LOGE("fail to create decodebin");
5761 /* raw pad handling signal */
5762 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5763 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5765 /* no-more-pad pad handling signal */
5766 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5767 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5769 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5770 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5772 /* This signal is emitted when a pad for which there is no further possible
5773 decoding is added to the decodebin.*/
5774 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5775 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5777 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5778 before looking for any elements that can handle that stream.*/
5779 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5780 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5782 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5783 before looking for any elements that can handle that stream.*/
5784 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5785 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5787 /* This signal is emitted once decodebin has finished decoding all the data.*/
5788 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5789 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5791 /* This signal is emitted when a element is added to the bin.*/
5792 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5793 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5800 __mmplayer_gst_make_queue2(mm_player_t *player)
5802 GstElement *queue2 = NULL;
5803 gint64 dur_bytes = 0L;
5804 guint max_buffer_size_bytes = 0;
5805 MMPlayerGstElement *mainbin = NULL;
5806 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5811 mainbin = player->pipeline->mainbin;
5813 queue2 = gst_element_factory_make("queue2", "queue2");
5815 LOGE("failed to create buffering queue element");
5819 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5820 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5822 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5824 if (dur_bytes > 0) {
5825 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5826 type = MUXED_BUFFER_TYPE_FILE;
5828 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5829 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5835 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5836 * skip the pull mode(file or ring buffering) setting. */
5837 if (!g_strrstr(player->type, "video/mpegts")) {
5838 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5 * 1024 * 1024);
5839 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5841 __mm_player_streaming_set_queue2(player->streamer,
5844 max_buffer_size_bytes,
5845 player->ini.http_buffering_time,
5847 player->http_file_buffering_path,
5848 (guint64)dur_bytes);
5855 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5857 MMPlayerGstElement *mainbin = NULL;
5858 GstElement *decodebin = NULL;
5859 GstElement *queue2 = NULL;
5860 GstPad *sinkpad = NULL;
5861 GstPad *qsrcpad = NULL;
5862 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5865 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5867 mainbin = player->pipeline->mainbin;
5869 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5871 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5872 LOGW("need to check: muxed buffer is not null");
5875 queue2 = __mmplayer_gst_make_queue2(player);
5877 LOGE("failed to make queue2");
5881 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5882 LOGE("failed to add buffering queue");
5886 sinkpad = gst_element_get_static_pad(queue2, "sink");
5887 qsrcpad = gst_element_get_static_pad(queue2, "src");
5889 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5890 LOGE("failed to link [%s:%s]-[%s:%s]",
5891 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5895 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5896 LOGE("failed to sync queue2 state with parent");
5900 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5901 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5905 gst_object_unref(GST_OBJECT(sinkpad));
5909 /* create decodebin */
5910 decodebin = __mmplayer_gst_make_decodebin(player);
5912 LOGE("failed to make decodebin");
5916 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5917 LOGE("failed to add decodebin");
5921 /* to force caps on the decodebin element and avoid reparsing stuff by
5922 * typefind. It also avoids a deadlock in the way typefind activates pads in
5923 * the state change */
5924 g_object_set(decodebin, "sink-caps", caps, NULL);
5926 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5928 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5929 LOGE("failed to link [%s:%s]-[%s:%s]",
5930 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5934 gst_object_unref(GST_OBJECT(sinkpad));
5937 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5938 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5940 /* set decodebin property about buffer in streaming playback. *
5941 * in case of HLS/DASH, it does not need to have big buffer *
5942 * because it is kind of adaptive streaming. */
5943 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5944 gdouble high_percent = 0.0;
5946 init_buffering_time = (init_buffering_time != 0) ? init_buffering_time : player->ini.http_buffering_time;
5947 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
5949 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
5950 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
5952 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5953 "high-percent", (gint)high_percent,
5954 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
5955 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
5956 "max-size-buffers", 0, NULL); // disable or automatic
5959 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
5960 LOGE("failed to sync decodebin state with parent");
5971 gst_object_unref(GST_OBJECT(sinkpad));
5974 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5975 * You need to explicitly set elements to the NULL state before
5976 * dropping the final reference, to allow them to clean up.
5978 gst_element_set_state(queue2, GST_STATE_NULL);
5980 /* And, it still has a parent "player".
5981 * You need to let the parent manage the object instead of unreffing the object directly.
5983 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
5984 gst_object_unref(queue2);
5989 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5990 * You need to explicitly set elements to the NULL state before
5991 * dropping the final reference, to allow them to clean up.
5993 gst_element_set_state(decodebin, GST_STATE_NULL);
5995 /* And, it still has a parent "player".
5996 * You need to let the parent manage the object instead of unreffing the object directly.
5999 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6000 gst_object_unref(decodebin);
6008 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6012 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6013 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6015 LOGD("class : %s, mime : %s", factory_class, mime);
6017 /* add missing plugin */
6018 /* NOTE : msl should check missing plugin for image mime type.
6019 * Some motion jpeg clips can have playable audio track.
6020 * So, msl have to play audio after displaying popup written video format not supported.
6022 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6023 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6024 LOGD("not found demuxer");
6025 player->not_found_demuxer = TRUE;
6026 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6032 if (!g_strrstr(factory_class, "Demuxer")) {
6033 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6034 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6035 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6037 /* check that clip have multi tracks or not */
6038 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6039 LOGD("video plugin is already linked");
6041 LOGW("add VIDEO to missing plugin");
6042 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6043 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6045 } else if (g_str_has_prefix(mime, "audio")) {
6046 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6047 LOGD("audio plugin is already linked");
6049 LOGW("add AUDIO to missing plugin");
6050 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6051 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6059 return MM_ERROR_NONE;
6063 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6065 mm_player_t *player = (mm_player_t *)data;
6069 MMPLAYER_RETURN_IF_FAIL(player);
6071 /* remove fakesink. */
6072 if (!__mmplayer_gst_remove_fakesink(player,
6073 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6074 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6075 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6076 * source element are not same. To overcome this situation, this function will called
6077 * several places and several times. Therefore, this is not an error case.
6082 LOGD("[handle: %p] pipeline has completely constructed", player);
6084 if ((player->ini.async_start) &&
6085 (player->msg_posted == FALSE) &&
6086 (player->cmd >= MMPLAYER_COMMAND_START))
6087 __mmplayer_handle_missed_plugin(player);
6089 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6093 __mmplayer_check_profile(void)
6096 static int profile_tv = -1;
6098 if (__builtin_expect(profile_tv != -1, 1))
6101 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6102 switch (*profileName) {
6117 __mmplayer_get_next_uri(mm_player_t *player)
6119 MMPlayerParseProfile profile;
6121 guint num_of_list = 0;
6124 num_of_list = g_list_length(player->uri_info.uri_list);
6125 uri_idx = player->uri_info.uri_idx;
6127 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6128 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6129 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6131 LOGW("next uri does not exist");
6135 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6136 LOGE("failed to parse profile");
6140 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6141 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6142 LOGW("uri type is not supported(%d)", profile.uri_type);
6146 LOGD("success to find next uri %d", uri_idx);
6150 if (uri_idx == num_of_list) {
6151 LOGE("failed to find next uri");
6155 player->uri_info.uri_idx = uri_idx;
6156 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6158 if (mm_attrs_commit_all(player->attrs)) {
6159 LOGE("failed to commit");
6163 SECURE_LOGD("next playback uri: %s", uri);
6168 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6170 #define REPEAT_COUNT_INFINITELY -1
6171 #define REPEAT_COUNT_MIN 2
6173 MMHandleType attrs = 0;
6177 guint num_of_list = 0;
6178 int profile_tv = -1;
6182 LOGD("checking for gapless play option");
6184 if (player->pipeline->textbin) {
6185 LOGE("subtitle path is enabled. gapless play is not supported.");
6189 attrs = MMPLAYER_GET_ATTRS(player);
6191 LOGE("fail to get attributes.");
6195 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6197 /* gapless playback is not supported in case of video at TV profile. */
6198 profile_tv = __mmplayer_check_profile();
6199 if (profile_tv && video) {
6200 LOGW("not support video gapless playback");
6204 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6205 LOGE("failed to get play count");
6207 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6208 LOGE("failed to get gapless mode");
6210 /* check repeat count in case of audio */
6212 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6213 LOGW("gapless is disabled");
6217 num_of_list = g_list_length(player->uri_info.uri_list);
6219 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6221 if (num_of_list == 0) {
6222 /* audio looping path */
6223 if (count >= REPEAT_COUNT_MIN) {
6224 /* decrease play count */
6225 /* we succeeded to rewind. update play count and then wait for next EOS */
6227 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6228 /* commit attribute */
6229 if (mm_attrs_commit_all(attrs))
6230 LOGE("failed to commit attribute");
6232 } else if (count != REPEAT_COUNT_INFINITELY) {
6233 LOGD("there is no next uri and no repeat");
6236 LOGD("looping cnt %d", count);
6238 /* gapless playback path */
6239 if (!__mmplayer_get_next_uri(player)) {
6240 LOGE("failed to get next uri");
6247 LOGE("unable to play gapless path. EOS will be posted soon");
6252 __mmplayer_initialize_gapless_play(mm_player_t *player)
6258 player->smooth_streaming = FALSE;
6259 player->videodec_linked = 0;
6260 player->audiodec_linked = 0;
6261 player->textsink_linked = 0;
6262 player->is_external_subtitle_present = FALSE;
6263 player->is_external_subtitle_added_now = FALSE;
6264 player->not_supported_codec = MISSING_PLUGIN_NONE;
6265 player->can_support_codec = FOUND_PLUGIN_NONE;
6266 player->pending_seek.is_pending = false;
6267 player->pending_seek.pos = 0;
6268 player->msg_posted = FALSE;
6269 player->has_many_types = FALSE;
6270 player->no_more_pad = FALSE;
6271 player->not_found_demuxer = 0;
6272 player->seek_state = MMPLAYER_SEEK_NONE;
6273 player->is_subtitle_force_drop = FALSE;
6274 player->play_subtitle = FALSE;
6275 player->adjust_subtitle_pos = 0;
6277 player->total_bitrate = 0;
6278 player->total_maximum_bitrate = 0;
6280 __mmplayer_track_initialize(player);
6281 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6283 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6284 player->bitrate[i] = 0;
6285 player->maximum_bitrate[i] = 0;
6288 if (player->v_stream_caps) {
6289 gst_caps_unref(player->v_stream_caps);
6290 player->v_stream_caps = NULL;
6293 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6295 /* clean found parsers */
6296 if (player->parsers) {
6297 GList *parsers = player->parsers;
6298 for (; parsers; parsers = g_list_next(parsers)) {
6299 gchar *name = parsers->data;
6300 MMPLAYER_FREEIF(name);
6302 g_list_free(player->parsers);
6303 player->parsers = NULL;
6306 /* clean found audio decoders */
6307 if (player->audio_decoders) {
6308 GList *a_dec = player->audio_decoders;
6309 for (; a_dec; a_dec = g_list_next(a_dec)) {
6310 gchar *name = a_dec->data;
6311 MMPLAYER_FREEIF(name);
6313 g_list_free(player->audio_decoders);
6314 player->audio_decoders = NULL;
6321 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6323 MMPlayerGstElement *mainbin = NULL;
6324 MMMessageParamType msg_param = {0,};
6325 GstElement *element = NULL;
6326 MMHandleType attrs = 0;
6328 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6332 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6333 LOGE("player is not initialized");
6337 mainbin = player->pipeline->mainbin;
6338 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6340 attrs = MMPLAYER_GET_ATTRS(player);
6342 LOGE("fail to get attributes");
6346 /* Initialize Player values */
6347 __mmplayer_initialize_gapless_play(player);
6349 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6351 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6352 LOGE("failed to parse profile");
6353 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6357 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6358 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6359 LOGE("dash or hls is not supportable");
6360 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6364 element = __mmplayer_gst_create_source(player);
6366 LOGE("no source element was created");
6370 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6371 LOGE("failed to add source element to pipeline");
6372 gst_object_unref(GST_OBJECT(element));
6377 /* take source element */
6378 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6379 mainbin[MMPLAYER_M_SRC].gst = element;
6383 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6384 if (player->streamer == NULL) {
6385 player->streamer = __mm_player_streaming_create();
6386 __mm_player_streaming_initialize(player->streamer);
6389 elem_idx = MMPLAYER_M_TYPEFIND;
6390 element = gst_element_factory_make("typefind", "typefinder");
6391 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6392 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6394 elem_idx = MMPLAYER_M_AUTOPLUG;
6395 element = __mmplayer_gst_make_decodebin(player);
6398 /* check autoplug element is OK */
6400 LOGE("can not create element(%d)", elem_idx);
6404 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6405 LOGE("failed to add sinkbin to pipeline");
6406 gst_object_unref(GST_OBJECT(element));
6411 mainbin[elem_idx].id = elem_idx;
6412 mainbin[elem_idx].gst = element;
6414 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6415 LOGE("Failed to link src - autoplug(or typefind)");
6419 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6420 LOGE("Failed to change state of src element");
6424 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6425 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6426 LOGE("Failed to change state of decodebin");
6430 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6431 LOGE("Failed to change state of src element");
6436 player->gapless.stream_changed = TRUE;
6437 player->gapless.running = TRUE;
6443 MMPLAYER_PLAYBACK_UNLOCK(player);
6445 if (!player->msg_posted) {
6446 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6447 player->msg_posted = TRUE;
6454 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6456 mm_player_selector_t *selector = &player->selector[type];
6457 MMPlayerGstElement *sinkbin = NULL;
6458 enum MainElementID selectorId = MMPLAYER_M_NUM;
6459 enum MainElementID sinkId = MMPLAYER_M_NUM;
6460 GstPad *srcpad = NULL;
6461 GstPad *sinkpad = NULL;
6462 gboolean send_notice = FALSE;
6465 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6467 LOGD("type %d", type);
6470 case MM_PLAYER_TRACK_TYPE_AUDIO:
6471 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6472 sinkId = MMPLAYER_A_BIN;
6473 sinkbin = player->pipeline->audiobin;
6475 case MM_PLAYER_TRACK_TYPE_VIDEO:
6476 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6477 sinkId = MMPLAYER_V_BIN;
6478 sinkbin = player->pipeline->videobin;
6481 case MM_PLAYER_TRACK_TYPE_TEXT:
6482 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6483 sinkId = MMPLAYER_T_BIN;
6484 sinkbin = player->pipeline->textbin;
6487 LOGE("requested type is not supportable");
6492 if (player->pipeline->mainbin[selectorId].gst) {
6495 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6497 if (selector->event_probe_id != 0)
6498 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6499 selector->event_probe_id = 0;
6501 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6502 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6504 if (srcpad && sinkpad) {
6505 /* after getting drained signal there is no data flows, so no need to do pad_block */
6506 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6507 gst_pad_unlink(srcpad, sinkpad);
6509 /* send custom event to sink pad to handle it at video sink */
6511 LOGD("send custom event to sinkpad");
6512 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6513 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6514 gst_pad_send_event(sinkpad, event);
6518 gst_object_unref(sinkpad);
6521 gst_object_unref(srcpad);
6524 LOGD("selector release");
6526 /* release and unref requests pad from the selector */
6527 for (n = 0; n < selector->channels->len; n++) {
6528 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6529 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6531 g_ptr_array_set_size(selector->channels, 0);
6533 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6534 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6536 player->pipeline->mainbin[selectorId].gst = NULL;
6544 __mmplayer_deactivate_old_path(mm_player_t *player)
6547 MMPLAYER_RETURN_IF_FAIL(player);
6549 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6550 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6551 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6552 LOGE("deactivate selector error");
6556 __mmplayer_track_destroy(player);
6557 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6559 if (player->streamer) {
6560 __mm_player_streaming_deinitialize(player->streamer);
6561 __mm_player_streaming_destroy(player->streamer);
6562 player->streamer = NULL;
6565 MMPLAYER_PLAYBACK_LOCK(player);
6566 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6573 if (!player->msg_posted) {
6574 MMMessageParamType msg = {0,};
6577 msg.code = MM_ERROR_PLAYER_INTERNAL;
6578 LOGE("gapless_uri_play> deactivate error");
6580 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6581 player->msg_posted = TRUE;
6587 _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char *file_path)
6589 int result = MM_ERROR_NONE;
6590 mm_player_t *player = (mm_player_t *)hplayer;
6593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6596 player->http_file_buffering_path = (gchar *)file_path;
6597 LOGD("temp file path: %s", player->http_file_buffering_path);
6604 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6606 int result = MM_ERROR_NONE;
6607 mm_player_t *player = (mm_player_t *)hplayer;
6610 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6612 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6613 if (mm_attrs_commit_all(player->attrs)) {
6614 LOGE("failed to commit the original uri.");
6615 result = MM_ERROR_PLAYER_INTERNAL;
6617 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6618 LOGE("failed to add the original uri in the uri list.");
6626 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6628 mm_player_t *player = (mm_player_t *)hplayer;
6629 guint num_of_list = 0;
6633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6634 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6636 if (player->pipeline && player->pipeline->textbin) {
6637 LOGE("subtitle path is enabled.");
6638 return MM_ERROR_PLAYER_INVALID_STATE;
6641 num_of_list = g_list_length(player->uri_info.uri_list);
6643 if (is_first_path) {
6644 if (num_of_list == 0) {
6645 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6646 LOGD("add original path : %s", uri);
6648 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6649 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6651 LOGD("change original path : %s", uri);
6654 MMHandleType attrs = 0;
6655 attrs = MMPLAYER_GET_ATTRS(player);
6657 if (num_of_list == 0) {
6658 char *original_uri = NULL;
6661 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6663 if (!original_uri) {
6664 LOGE("there is no original uri.");
6665 return MM_ERROR_PLAYER_INVALID_STATE;
6668 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6669 player->uri_info.uri_idx = 0;
6671 LOGD("add original path at first : %s", original_uri);
6675 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6676 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6680 return MM_ERROR_NONE;
6684 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6686 mm_player_t *player = (mm_player_t *)hplayer;
6687 char *next_uri = NULL;
6688 guint num_of_list = 0;
6691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6693 num_of_list = g_list_length(player->uri_info.uri_list);
6695 if (num_of_list > 0) {
6696 gint uri_idx = player->uri_info.uri_idx;
6698 if (uri_idx < num_of_list-1)
6703 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6704 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6706 *uri = g_strdup(next_uri);
6710 return MM_ERROR_NONE;
6714 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6715 GstCaps *caps, gpointer data)
6717 mm_player_t *player = (mm_player_t *)data;
6718 const gchar *klass = NULL;
6719 const gchar *mime = NULL;
6720 gchar *caps_str = NULL;
6722 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6723 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6724 caps_str = gst_caps_to_string(caps);
6726 LOGW("unknown type of caps : %s from %s",
6727 caps_str, GST_ELEMENT_NAME(elem));
6729 MMPLAYER_FREEIF(caps_str);
6731 /* There is no available codec. */
6732 __mmplayer_check_not_supported_codec(player, klass, mime);
6736 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6737 GstCaps *caps, gpointer data)
6739 mm_player_t *player = (mm_player_t *)data;
6740 const char *mime = NULL;
6741 gboolean ret = TRUE;
6743 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6744 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6746 if (g_str_has_prefix(mime, "audio")) {
6747 GstStructure *caps_structure = NULL;
6748 gint samplerate = 0;
6750 gchar *caps_str = NULL;
6752 caps_structure = gst_caps_get_structure(caps, 0);
6753 gst_structure_get_int(caps_structure, "rate", &samplerate);
6754 gst_structure_get_int(caps_structure, "channels", &channels);
6756 if ((channels > 0 && samplerate == 0)) {
6757 LOGD("exclude audio...");
6761 caps_str = gst_caps_to_string(caps);
6762 /* set it directly because not sent by TAG */
6763 if (g_strrstr(caps_str, "mobile-xmf"))
6764 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6765 MMPLAYER_FREEIF(caps_str);
6766 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6767 MMMessageParamType msg_param;
6768 memset(&msg_param, 0, sizeof(MMMessageParamType));
6769 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6770 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6771 LOGD("video file is not supported on this device");
6773 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6774 LOGD("already video linked");
6777 LOGD("found new stream");
6784 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6786 int ret = MM_ERROR_NONE;
6788 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6790 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6791 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6793 LOGD("audio codec type: %d", codec_type);
6794 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6795 /* sw codec will be skipped */
6796 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6797 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6798 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6799 ret = MM_ERROR_PLAYER_INTERNAL;
6803 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6804 /* hw codec will be skipped */
6805 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6806 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6807 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6808 ret = MM_ERROR_PLAYER_INTERNAL;
6813 /* set stream information */
6814 if (!player->audiodec_linked)
6815 __mmplayer_set_audio_attrs(player, caps);
6817 /* update codec info */
6818 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6819 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6820 player->audiodec_linked = 1;
6822 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6824 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6826 LOGD("video codec type: %d", codec_type);
6827 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6828 /* sw codec is skipped */
6829 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6830 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6831 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6832 ret = MM_ERROR_PLAYER_INTERNAL;
6836 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6837 /* hw codec is skipped */
6838 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6839 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6840 ret = MM_ERROR_PLAYER_INTERNAL;
6845 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6846 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6848 /* mark video decoder for acquire */
6849 if (player->video_decoder_resource == NULL) {
6850 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6851 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6852 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6853 &player->video_decoder_resource)
6854 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6855 LOGE("could not mark video_decoder resource for acquire");
6856 ret = MM_ERROR_PLAYER_INTERNAL;
6860 LOGW("video decoder resource is already acquired, skip it.");
6861 ret = MM_ERROR_PLAYER_INTERNAL;
6865 player->interrupted_by_resource = FALSE;
6866 /* acquire resources for video playing */
6867 if (mm_resource_manager_commit(player->resource_manager)
6868 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6869 LOGE("could not acquire resources for video decoding");
6870 ret = MM_ERROR_PLAYER_INTERNAL;
6875 /* update codec info */
6876 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6877 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6878 player->videodec_linked = 1;
6886 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6887 GstCaps *caps, GstElementFactory *factory, gpointer data)
6889 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
6890 We are defining our own and will be removed when it actually exposed */
6892 GST_AUTOPLUG_SELECT_TRY,
6893 GST_AUTOPLUG_SELECT_EXPOSE,
6894 GST_AUTOPLUG_SELECT_SKIP
6895 } GstAutoplugSelectResult;
6897 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6898 mm_player_t *player = (mm_player_t *)data;
6900 gchar *factory_name = NULL;
6901 gchar *caps_str = NULL;
6902 const gchar *klass = NULL;
6905 factory_name = GST_OBJECT_NAME(factory);
6906 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6907 caps_str = gst_caps_to_string(caps);
6909 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6911 /* store type string */
6912 if (player->type == NULL) {
6913 player->type = gst_caps_to_string(caps);
6914 __mmplayer_update_content_type_info(player);
6917 /* filtering exclude keyword */
6918 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6919 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6920 LOGW("skipping [%s] by exculde keyword [%s]",
6921 factory_name, player->ini.exclude_element_keyword[idx]);
6923 result = GST_AUTOPLUG_SELECT_SKIP;
6928 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6929 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6930 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6931 factory_name, player->ini.unsupported_codec_keyword[idx]);
6932 result = GST_AUTOPLUG_SELECT_SKIP;
6937 /* exclude webm format */
6938 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6939 * because webm format is not supportable.
6940 * If webm is disabled in "autoplug-continue", there is no state change
6941 * failure or error because the decodebin will expose the pad directly.
6942 * It make MSL invoke _prepare_async_callback.
6943 * So, we need to disable webm format in "autoplug-select" */
6944 if (caps_str && strstr(caps_str, "webm")) {
6945 LOGW("webm is not supported");
6946 result = GST_AUTOPLUG_SELECT_SKIP;
6950 /* check factory class for filtering */
6951 /* NOTE : msl don't need to use image plugins.
6952 * So, those plugins should be skipped for error handling.
6954 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6955 LOGD("skipping [%s] by not required", factory_name);
6956 result = GST_AUTOPLUG_SELECT_SKIP;
6960 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
6961 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
6962 // TO CHECK : subtitle if needed, add subparse exception.
6963 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
6964 result = GST_AUTOPLUG_SELECT_SKIP;
6968 if (g_strrstr(factory_name, "mpegpsdemux")) {
6969 LOGD("skipping PS container - not support");
6970 result = GST_AUTOPLUG_SELECT_SKIP;
6974 if (g_strrstr(factory_name, "mssdemux"))
6975 player->smooth_streaming = TRUE;
6977 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
6978 (g_strrstr(klass, "Codec/Decoder/Video"))) {
6981 GstStructure *str = NULL;
6982 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
6984 /* don't make video because of not required */
6985 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
6986 (!player->set_mode.media_packet_video_stream)) {
6987 LOGD("no need video decoding, expose pad");
6988 result = GST_AUTOPLUG_SELECT_EXPOSE;
6992 /* get w/h for omx state-tune */
6993 /* FIXME: deprecated? */
6994 str = gst_caps_get_structure(caps, 0);
6995 gst_structure_get_int(str, "width", &width);
6998 if (player->v_stream_caps) {
6999 gst_caps_unref(player->v_stream_caps);
7000 player->v_stream_caps = NULL;
7003 player->v_stream_caps = gst_caps_copy(caps);
7004 LOGD("take caps for video state tune");
7005 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7009 if (g_strrstr(klass, "Codec/Decoder")) {
7010 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7011 LOGD("skipping %s codec", factory_name);
7012 result = GST_AUTOPLUG_SELECT_SKIP;
7018 MMPLAYER_FREEIF(caps_str);
7024 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7027 //mm_player_t *player = (mm_player_t *)data;
7028 GstCaps *caps = NULL;
7030 LOGD("[Decodebin2] pad-removed signal");
7032 caps = gst_pad_query_caps(new_pad, NULL);
7034 LOGW("query caps is NULL");
7038 gchar *caps_str = NULL;
7039 caps_str = gst_caps_to_string(caps);
7041 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7043 MMPLAYER_FREEIF(caps_str);
7044 gst_caps_unref(caps);
7048 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7050 mm_player_t *player = (mm_player_t *)data;
7051 GstIterator *iter = NULL;
7052 GValue item = { 0, };
7054 gboolean done = FALSE;
7055 gboolean is_all_drained = TRUE;
7058 MMPLAYER_RETURN_IF_FAIL(player);
7060 LOGD("__mmplayer_gst_decode_drained");
7062 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7063 LOGW("Fail to get cmd lock");
7067 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7068 !__mmplayer_verify_gapless_play_path(player)) {
7069 LOGD("decoding is finished.");
7070 __mmplayer_reset_gapless_state(player);
7071 MMPLAYER_CMD_UNLOCK(player);
7075 player->gapless.reconfigure = TRUE;
7077 /* check decodebin src pads whether they received EOS or not */
7078 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7081 switch (gst_iterator_next(iter, &item)) {
7082 case GST_ITERATOR_OK:
7083 pad = g_value_get_object(&item);
7084 if (pad && !GST_PAD_IS_EOS(pad)) {
7085 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7086 is_all_drained = FALSE;
7089 g_value_reset(&item);
7091 case GST_ITERATOR_RESYNC:
7092 gst_iterator_resync(iter);
7094 case GST_ITERATOR_ERROR:
7095 case GST_ITERATOR_DONE:
7100 g_value_unset(&item);
7101 gst_iterator_free(iter);
7103 if (!is_all_drained) {
7104 LOGD("Wait util the all pads get EOS.");
7105 MMPLAYER_CMD_UNLOCK(player);
7110 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7111 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7113 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7114 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7115 __mmplayer_deactivate_old_path(player);
7116 MMPLAYER_CMD_UNLOCK(player);
7122 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7124 mm_player_t *player = (mm_player_t *)data;
7125 const gchar *klass = NULL;
7126 gchar *factory_name = NULL;
7128 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7129 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7131 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7133 if (__mmplayer_add_dump_buffer_probe(player, element))
7134 LOGD("add buffer probe");
7137 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7138 gchar *selected = NULL;
7139 selected = g_strdup(GST_ELEMENT_NAME(element));
7140 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7144 if (g_strrstr(klass, "Parser")) {
7145 gchar *selected = NULL;
7147 selected = g_strdup(factory_name);
7148 player->parsers = g_list_append(player->parsers, selected);
7151 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7152 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7153 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7155 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7156 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7158 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7159 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7160 "max-video-width", player->adaptive_info.limit.width,
7161 "max-video-height", player->adaptive_info.limit.height, NULL);
7163 } else if (g_strrstr(klass, "Demuxer")) {
7164 //LOGD("plugged element is demuxer. take it");
7165 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7166 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7169 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7170 int surface_type = 0;
7172 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7175 // to support trust-zone only
7176 if (g_strrstr(factory_name, "asfdemux")) {
7177 LOGD("set file-location %s", player->profile.uri);
7178 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7179 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7180 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7181 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7182 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7183 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7184 (__mmplayer_is_only_mp3_type(player->type))) {
7185 LOGD("[mpegaudioparse] set streaming pull mode.");
7186 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7188 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7189 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7192 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7193 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7194 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7196 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7197 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7199 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7200 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7201 (MMPLAYER_IS_DASH_STREAMING(player))) {
7202 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7203 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time);
7204 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7213 __mmplayer_release_misc(mm_player_t *player)
7216 bool cur_mode = player->set_mode.rich_audio;
7219 MMPLAYER_RETURN_IF_FAIL(player);
7221 player->video_stream_cb = NULL;
7222 player->video_stream_cb_user_param = NULL;
7223 player->video_stream_prerolled = false;
7225 player->audio_stream_render_cb = NULL;
7226 player->audio_stream_cb_user_param = NULL;
7227 player->audio_stream_sink_sync = false;
7229 player->video_stream_changed_cb = NULL;
7230 player->video_stream_changed_cb_user_param = NULL;
7232 player->audio_stream_changed_cb = NULL;
7233 player->audio_stream_changed_cb_user_param = NULL;
7235 player->sent_bos = FALSE;
7236 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7238 player->seek_state = MMPLAYER_SEEK_NONE;
7240 player->total_bitrate = 0;
7241 player->total_maximum_bitrate = 0;
7243 player->not_found_demuxer = 0;
7245 player->last_position = 0;
7246 player->duration = 0;
7247 player->http_content_size = 0;
7248 player->not_supported_codec = MISSING_PLUGIN_NONE;
7249 player->can_support_codec = FOUND_PLUGIN_NONE;
7250 player->pending_seek.is_pending = false;
7251 player->pending_seek.pos = 0;
7252 player->msg_posted = FALSE;
7253 player->has_many_types = FALSE;
7254 player->is_subtitle_force_drop = FALSE;
7255 player->play_subtitle = FALSE;
7256 player->adjust_subtitle_pos = 0;
7257 player->last_multiwin_status = FALSE;
7258 player->has_closed_caption = FALSE;
7259 player->set_mode.media_packet_video_stream = false;
7260 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7261 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7263 player->set_mode.rich_audio = cur_mode;
7265 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7266 player->bitrate[i] = 0;
7267 player->maximum_bitrate[i] = 0;
7270 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7272 /* remove media stream cb(appsrc cb) */
7273 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7274 player->media_stream_buffer_status_cb[i] = NULL;
7275 player->media_stream_seek_data_cb[i] = NULL;
7276 player->buffer_cb_user_param[i] = NULL;
7277 player->seek_cb_user_param[i] = NULL;
7279 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7281 /* free memory related to audio effect */
7282 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7284 if (player->adaptive_info.var_list) {
7285 g_list_free_full(player->adaptive_info.var_list, g_free);
7286 player->adaptive_info.var_list = NULL;
7289 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7290 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7291 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7293 /* Reset video360 settings to their defaults in case if the pipeline is to be
7296 player->video360_metadata.is_spherical = -1;
7297 player->is_openal_plugin_used = FALSE;
7299 player->is_content_spherical = FALSE;
7300 player->is_video360_enabled = TRUE;
7301 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7302 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7303 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7304 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7305 player->video360_zoom = 1.0f;
7306 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7307 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7309 player->sound.rg_enable = false;
7311 __mmplayer_initialize_video_roi(player);
7316 __mmplayer_release_misc_post(mm_player_t *player)
7318 char *original_uri = NULL;
7321 /* player->pipeline is already released before. */
7323 MMPLAYER_RETURN_IF_FAIL(player);
7325 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7327 /* clean found parsers */
7328 if (player->parsers) {
7329 GList *parsers = player->parsers;
7330 for (; parsers; parsers = g_list_next(parsers)) {
7331 gchar *name = parsers->data;
7332 MMPLAYER_FREEIF(name);
7334 g_list_free(player->parsers);
7335 player->parsers = NULL;
7338 /* clean found audio decoders */
7339 if (player->audio_decoders) {
7340 GList *a_dec = player->audio_decoders;
7341 for (; a_dec; a_dec = g_list_next(a_dec)) {
7342 gchar *name = a_dec->data;
7343 MMPLAYER_FREEIF(name);
7345 g_list_free(player->audio_decoders);
7346 player->audio_decoders = NULL;
7349 /* clean the uri list except original uri */
7350 if (player->uri_info.uri_list) {
7351 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7353 if (player->attrs) {
7354 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7355 LOGD("restore original uri = %s", original_uri);
7357 if (mm_attrs_commit_all(player->attrs))
7358 LOGE("failed to commit the original uri.");
7361 GList *uri_list = player->uri_info.uri_list;
7362 for (; uri_list; uri_list = g_list_next(uri_list)) {
7363 gchar *uri = uri_list->data;
7364 MMPLAYER_FREEIF(uri);
7366 g_list_free(player->uri_info.uri_list);
7367 player->uri_info.uri_list = NULL;
7370 /* clear the audio stream buffer list */
7371 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7373 /* clear the video stream bo list */
7374 __mmplayer_video_stream_destroy_bo_list(player);
7375 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7377 if (player->profile.input_mem.buf) {
7378 free(player->profile.input_mem.buf);
7379 player->profile.input_mem.buf = NULL;
7381 player->profile.input_mem.len = 0;
7382 player->profile.input_mem.offset = 0;
7384 player->uri_info.uri_idx = 0;
7389 __mmplayer_check_subtitle(mm_player_t *player)
7391 MMHandleType attrs = 0;
7392 char *subtitle_uri = NULL;
7396 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7398 /* get subtitle attribute */
7399 attrs = MMPLAYER_GET_ATTRS(player);
7403 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7404 if (!subtitle_uri || !strlen(subtitle_uri))
7407 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7408 player->is_external_subtitle_present = TRUE;
7416 __mmplayer_cancel_eos_timer(mm_player_t *player)
7418 MMPLAYER_RETURN_IF_FAIL(player);
7420 if (player->eos_timer) {
7421 LOGD("cancel eos timer");
7422 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7423 player->eos_timer = 0;
7430 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7434 MMPLAYER_RETURN_IF_FAIL(player);
7435 MMPLAYER_RETURN_IF_FAIL(sink);
7437 player->sink_elements = g_list_append(player->sink_elements, sink);
7443 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7447 MMPLAYER_RETURN_IF_FAIL(player);
7448 MMPLAYER_RETURN_IF_FAIL(sink);
7450 player->sink_elements = g_list_remove(player->sink_elements, sink);
7456 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7457 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7459 MMPlayerSignalItem *item = NULL;
7462 MMPLAYER_RETURN_IF_FAIL(player);
7464 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7465 LOGE("invalid signal type [%d]", type);
7469 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7471 LOGE("cannot connect signal [%s]", signal);
7476 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7477 player->signals[type] = g_list_append(player->signals[type], item);
7483 /* NOTE : be careful with calling this api. please refer to below glib comment
7484 * glib comment : Note that there is a bug in GObject that makes this function much
7485 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7486 * will no longer be called, but, the signal handler is not currently disconnected.
7487 * If the instance is itself being freed at the same time than this doesn't matter,
7488 * since the signal will automatically be removed, but if instance persists,
7489 * then the signal handler will leak. You should not remove the signal yourself
7490 * because in a future versions of GObject, the handler will automatically be
7493 * It's possible to work around this problem in a way that will continue to work
7494 * with future versions of GObject by checking that the signal handler is still
7495 * connected before disconnected it:
7497 * if (g_signal_handler_is_connected(instance, id))
7498 * g_signal_handler_disconnect(instance, id);
7501 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7503 GList *sig_list = NULL;
7504 MMPlayerSignalItem *item = NULL;
7508 MMPLAYER_RETURN_IF_FAIL(player);
7510 LOGD("release signals type : %d", type);
7512 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7513 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7514 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7515 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7516 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7517 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7521 sig_list = player->signals[type];
7523 for (; sig_list; sig_list = sig_list->next) {
7524 item = sig_list->data;
7526 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7527 if (g_signal_handler_is_connected(item->obj, item->sig))
7528 g_signal_handler_disconnect(item->obj, item->sig);
7531 MMPLAYER_FREEIF(item);
7534 g_list_free(player->signals[type]);
7535 player->signals[type] = NULL;
7543 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7545 mm_player_t *player = 0;
7546 int prev_display_surface_type = 0;
7547 void *prev_display_overlay = NULL;
7551 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7552 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7554 player = MM_PLAYER_CAST(handle);
7556 /* check video sinkbin is created */
7557 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7558 LOGE("Videosink is already created");
7559 return MM_ERROR_NONE;
7562 LOGD("videosink element is not yet ready");
7564 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7565 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7567 return MM_ERROR_INVALID_ARGUMENT;
7570 /* load previous attributes */
7571 if (player->attrs) {
7572 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7573 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7574 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7575 if (prev_display_surface_type == surface_type) {
7576 LOGD("incoming display surface type is same as previous one, do nothing..");
7578 return MM_ERROR_NONE;
7581 LOGE("failed to load attributes");
7583 return MM_ERROR_PLAYER_INTERNAL;
7586 /* videobin is not created yet, so we just set attributes related to display surface */
7587 LOGD("store display attribute for given surface type(%d)", surface_type);
7588 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7589 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7590 if (mm_attrs_commit_all(player->attrs)) {
7591 LOGE("failed to commit attribute");
7593 return MM_ERROR_PLAYER_INTERNAL;
7597 return MM_ERROR_NONE;
7600 /* Note : if silent is true, then subtitle would not be displayed. :*/
7602 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7604 mm_player_t *player = (mm_player_t *)hplayer;
7608 /* check player handle */
7609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7611 player->set_mode.subtitle_off = silent;
7613 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7617 return MM_ERROR_NONE;
7621 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7623 MMPlayerGstElement *mainbin = NULL;
7624 MMPlayerGstElement *textbin = NULL;
7625 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7626 GstState current_state = GST_STATE_VOID_PENDING;
7627 GstState element_state = GST_STATE_VOID_PENDING;
7628 GstState element_pending_state = GST_STATE_VOID_PENDING;
7630 GstEvent *event = NULL;
7631 int result = MM_ERROR_NONE;
7633 GstClock *curr_clock = NULL;
7634 GstClockTime base_time, start_time, curr_time;
7639 /* check player handle */
7640 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7642 player->pipeline->mainbin &&
7643 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7645 mainbin = player->pipeline->mainbin;
7646 textbin = player->pipeline->textbin;
7648 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7650 // sync clock with current pipeline
7651 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7652 curr_time = gst_clock_get_time(curr_clock);
7654 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7655 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7657 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7658 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7660 if (current_state > GST_STATE_READY) {
7661 // sync state with current pipeline
7662 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7663 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7664 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7666 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7667 if (GST_STATE_CHANGE_FAILURE == ret) {
7668 LOGE("fail to state change.");
7669 result = MM_ERROR_PLAYER_INTERNAL;
7673 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7674 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7677 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7678 gst_object_unref(curr_clock);
7681 // seek to current position
7682 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7683 result = MM_ERROR_PLAYER_INVALID_STATE;
7684 LOGE("gst_element_query_position failed, invalid state");
7688 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7689 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);
7691 __mmplayer_gst_send_event_to_sink(player, event);
7693 result = MM_ERROR_PLAYER_INTERNAL;
7694 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7698 /* sync state with current pipeline */
7699 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7700 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7701 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7703 return MM_ERROR_NONE;
7706 /* release text pipeline resource */
7707 player->textsink_linked = 0;
7709 /* release signal */
7710 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7712 /* release textbin with it's childs */
7713 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7714 MMPLAYER_FREEIF(player->pipeline->textbin);
7715 player->pipeline->textbin = NULL;
7717 /* release subtitle elem */
7718 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7719 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7725 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7727 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7728 GstState current_state = GST_STATE_VOID_PENDING;
7730 MMHandleType attrs = 0;
7731 MMPlayerGstElement *mainbin = NULL;
7732 MMPlayerGstElement *textbin = NULL;
7734 gchar *subtitle_uri = NULL;
7735 int result = MM_ERROR_NONE;
7736 const gchar *charset = NULL;
7740 /* check player handle */
7741 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7743 player->pipeline->mainbin &&
7744 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7745 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7747 mainbin = player->pipeline->mainbin;
7748 textbin = player->pipeline->textbin;
7750 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7751 if (current_state < GST_STATE_READY) {
7752 result = MM_ERROR_PLAYER_INVALID_STATE;
7753 LOGE("Pipeline is not in proper state");
7757 attrs = MMPLAYER_GET_ATTRS(player);
7759 LOGE("cannot get content attribute");
7760 result = MM_ERROR_PLAYER_INTERNAL;
7764 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7765 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7766 LOGE("subtitle uri is not proper filepath");
7767 result = MM_ERROR_PLAYER_INVALID_URI;
7771 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7772 LOGE("failed to get storage info of subtitle path");
7773 result = MM_ERROR_PLAYER_INVALID_URI;
7777 LOGD("old subtitle file path is [%s]", subtitle_uri);
7778 LOGD("new subtitle file path is [%s]", filepath);
7780 if (!strcmp(filepath, subtitle_uri)) {
7781 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7784 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7785 if (mm_attrs_commit_all(player->attrs)) {
7786 LOGE("failed to commit.");
7791 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7792 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7793 player->subtitle_language_list = NULL;
7794 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7796 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7797 if (ret != GST_STATE_CHANGE_SUCCESS) {
7798 LOGE("failed to change state of textbin to READY");
7799 result = MM_ERROR_PLAYER_INTERNAL;
7803 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7804 if (ret != GST_STATE_CHANGE_SUCCESS) {
7805 LOGE("failed to change state of subparse to READY");
7806 result = MM_ERROR_PLAYER_INTERNAL;
7810 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7811 if (ret != GST_STATE_CHANGE_SUCCESS) {
7812 LOGE("failed to change state of filesrc to READY");
7813 result = MM_ERROR_PLAYER_INTERNAL;
7817 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7819 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7821 charset = util_get_charset(filepath);
7823 LOGD("detected charset is %s", charset);
7824 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7827 result = _mmplayer_sync_subtitle_pipeline(player);
7834 /* API to switch between external subtitles */
7836 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7838 int result = MM_ERROR_NONE;
7839 mm_player_t *player = (mm_player_t *)hplayer;
7844 /* check player handle */
7845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7847 /* filepath can be null in idle state */
7849 /* check file path */
7850 if ((path = strstr(filepath, "file://")))
7851 result = util_exist_file_path(path + 7);
7853 result = util_exist_file_path(filepath);
7855 if (result != MM_ERROR_NONE) {
7856 LOGE("invalid subtitle path 0x%X", result);
7857 return result; /* file not found or permission denied */
7861 if (!player->pipeline) {
7863 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7864 if (mm_attrs_commit_all(player->attrs)) {
7865 LOGE("failed to commit"); /* subtitle path will not be created */
7866 return MM_ERROR_PLAYER_INTERNAL;
7869 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7870 /* check filepath */
7871 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7873 if (!__mmplayer_check_subtitle(player)) {
7874 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7875 if (mm_attrs_commit_all(player->attrs)) {
7876 LOGE("failed to commit");
7877 return MM_ERROR_PLAYER_INTERNAL;
7880 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7881 LOGE("fail to create text pipeline");
7882 return MM_ERROR_PLAYER_INTERNAL;
7885 result = _mmplayer_sync_subtitle_pipeline(player);
7887 result = __mmplayer_change_external_subtitle_language(player, filepath);
7890 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7891 player->is_external_subtitle_added_now = TRUE;
7893 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7894 if (!player->subtitle_language_list) {
7895 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7896 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7897 LOGW("subtitle language list is not updated yet");
7899 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7907 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7909 int result = MM_ERROR_NONE;
7910 gchar *change_pad_name = NULL;
7911 GstPad *sinkpad = NULL;
7912 MMPlayerGstElement *mainbin = NULL;
7913 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7914 GstCaps *caps = NULL;
7915 gint total_track_num = 0;
7919 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7920 MM_ERROR_PLAYER_NOT_INITIALIZED);
7922 LOGD("Change Track(%d) to %d", type, index);
7924 mainbin = player->pipeline->mainbin;
7926 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7927 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7928 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7929 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7931 /* Changing Video Track is not supported. */
7932 LOGE("Track Type Error");
7936 if (mainbin[elem_idx].gst == NULL) {
7937 result = MM_ERROR_PLAYER_NO_OP;
7938 LOGD("Req track doesn't exist");
7942 total_track_num = player->selector[type].total_track_num;
7943 if (total_track_num <= 0) {
7944 result = MM_ERROR_PLAYER_NO_OP;
7945 LOGD("Language list is not available");
7949 if ((index < 0) || (index >= total_track_num)) {
7950 result = MM_ERROR_INVALID_ARGUMENT;
7951 LOGD("Not a proper index : %d", index);
7955 /*To get the new pad from the selector*/
7956 change_pad_name = g_strdup_printf("sink_%u", index);
7957 if (change_pad_name == NULL) {
7958 result = MM_ERROR_PLAYER_INTERNAL;
7959 LOGD("Pad does not exists");
7963 LOGD("new active pad name: %s", change_pad_name);
7965 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
7966 if (sinkpad == NULL) {
7967 LOGD("sinkpad is NULL");
7968 result = MM_ERROR_PLAYER_INTERNAL;
7972 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
7973 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
7975 caps = gst_pad_get_current_caps(sinkpad);
7976 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
7979 gst_object_unref(sinkpad);
7981 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
7982 __mmplayer_set_audio_attrs(player, caps);
7985 MMPLAYER_FREEIF(change_pad_name);
7990 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
7992 int result = MM_ERROR_NONE;
7993 mm_player_t *player = NULL;
7994 MMPlayerGstElement *mainbin = NULL;
7996 gint current_active_index = 0;
7998 GstState current_state = GST_STATE_VOID_PENDING;
7999 GstEvent *event = NULL;
8004 player = (mm_player_t *)hplayer;
8005 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8007 if (!player->pipeline) {
8008 LOGE("Track %d pre setting -> %d", type, index);
8010 player->selector[type].active_pad_index = index;
8014 mainbin = player->pipeline->mainbin;
8016 current_active_index = player->selector[type].active_pad_index;
8018 /*If index is same as running index no need to change the pad*/
8019 if (current_active_index == index)
8022 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8023 result = MM_ERROR_PLAYER_INVALID_STATE;
8027 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8028 if (current_state < GST_STATE_PAUSED) {
8029 result = MM_ERROR_PLAYER_INVALID_STATE;
8030 LOGW("Pipeline not in porper state");
8034 result = __mmplayer_change_selector_pad(player, type, index);
8035 if (result != MM_ERROR_NONE) {
8036 LOGE("change selector pad error");
8040 player->selector[type].active_pad_index = index;
8042 if (current_state == GST_STATE_PLAYING) {
8043 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8044 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8045 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8047 __mmplayer_gst_send_event_to_sink(player, event);
8049 result = MM_ERROR_PLAYER_INTERNAL;
8059 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8061 mm_player_t *player = (mm_player_t *)hplayer;
8065 /* check player handle */
8066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8068 *silent = player->set_mode.subtitle_off;
8070 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8074 return MM_ERROR_NONE;
8078 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8080 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8081 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8083 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8084 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8088 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8089 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8090 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8091 mm_player_dump_t *dump_s;
8092 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8093 if (dump_s == NULL) {
8094 LOGE("malloc fail");
8098 dump_s->dump_element_file = NULL;
8099 dump_s->dump_pad = NULL;
8100 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8102 if (dump_s->dump_pad) {
8103 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8104 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]);
8105 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8106 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);
8107 /* add list for removed buffer probe and close FILE */
8108 player->dump_list = g_list_append(player->dump_list, dump_s);
8109 LOGD("%s sink pad added buffer probe for dump", factory_name);
8112 MMPLAYER_FREEIF(dump_s);
8113 LOGE("failed to get %s sink pad added", factory_name);
8120 static GstPadProbeReturn
8121 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8123 FILE *dump_data = (FILE *)u_data;
8125 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8126 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8128 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8130 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8132 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8134 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8136 return GST_PAD_PROBE_OK;
8140 __mmplayer_release_dump_list(GList *dump_list)
8142 GList *d_list = dump_list;
8147 for (; d_list; d_list = g_list_next(d_list)) {
8148 mm_player_dump_t *dump_s = d_list->data;
8149 if (dump_s->dump_pad) {
8150 if (dump_s->probe_handle_id)
8151 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8153 if (dump_s->dump_element_file) {
8154 fclose(dump_s->dump_element_file);
8155 dump_s->dump_element_file = NULL;
8157 MMPLAYER_FREEIF(dump_s);
8159 g_list_free(dump_list);
8164 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8166 mm_player_t *player = (mm_player_t *)hplayer;
8170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8171 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8173 *exist = (bool)player->has_closed_caption;
8177 return MM_ERROR_NONE;
8181 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8185 // LOGD("unref internal gst buffer %p", buffer);
8186 gst_buffer_unref((GstBuffer *)buffer);
8193 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8195 mm_player_t *player = (mm_player_t *)hplayer;
8199 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8200 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8202 if (MMPLAYER_IS_STREAMING(player))
8203 *timeout = (int)player->ini.live_state_change_timeout;
8205 *timeout = (int)player->ini.localplayback_state_change_timeout;
8207 LOGD("timeout = %d", *timeout);
8210 return MM_ERROR_NONE;
8214 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8216 mm_player_t *player = (mm_player_t *)hplayer;
8220 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8221 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8223 *num = player->video_num_buffers;
8224 *extra_num = player->video_extra_num_buffers;
8226 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8229 return MM_ERROR_NONE;
8233 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8237 MMPLAYER_RETURN_IF_FAIL(player);
8239 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8241 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8242 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8243 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8244 player->storage_info[i].id = -1;
8245 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8247 if (path_type != MMPLAYER_PATH_MAX)
8256 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8258 int ret = MM_ERROR_NONE;
8259 mm_player_t *player = (mm_player_t *)hplayer;
8260 MMMessageParamType msg_param = {0, };
8263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8265 LOGW("state changed storage %d:%d", id, state);
8267 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8268 return MM_ERROR_NONE;
8270 /* FIXME: text path should be handled seperately. */
8271 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8272 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8273 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8274 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8275 LOGW("external storage is removed");
8277 if (player->msg_posted == FALSE) {
8278 memset(&msg_param, 0, sizeof(MMMessageParamType));
8279 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8280 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8281 player->msg_posted = TRUE;
8284 /* unrealize the player */
8285 ret = _mmplayer_unrealize(hplayer);
8286 if (ret != MM_ERROR_NONE)
8287 LOGE("failed to unrealize");
8295 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8297 int ret = MM_ERROR_NONE;
8298 mm_player_t *player = (mm_player_t *)hplayer;
8299 int idx = 0, total = 0;
8300 gchar *result = NULL, *tmp = NULL;
8303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8304 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8306 total = *num = g_list_length(player->adaptive_info.var_list);
8308 LOGW("There is no stream variant info.");
8312 result = g_strdup("");
8313 for (idx = 0 ; idx < total ; idx++) {
8314 VariantData *v_data = NULL;
8315 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8318 gchar data[64] = {0};
8319 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8321 tmp = g_strconcat(result, data, NULL);
8325 LOGW("There is no variant data in %d", idx);
8330 *var_info = (char *)result;
8332 LOGD("variant info %d:%s", *num, *var_info);
8338 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8340 int ret = MM_ERROR_NONE;
8341 mm_player_t *player = (mm_player_t *)hplayer;
8344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8346 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8348 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8349 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8350 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8352 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8353 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8354 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8355 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8357 /* FIXME: seek to current position for applying new variant limitation */
8366 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8368 int ret = MM_ERROR_NONE;
8369 mm_player_t *player = (mm_player_t *)hplayer;
8372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8373 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8375 *bandwidth = player->adaptive_info.limit.bandwidth;
8376 *width = player->adaptive_info.limit.width;
8377 *height = player->adaptive_info.limit.height;
8379 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8386 _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8388 int ret = MM_ERROR_NONE;
8389 mm_player_t *player = (mm_player_t *)hplayer;
8392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8394 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8395 LOGW("buffer_ms will not be applied.");
8397 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8399 if (player->streamer == NULL) {
8400 player->streamer = __mm_player_streaming_create();
8401 __mm_player_streaming_initialize(player->streamer);
8405 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8407 if (rebuffer_ms >= 0)
8408 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8416 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8418 int ret = MM_ERROR_NONE;
8419 mm_player_t *player = (mm_player_t *)hplayer;
8422 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8423 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8425 if (player->streamer == NULL) {
8426 player->streamer = __mm_player_streaming_create();
8427 __mm_player_streaming_initialize(player->streamer);
8430 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8431 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8433 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8440 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8442 #define IDX_FIRST_SW_CODEC 0
8443 mm_player_t *player = (mm_player_t *)hplayer;
8444 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8445 MMHandleType attrs = 0;
8448 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8450 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8451 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8452 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8454 switch (stream_type) {
8455 case MM_PLAYER_STREAM_TYPE_AUDIO:
8456 /* to support audio codec selection, codec info have to be added in ini file as below.
8457 audio codec element hw = xxxx
8458 audio codec element sw = avdec */
8459 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8460 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8461 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8462 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8463 LOGE("There is no audio codec info for codec_type %d", codec_type);
8464 return MM_ERROR_PLAYER_NO_OP;
8467 case MM_PLAYER_STREAM_TYPE_VIDEO:
8468 /* to support video codec selection, codec info have to be added in ini file as below.
8469 video codec element hw = omx
8470 video codec element sw = avdec */
8471 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8472 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8473 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8474 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8475 LOGE("There is no video codec info for codec_type %d", codec_type);
8476 return MM_ERROR_PLAYER_NO_OP;
8480 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8481 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8485 LOGD("update %s codec_type to %d", attr_name, codec_type);
8487 attrs = MMPLAYER_GET_ATTRS(player);
8488 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8490 if (mm_attrs_commit_all(player->attrs)) {
8491 LOGE("failed to commit codec_type attributes");
8492 return MM_ERROR_PLAYER_INTERNAL;
8496 return MM_ERROR_NONE;
8500 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8502 mm_player_t *player = (mm_player_t *)hplayer;
8503 GstElement *rg_vol_element = NULL;
8507 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8509 player->sound.rg_enable = enabled;
8511 /* just hold rgvolume enable value if pipeline is not ready */
8512 if (!player->pipeline || !player->pipeline->audiobin) {
8513 LOGD("pipeline is not ready. holding rgvolume enable value");
8514 return MM_ERROR_NONE;
8517 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8519 if (!rg_vol_element) {
8520 LOGD("rgvolume element is not created");
8521 return MM_ERROR_PLAYER_INTERNAL;
8525 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8527 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8531 return MM_ERROR_NONE;
8535 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8537 mm_player_t *player = (mm_player_t *)hplayer;
8538 GstElement *rg_vol_element = NULL;
8539 gboolean enable = FALSE;
8543 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8544 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8546 /* just hold enable_rg value if pipeline is not ready */
8547 if (!player->pipeline || !player->pipeline->audiobin) {
8548 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8549 *enabled = player->sound.rg_enable;
8550 return MM_ERROR_NONE;
8553 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8555 if (!rg_vol_element) {
8556 LOGD("rgvolume element is not created");
8557 return MM_ERROR_PLAYER_INTERNAL;
8560 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8561 *enabled = (bool)enable;
8565 return MM_ERROR_NONE;
8569 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8571 mm_player_t *player = (mm_player_t *)hplayer;
8572 MMHandleType attrs = 0;
8573 void *handle = NULL;
8574 int ret = MM_ERROR_NONE;
8578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8580 attrs = MMPLAYER_GET_ATTRS(player);
8581 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8583 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8585 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8586 return MM_ERROR_PLAYER_INTERNAL;
8589 player->video_roi.scale_x = scale_x;
8590 player->video_roi.scale_y = scale_y;
8591 player->video_roi.scale_width = scale_width;
8592 player->video_roi.scale_height = scale_height;
8594 /* check video sinkbin is created */
8595 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8596 return MM_ERROR_NONE;
8598 if (!gst_video_overlay_set_video_roi_area(
8599 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8600 scale_x, scale_y, scale_width, scale_height))
8601 ret = MM_ERROR_PLAYER_INTERNAL;
8603 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8604 scale_x, scale_y, scale_width, scale_height);
8612 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8614 mm_player_t *player = (mm_player_t *)hplayer;
8615 int ret = MM_ERROR_NONE;
8619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8620 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8622 *scale_x = player->video_roi.scale_x;
8623 *scale_y = player->video_roi.scale_y;
8624 *scale_width = player->video_roi.scale_width;
8625 *scale_height = player->video_roi.scale_height;
8627 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8628 *scale_x, *scale_y, *scale_width, *scale_height);
8634 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8636 gboolean ret = FALSE;
8637 gint64 dur_nsec = 0;
8638 LOGD("try to update duration");
8640 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8641 player->duration = dur_nsec;
8642 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8646 if (player->duration < 0) {
8647 LOGW("duration is Non-Initialized !!!");
8648 player->duration = 0;
8651 /* update streaming service type */
8652 player->streaming_type = __mmplayer_get_stream_service_type(player);
8654 /* check duration is OK */
8655 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8656 /* FIXIT : find another way to get duration here. */
8657 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8663 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8665 /* update audio params
8666 NOTE : We need original audio params and it can be only obtained from src pad of audio
8667 decoder. Below code only valid when we are not using 'resampler' just before
8668 'audioconverter'. */
8669 GstCaps *caps_a = NULL;
8671 gint samplerate = 0, channels = 0;
8672 GstStructure *p = NULL;
8674 LOGD("try to update audio attrs");
8676 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8677 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8679 pad = gst_element_get_static_pad(
8680 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8683 LOGW("failed to get pad from audiosink");
8687 caps_a = gst_pad_get_current_caps(pad);
8689 LOGW("not ready to get audio caps");
8690 gst_object_unref(pad);
8694 p = gst_caps_get_structure(caps_a, 0);
8696 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8698 gst_structure_get_int(p, "rate", &samplerate);
8699 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8701 gst_structure_get_int(p, "channels", &channels);
8702 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8704 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8706 gst_caps_unref(caps_a);
8707 gst_object_unref(pad);
8713 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8715 LOGD("try to update video attrs");
8717 GstCaps *caps_v = NULL;
8721 GstStructure *p = NULL;
8723 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8724 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8726 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8728 LOGD("no videosink sink pad");
8732 caps_v = gst_pad_get_current_caps(pad);
8733 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8734 if (!caps_v && player->v_stream_caps) {
8735 caps_v = player->v_stream_caps;
8736 gst_caps_ref(caps_v);
8740 LOGD("no negitiated caps from videosink");
8741 gst_object_unref(pad);
8745 p = gst_caps_get_structure(caps_v, 0);
8746 gst_structure_get_int(p, "width", &width);
8747 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8749 gst_structure_get_int(p, "height", &height);
8750 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8752 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8754 SECURE_LOGD("width : %d height : %d", width, height);
8756 gst_caps_unref(caps_v);
8757 gst_object_unref(pad);
8760 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8761 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8768 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8770 gboolean ret = FALSE;
8771 guint64 data_size = 0;
8775 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8776 if (!player->duration)
8779 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8780 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8781 if (stat(path, &sb) == 0)
8782 data_size = (guint64)sb.st_size;
8784 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8785 data_size = player->http_content_size;
8788 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8791 guint64 bitrate = 0;
8792 guint64 msec_dur = 0;
8794 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8796 bitrate = data_size * 8 * 1000 / msec_dur;
8797 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8798 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8802 LOGD("player duration is less than 0");
8806 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8807 if (player->total_bitrate) {
8808 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8817 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8819 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8820 data->uri_type = uri_type;
8824 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8826 int ret = MM_ERROR_PLAYER_INVALID_URI;
8828 char *buffer = NULL;
8829 char *seperator = strchr(path, ',');
8830 char ext[100] = {0,}, size[100] = {0,};
8833 if ((buffer = strstr(path, "ext="))) {
8834 buffer += strlen("ext=");
8836 if (strlen(buffer)) {
8837 strncpy(ext, buffer, 99);
8839 if ((seperator = strchr(ext, ','))
8840 || (seperator = strchr(ext, ' '))
8841 || (seperator = strchr(ext, '\0'))) {
8842 seperator[0] = '\0';
8847 if ((buffer = strstr(path, "size="))) {
8848 buffer += strlen("size=");
8850 if (strlen(buffer) > 0) {
8851 strncpy(size, buffer, 99);
8853 if ((seperator = strchr(size, ','))
8854 || (seperator = strchr(size, ' '))
8855 || (seperator = strchr(size, '\0'))) {
8856 seperator[0] = '\0';
8859 mem_size = atoi(size);
8864 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8866 if (mem_size && param) {
8867 if (data->input_mem.buf)
8868 free(data->input_mem.buf);
8869 data->input_mem.buf = malloc(mem_size);
8871 if (data->input_mem.buf) {
8872 memcpy(data->input_mem.buf, param, mem_size);
8873 data->input_mem.len = mem_size;
8874 ret = MM_ERROR_NONE;
8876 LOGE("failed to alloc mem %d", mem_size);
8877 ret = MM_ERROR_PLAYER_INTERNAL;
8880 data->input_mem.offset = 0;
8881 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8888 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8890 gchar *location = NULL;
8893 int ret = MM_ERROR_NONE;
8895 if ((path = strstr(uri, "file://"))) {
8896 location = g_filename_from_uri(uri, NULL, &err);
8897 if (!location || (err != NULL)) {
8898 LOGE("Invalid URI '%s' for filesrc: %s", path,
8899 (err != NULL) ? err->message : "unknown error");
8903 MMPLAYER_FREEIF(location);
8905 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8906 return MM_ERROR_PLAYER_INVALID_URI;
8908 LOGD("path from uri: %s", location);
8911 path = (location != NULL) ? (location) : ((char *)uri);
8914 ret = util_exist_file_path(path);
8916 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8917 if (ret == MM_ERROR_NONE) {
8918 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8919 if (util_is_sdp_file(path)) {
8920 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8921 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8923 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8925 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8926 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8928 LOGE("invalid uri, could not play..");
8929 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8932 MMPLAYER_FREEIF(location);
8937 static MMPlayerVideoStreamDataType *
8938 __mmplayer_create_stream_from_pad(GstPad *pad)
8940 GstCaps *caps = NULL;
8941 GstStructure *structure = NULL;
8942 unsigned int fourcc = 0;
8943 const gchar *string_format = NULL;
8944 MMPlayerVideoStreamDataType *stream = NULL;
8946 MMPixelFormatType format;
8948 caps = gst_pad_get_current_caps(pad);
8950 LOGE("Caps is NULL.");
8954 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8955 structure = gst_caps_get_structure(caps, 0);
8956 gst_structure_get_int(structure, "width", &width);
8957 gst_structure_get_int(structure, "height", &height);
8958 string_format = gst_structure_get_string(structure, "format");
8960 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8961 format = util_get_pixtype(fourcc);
8962 gst_caps_unref(caps);
8965 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8966 LOGE("Wrong condition!!");
8970 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
8972 LOGE("failed to alloc mem for video data");
8976 stream->width = width;
8977 stream->height = height;
8978 stream->format = format;
8984 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
8986 unsigned int pitch = 0;
8988 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
8990 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
8991 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
8992 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
8993 stream->stride[index] = pitch;
8994 stream->elevation[index] = stream->height;
8999 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9001 if (stream->format == MM_PIXEL_FORMAT_I420) {
9002 int ret = TBM_SURFACE_ERROR_NONE;
9003 tbm_surface_h surface;
9004 tbm_surface_info_s info;
9006 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9008 ret = tbm_surface_get_info(surface, &info);
9009 if (ret != TBM_SURFACE_ERROR_NONE) {
9010 tbm_surface_destroy(surface);
9014 tbm_surface_destroy(surface);
9015 stream->stride[0] = info.planes[0].stride;
9016 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9017 stream->stride[1] = info.planes[1].stride;
9018 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9019 stream->stride[2] = info.planes[2].stride;
9020 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9021 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9022 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9023 stream->stride[0] = stream->width * 4;
9024 stream->elevation[0] = stream->height;
9025 stream->bo_size = stream->stride[0] * stream->height;
9027 LOGE("Not support format %d", stream->format);
9035 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9037 tbm_bo_handle thandle;
9039 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9040 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9041 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9045 unsigned char *src = NULL;
9046 unsigned char *dest = NULL;
9047 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9049 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9051 LOGE("fail to gst_memory_map");
9055 if (!mapinfo.data) {
9056 LOGE("data pointer is wrong");
9060 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9061 if (!stream->bo[0]) {
9062 LOGE("Fail to tbm_bo_alloc!!");
9066 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9068 LOGE("thandle pointer is wrong");
9072 if (stream->format == MM_PIXEL_FORMAT_I420) {
9073 src_stride[0] = GST_ROUND_UP_4(stream->width);
9074 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9075 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9076 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9079 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9080 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9082 for (i = 0; i < 3; i++) {
9083 src = mapinfo.data + src_offset[i];
9084 dest = thandle.ptr + dest_offset[i];
9089 for (j = 0; j < stream->height >> k; j++) {
9090 memcpy(dest, src, stream->width>>k);
9091 src += src_stride[i];
9092 dest += stream->stride[i];
9095 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9096 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9098 LOGE("Not support format %d", stream->format);
9102 tbm_bo_unmap(stream->bo[0]);
9103 gst_memory_unmap(mem, &mapinfo);
9109 tbm_bo_unmap(stream->bo[0]);
9112 gst_memory_unmap(mem, &mapinfo);
9118 __mmplayer_set_pause_state(mm_player_t *player)
9120 if (player->sent_bos)
9123 /* rtsp case, get content attrs by GstMessage */
9124 if (MMPLAYER_IS_RTSP_STREAMING(player))
9127 /* it's first time to update all content attrs. */
9128 __mmplayer_update_content_attrs(player, ATTR_ALL);
9132 __mmplayer_set_playing_state(mm_player_t *player)
9134 gchar *audio_codec = NULL;
9136 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9137 /* initialize because auto resume is done well. */
9138 player->resumed_by_rewind = FALSE;
9139 player->playback_rate = 1.0;
9142 if (player->sent_bos)
9145 /* try to get content metadata */
9147 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9148 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9149 * legacy mmfw-player api
9151 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9153 if ((player->cmd == MMPLAYER_COMMAND_START)
9154 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9155 __mmplayer_handle_missed_plugin(player);
9158 /* check audio codec field is set or not
9159 * we can get it from typefinder or codec's caps.
9161 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9163 /* The codec format can't be sent for audio only case like amr, mid etc.
9164 * Because, parser don't make related TAG.
9165 * So, if it's not set yet, fill it with found data.
9168 if (g_strrstr(player->type, "audio/midi"))
9169 audio_codec = "MIDI";
9170 else if (g_strrstr(player->type, "audio/x-amr"))
9171 audio_codec = "AMR";
9172 else if (g_strrstr(player->type, "audio/mpeg")
9173 && !g_strrstr(player->type, "mpegversion= (int)1"))
9174 audio_codec = "AAC";
9176 audio_codec = "unknown";
9178 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9180 if (mm_attrs_commit_all(player->attrs))
9181 LOGE("failed to update attributes");
9183 LOGD("set audio codec type with caps");