4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
113 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
114 We are defining our own and will be removed when it actually exposed */
116 GST_AUTOPLUG_SELECT_TRY,
117 GST_AUTOPLUG_SELECT_EXPOSE,
118 GST_AUTOPLUG_SELECT_SKIP
119 } GstAutoplugSelectResult;
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
135 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
136 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
137 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
142 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
143 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
144 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
152 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_release_misc(mm_player_t *player);
154 static void __mmplayer_release_misc_post(mm_player_t *player);
155 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
156 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
159 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
161 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
162 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
163 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
164 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
165 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
166 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
167 static gpointer __mmplayer_gapless_play_thread(gpointer data);
168 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
169 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static void __mmplayer_release_dump_list(GList *dump_list);
171 static int __mmplayer_gst_realize(mm_player_t *player);
172 static int __mmplayer_gst_unrealize(mm_player_t *player);
173 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
174 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
177 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
178 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
179 static void __mmplayer_check_pipeline(mm_player_t *player);
180 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
181 static void __mmplayer_deactivate_old_path(mm_player_t *player);
182 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
183 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
184 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
185 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
186 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
187 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
188 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
189 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
193 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
194 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
195 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
197 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
198 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
199 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
200 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
202 static void __mmplayer_set_pause_state(mm_player_t *player);
203 static void __mmplayer_set_playing_state(mm_player_t *player);
204 /*===========================================================================================
206 | FUNCTION DEFINITIONS |
208 ========================================================================================== */
212 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
216 count = gst_tag_list_get_tag_size(list, tag);
218 LOGD("count = %d", count);
220 for (i = 0; i < count; i++) {
223 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
224 if (!gst_tag_list_get_string_index(list, tag, i, &str))
225 g_assert_not_reached();
227 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
231 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
233 g_print(" : %s", str);
240 /* This function should be called after the pipeline goes PAUSED or higher
243 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
245 static gboolean has_duration = FALSE;
246 static gboolean has_video_attrs = FALSE;
247 static gboolean has_audio_attrs = FALSE;
248 static gboolean has_bitrate = FALSE;
249 gboolean missing_only = FALSE;
250 gboolean all = FALSE;
251 MMHandleType attrs = 0;
255 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
257 /* check player state here */
258 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
259 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
260 /* give warning now only */
261 LOGW("be careful. content attributes may not available in this state ");
264 /* get content attribute first */
265 attrs = MMPLAYER_GET_ATTRS(player);
267 LOGE("cannot get content attribute");
271 /* get update flag */
273 if (flag & ATTR_MISSING_ONLY) {
275 LOGD("updating missed attr only");
278 if (flag & ATTR_ALL) {
280 has_duration = FALSE;
281 has_video_attrs = FALSE;
282 has_audio_attrs = FALSE;
285 LOGD("updating all attrs");
288 if (missing_only && all) {
289 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
290 missing_only = FALSE;
293 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
294 has_duration = __mmplayer_update_duration_value(player);
296 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
297 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
299 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
300 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
302 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
303 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
306 if (mm_attrs_commit_all(attrs)) {
307 LOGE("failed to update attributes");
317 __mmplayer_get_stream_service_type(mm_player_t *player)
319 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
325 player->pipeline->mainbin &&
326 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
327 STREAMING_SERVICE_NONE);
329 /* streaming service type if streaming */
330 if (!MMPLAYER_IS_STREAMING(player))
331 return STREAMING_SERVICE_NONE;
333 streaming_type = (player->duration == 0) ?
334 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
336 switch (streaming_type) {
337 case STREAMING_SERVICE_LIVE:
338 LOGD("it's live streaming");
340 case STREAMING_SERVICE_VOD:
341 LOGD("it's vod streaming");
344 LOGE("should not get here");
350 return streaming_type;
353 /* this function sets the player state and also report
354 * it to applicaton by calling callback function
357 __mmplayer_set_state(mm_player_t *player, int state)
359 MMMessageParamType msg = {0, };
361 MMPLAYER_RETURN_IF_FAIL(player);
363 if (MMPLAYER_CURRENT_STATE(player) == state) {
364 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
365 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
369 /* update player states */
370 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
371 MMPLAYER_CURRENT_STATE(player) = state;
373 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
374 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
377 MMPLAYER_PRINT_STATE(player);
379 switch (MMPLAYER_CURRENT_STATE(player)) {
380 case MM_PLAYER_STATE_NULL:
381 case MM_PLAYER_STATE_READY:
383 case MM_PLAYER_STATE_PAUSED:
384 __mmplayer_set_pause_state(player);
386 case MM_PLAYER_STATE_PLAYING:
387 __mmplayer_set_playing_state(player);
389 case MM_PLAYER_STATE_NONE:
391 LOGW("invalid target state, there is nothing to do.");
396 /* post message to application */
397 if (MMPLAYER_TARGET_STATE(player) == state) {
398 /* fill the message with state of player */
399 msg.union_type = MM_MSG_UNION_STATE;
400 msg.state.previous = MMPLAYER_PREV_STATE(player);
401 msg.state.current = MMPLAYER_CURRENT_STATE(player);
403 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
405 /* state changed by resource callback */
406 if (player->interrupted_by_resource)
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
408 else /* state changed by usecase */
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
412 LOGD("intermediate state, do nothing.");
413 MMPLAYER_PRINT_STATE(player);
417 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
418 && !player->sent_bos) {
419 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
420 player->sent_bos = TRUE;
427 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
429 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
430 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
434 //LOGD("incomming command : %d ", command);
436 current_state = MMPLAYER_CURRENT_STATE(player);
437 pending_state = MMPLAYER_PENDING_STATE(player);
439 MMPLAYER_PRINT_STATE(player);
442 case MMPLAYER_COMMAND_CREATE:
444 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
446 if (current_state == MM_PLAYER_STATE_NULL ||
447 current_state == MM_PLAYER_STATE_READY ||
448 current_state == MM_PLAYER_STATE_PAUSED ||
449 current_state == MM_PLAYER_STATE_PLAYING)
454 case MMPLAYER_COMMAND_DESTROY:
456 /* destroy can called anytime */
458 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
462 case MMPLAYER_COMMAND_REALIZE:
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
466 if (pending_state != MM_PLAYER_STATE_NONE) {
469 /* need ready state to realize */
470 if (current_state == MM_PLAYER_STATE_READY)
473 if (current_state != MM_PLAYER_STATE_NULL)
479 case MMPLAYER_COMMAND_UNREALIZE:
481 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
483 if (current_state == MM_PLAYER_STATE_NULL)
488 case MMPLAYER_COMMAND_START:
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PLAYING)
495 else if (current_state != MM_PLAYER_STATE_READY &&
496 current_state != MM_PLAYER_STATE_PAUSED)
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
501 LOGD("player is going to paused state, just change the pending state as playing");
508 case MMPLAYER_COMMAND_STOP:
510 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
512 if (current_state == MM_PLAYER_STATE_READY)
515 /* need playing/paused state to stop */
516 if (current_state != MM_PLAYER_STATE_PLAYING &&
517 current_state != MM_PLAYER_STATE_PAUSED)
522 case MMPLAYER_COMMAND_PAUSE:
524 if (MMPLAYER_IS_LIVE_STREAMING(player))
527 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
528 goto NOT_COMPLETED_SEEK;
530 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
532 if (pending_state == MM_PLAYER_STATE_NONE) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
535 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
537 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
539 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
540 if (current_state == MM_PLAYER_STATE_PAUSED)
541 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
548 case MMPLAYER_COMMAND_RESUME:
550 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
551 goto NOT_COMPLETED_SEEK;
553 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
555 if (pending_state == MM_PLAYER_STATE_NONE) {
556 if (current_state == MM_PLAYER_STATE_PLAYING)
558 else if (current_state != MM_PLAYER_STATE_PAUSED)
560 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
562 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
563 LOGD("player is going to paused state, just change the pending state as playing");
573 player->cmd = command;
575 return MM_ERROR_NONE;
578 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
579 MMPLAYER_STATE_GET_NAME(current_state), command);
580 return MM_ERROR_PLAYER_INVALID_STATE;
583 LOGW("not completed seek");
584 return MM_ERROR_PLAYER_DOING_SEEK;
587 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
592 return MM_ERROR_PLAYER_NO_OP;
596 __mmplayer_gapless_play_thread(gpointer data)
598 mm_player_t *player = (mm_player_t *)data;
599 MMPlayerGstElement *mainbin = NULL;
601 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
603 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
604 while (!player->gapless_play_thread_exit) {
605 LOGD("gapless play thread started. waiting for signal.");
606 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
608 LOGD("reconfigure pipeline for gapless play.");
610 if (player->gapless_play_thread_exit) {
611 if (player->gapless.reconfigure) {
612 player->gapless.reconfigure = false;
613 MMPLAYER_PLAYBACK_UNLOCK(player);
615 LOGD("exiting gapless play thread");
619 mainbin = player->pipeline->mainbin;
621 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
622 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
627 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
629 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
635 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
637 GSource *source = NULL;
641 source = g_main_context_find_source_by_id(context, source_id);
642 if (source != NULL) {
643 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
644 g_source_destroy(source);
651 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
653 mm_player_t *player = (mm_player_t *)hplayer;
654 GstMessage *msg = NULL;
655 GQueue *queue = NULL;
658 MMPLAYER_RETURN_IF_FAIL(player);
660 /* disconnecting bus watch */
661 if (player->bus_watcher)
662 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
663 player->bus_watcher = 0;
665 /* destroy the gst bus msg thread */
666 if (player->bus_msg_thread) {
667 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
668 player->bus_msg_thread_exit = TRUE;
669 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
670 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
672 LOGD("gst bus msg thread exit.");
673 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
674 player->bus_msg_thread = NULL;
676 g_mutex_clear(&player->bus_msg_thread_mutex);
677 g_cond_clear(&player->bus_msg_thread_cond);
680 g_mutex_lock(&player->bus_msg_q_lock);
681 queue = player->bus_msg_q;
682 while (!g_queue_is_empty(queue)) {
683 msg = (GstMessage *)g_queue_pop_head(queue);
688 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
689 gst_message_unref(msg);
691 g_mutex_unlock(&player->bus_msg_q_lock);
697 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
699 GstElement *parent = NULL;
701 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
703 /* if we have no fakesink. this meas we are using decodebin which doesn'
704 t need to add extra fakesink */
705 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
708 MMPLAYER_FSINK_LOCK(player);
713 /* get parent of fakesink */
714 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
716 LOGD("fakesink already removed");
720 gst_element_set_locked_state(fakesink->gst, TRUE);
722 /* setting the state to NULL never returns async
723 * so no need to wait for completion of state transiton
725 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
726 LOGE("fakesink state change failure!");
727 /* FIXIT : should I return here? or try to proceed to next? */
730 /* remove fakesink from it's parent */
731 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
732 LOGE("failed to remove fakesink");
734 gst_object_unref(parent);
739 gst_object_unref(parent);
741 LOGD("state-holder removed");
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
750 gst_element_set_locked_state(fakesink->gst, FALSE);
752 MMPLAYER_FSINK_UNLOCK(player);
756 static GstPadProbeReturn
757 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
759 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
760 return GST_PAD_PROBE_OK;
764 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
766 gint64 stop_running_time = 0;
767 gint64 position_running_time = 0;
771 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
772 if ((player->gapless.update_segment[idx] == TRUE) ||
773 !(player->selector[idx].event_probe_id)) {
774 /* LOGW("[%d] skip", idx); */
778 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
780 gst_segment_to_running_time(&player->gapless.segment[idx],
781 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
782 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
787 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->duration);
793 position_running_time =
794 gst_segment_to_running_time(&player->gapless.segment[idx],
795 GST_FORMAT_TIME, player->gapless.segment[idx].position);
797 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
798 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
800 GST_TIME_ARGS(stop_running_time),
801 GST_TIME_ARGS(position_running_time),
802 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
803 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
805 position_running_time = MAX(position_running_time, stop_running_time);
806 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
807 GST_FORMAT_TIME, player->gapless.segment[idx].start);
808 position_running_time = MAX(0, position_running_time);
809 position = MAX(position, position_running_time);
813 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
814 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
815 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
817 player->gapless.start_time[stream_type] += position;
823 static GstPadProbeReturn
824 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
826 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
827 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
828 mm_player_t *player = (mm_player_t *)data;
829 GstCaps *caps = NULL;
830 GstStructure *str = NULL;
831 const gchar *name = NULL;
832 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
833 gboolean caps_ret = TRUE;
835 if (GST_EVENT_IS_DOWNSTREAM(event) &&
836 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
837 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
838 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
839 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
841 } else if (GST_EVENT_IS_UPSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
846 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
850 if (strstr(name, "audio")) {
851 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
852 } else if (strstr(name, "video")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
855 /* text track is not supportable */
856 LOGE("invalid name %s", name);
860 switch (GST_EVENT_TYPE(event)) {
863 /* in case of gapless, drop eos event not to send it to sink */
864 if (player->gapless.reconfigure && !player->msg_posted) {
865 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
866 ret = GST_PAD_PROBE_DROP;
870 case GST_EVENT_STREAM_START:
872 __mmplayer_gst_selector_update_start_time(player, stream_type);
875 case GST_EVENT_FLUSH_STOP:
877 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
878 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
879 player->gapless.start_time[stream_type] = 0;
882 case GST_EVENT_SEGMENT:
887 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
888 gst_event_copy_segment(event, &segment);
890 if (segment.format != GST_FORMAT_TIME)
893 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
894 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
895 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
896 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
897 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
898 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
900 /* keep the all the segment ev to cover the seeking */
901 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
902 player->gapless.update_segment[stream_type] = TRUE;
904 if (!player->gapless.running)
907 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
909 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
911 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
912 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
913 gst_event_unref(event);
914 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
920 gdouble proportion = 0.0;
921 GstClockTimeDiff diff = 0;
922 GstClockTime timestamp = 0;
923 gint64 running_time_diff = -1;
925 GstEvent *tmpev = NULL;
927 running_time_diff = player->gapless.segment[stream_type].base;
929 if (running_time_diff <= 0) /* don't need to adjust */
932 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
933 gst_event_unref(event);
935 if (timestamp < running_time_diff) {
936 LOGW("QOS event from previous group");
937 ret = GST_PAD_PROBE_DROP;
941 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
942 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(timestamp),
944 GST_TIME_ARGS(running_time_diff),
945 GST_TIME_ARGS(timestamp - running_time_diff));
947 timestamp -= running_time_diff;
949 /* That case is invalid for QoS events */
950 if (diff < 0 && -diff > timestamp) {
951 LOGW("QOS event from previous group");
952 ret = GST_PAD_PROBE_DROP;
956 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
957 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
967 gst_caps_unref(caps);
971 /* create fakesink for audio or video path witout audiobin or videobin */
973 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
975 GstElement *pipeline = NULL;
976 GstElement *fakesink = NULL;
977 GstPad *sinkpad = NULL;
980 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
982 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
985 fakesink = gst_element_factory_make("fakesink", NULL);
986 if (fakesink == NULL) {
987 LOGE("failed to create fakesink");
991 /* store it as it's sink element */
992 __mmplayer_add_sink(player, fakesink);
994 gst_bin_add(GST_BIN(pipeline), fakesink);
997 sinkpad = gst_element_get_static_pad(fakesink, "sink");
999 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1001 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1002 LOGE("failed to link fakesink");
1003 gst_object_unref(GST_OBJECT(fakesink));
1007 if (strstr(name, "video")) {
1008 if (player->v_stream_caps) {
1009 gst_caps_unref(player->v_stream_caps);
1010 player->v_stream_caps = NULL;
1012 if (player->ini.set_dump_element_flag)
1013 __mmplayer_add_dump_buffer_probe(player, fakesink);
1016 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1017 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1021 gst_object_unref(GST_OBJECT(sinkpad));
1028 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1030 GstElement *pipeline = NULL;
1031 GstElement *selector = NULL;
1032 GstPad *srcpad = NULL;
1035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1037 selector = gst_element_factory_make("input-selector", NULL);
1039 LOGE("failed to create input-selector");
1042 g_object_set(selector, "sync-streams", TRUE, NULL);
1044 player->pipeline->mainbin[elem_idx].id = elem_idx;
1045 player->pipeline->mainbin[elem_idx].gst = selector;
1047 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1049 srcpad = gst_element_get_static_pad(selector, "src");
1051 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1052 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1053 __mmplayer_gst_selector_blocked, NULL, NULL);
1054 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1055 __mmplayer_gst_selector_event_probe, player, NULL);
1057 gst_element_set_state(selector, GST_STATE_PAUSED);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1060 gst_bin_add(GST_BIN(pipeline), selector);
1067 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1069 mm_player_t *player = (mm_player_t *)data;
1070 GstElement *selector = NULL;
1071 GstCaps *caps = NULL;
1072 GstStructure *str = NULL;
1073 const gchar *name = NULL;
1074 GstPad *sinkpad = NULL;
1075 gboolean first_track = FALSE;
1076 gboolean caps_ret = TRUE;
1078 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1079 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1082 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1083 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1085 LOGD("pad-added signal handling");
1087 /* get mimetype from caps */
1088 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1092 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1093 /* LOGD("detected mimetype : %s", name); */
1095 if (strstr(name, "video")) {
1097 gchar *caps_str = NULL;
1099 caps_str = gst_caps_to_string(caps);
1100 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1101 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1102 player->set_mode.video_zc = true;
1104 MMPLAYER_FREEIF(caps_str);
1106 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1107 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1109 LOGD("surface type : %d", stype);
1111 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1112 __mmplayer_gst_create_sinkbin(elem, pad, player);
1116 /* in case of exporting video frame, it requires the 360 video filter.
1117 * it will be handled in _no_more_pads(). */
1118 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1119 __mmplayer_gst_make_fakesink(player, pad, name);
1123 LOGD("video selector is required");
1124 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1125 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1126 } else if (strstr(name, "audio")) {
1127 gint samplerate = 0;
1130 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1131 if (player->build_audio_offload)
1132 player->no_more_pad = TRUE; /* remove state holder */
1133 __mmplayer_gst_create_sinkbin(elem, pad, player);
1137 gst_structure_get_int(str, "rate", &samplerate);
1138 gst_structure_get_int(str, "channels", &channels);
1140 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1141 __mmplayer_gst_make_fakesink(player, pad, name);
1145 LOGD("audio selector is required");
1146 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1147 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1149 } else if (strstr(name, "text")) {
1150 LOGD("text selector is required");
1151 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1152 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1154 LOGE("invalid caps info");
1158 /* check selector and create it */
1159 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1160 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1165 LOGD("input-selector is already created.");
1169 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1171 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1173 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1174 LOGE("failed to link selector");
1175 gst_object_unref(GST_OBJECT(selector));
1180 LOGD("this track will be activated");
1181 g_object_set(selector, "active-pad", sinkpad, NULL);
1184 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1190 gst_caps_unref(caps);
1193 gst_object_unref(GST_OBJECT(sinkpad));
1201 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1203 GstPad *srcpad = NULL;
1206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1208 LOGD("type %d", type);
1211 LOGD("there is no %d track", type);
1215 srcpad = gst_element_get_static_pad(selector, "src");
1217 LOGE("failed to get srcpad from selector");
1221 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1223 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1225 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1226 if (player->selector[type].block_id) {
1227 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1228 player->selector[type].block_id = 0;
1232 gst_object_unref(GST_OBJECT(srcpad));
1241 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1243 MMHandleType attrs = 0;
1244 gint active_index = 0;
1247 MMPLAYER_RETURN_IF_FAIL(player);
1249 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1251 /* change track to active pad */
1252 active_index = player->selector[type].active_pad_index;
1253 if ((active_index != DEFAULT_TRACK) &&
1254 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1255 LOGW("failed to change %d type track to %d", type, active_index);
1256 player->selector[type].active_pad_index = DEFAULT_TRACK;
1260 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1261 attrs = MMPLAYER_GET_ATTRS(player);
1263 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1264 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1266 if (mm_attrs_commit_all(attrs))
1267 LOGW("failed to commit attrs.");
1269 LOGW("cannot get content attribute");
1278 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1281 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1283 if (!audio_selector) {
1284 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1286 /* in case the source is changed, output can be changed. */
1287 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1288 LOGD("remove previous audiobin if it exist");
1290 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1291 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1293 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1294 MMPLAYER_FREEIF(player->pipeline->audiobin);
1297 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1298 __mmplayer_pipeline_complete(NULL, player);
1303 /* apply the audio track information */
1304 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1306 /* create audio sink path */
1307 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1308 LOGE("failed to create audio sink path");
1317 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1320 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1322 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1323 LOGD("text path is not supproted");
1327 /* apply the text track information */
1328 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1330 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1331 player->has_closed_caption = TRUE;
1333 /* create text decode path */
1334 player->no_more_pad = TRUE;
1336 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1337 LOGE("failed to create text sink path");
1346 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1348 gint64 dur_bytes = 0L;
1351 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1352 player->pipeline->mainbin && player->streamer, FALSE);
1354 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1355 LOGE("fail to get duration.");
1357 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1358 * use file information was already set on Q2 when it was created. */
1359 __mm_player_streaming_set_queue2(player->streamer,
1360 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1361 TRUE, /* use_buffering */
1362 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1363 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1370 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1372 mm_player_t *player = NULL;
1373 GstElement *video_selector = NULL;
1374 GstElement *audio_selector = NULL;
1375 GstElement *text_selector = NULL;
1378 player = (mm_player_t *)data;
1380 LOGD("no-more-pad signal handling");
1382 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1383 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1384 LOGW("player is shutting down");
1388 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1389 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1390 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1391 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1392 LOGE("failed to set queue2 buffering");
1397 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1398 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1399 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1401 if (!video_selector && !audio_selector && !text_selector) {
1402 LOGW("there is no selector");
1403 player->no_more_pad = TRUE;
1407 /* create video path followed by video-select */
1408 if (video_selector && !audio_selector && !text_selector)
1409 player->no_more_pad = TRUE;
1411 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1414 /* create audio path followed by audio-select */
1415 if (audio_selector && !text_selector)
1416 player->no_more_pad = TRUE;
1418 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1421 /* create text path followed by text-select */
1422 __mmplayer_create_text_sink_path(player, text_selector);
1425 if (player->gapless.reconfigure) {
1426 player->gapless.reconfigure = FALSE;
1427 MMPLAYER_PLAYBACK_UNLOCK(player);
1434 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1436 gboolean ret = FALSE;
1437 GstElement *pipeline = NULL;
1438 GstPad *sinkpad = NULL;
1441 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1444 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1446 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1448 LOGE("failed to get pad from sinkbin");
1454 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1455 LOGE("failed to link sinkbin for reusing");
1456 goto EXIT; /* exit either pass or fail */
1460 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1461 LOGE("failed to set state(READY) to sinkbin");
1466 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1467 LOGE("failed to add sinkbin to pipeline");
1472 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1473 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1478 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1479 LOGE("failed to set state(PAUSED) to sinkbin");
1488 gst_object_unref(GST_OBJECT(sinkpad));
1496 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t *player = NULL;
1499 GstCaps *caps = NULL;
1500 gchar *caps_str = NULL;
1501 GstStructure *str = NULL;
1502 const gchar *name = NULL;
1503 GstElement *sinkbin = NULL;
1504 gboolean reusing = FALSE;
1505 gboolean caps_ret = TRUE;
1506 gchar *sink_pad_name = "sink";
1509 player = (mm_player_t *)data;
1512 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1513 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1515 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1519 caps_str = gst_caps_to_string(caps);
1521 /* LOGD("detected mimetype : %s", name); */
1522 if (strstr(name, "audio")) {
1523 if (player->pipeline->audiobin == NULL) {
1524 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1525 LOGE("failed to create audiobin. continuing without audio");
1529 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1530 LOGD("creating audiobin success");
1533 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1534 LOGD("reusing audiobin");
1535 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1537 } else if (strstr(name, "video")) {
1538 /* 1. zero copy is updated at _decode_pad_added()
1539 * 2. NULL surface type is handled in _decode_pad_added() */
1540 LOGD("zero copy %d", player->set_mode.video_zc);
1541 if (player->pipeline->videobin == NULL) {
1542 int surface_type = 0;
1543 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1544 LOGD("display_surface_type (%d)", surface_type);
1546 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1547 LOGD("mark video overlay for acquire");
1548 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1549 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1550 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1551 &player->video_overlay_resource)
1552 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1553 LOGE("could not mark video_overlay resource for acquire");
1558 player->interrupted_by_resource = FALSE;
1560 if (mm_resource_manager_commit(player->resource_manager) !=
1561 MM_RESOURCE_MANAGER_ERROR_NONE) {
1562 LOGE("could not acquire resources for video playing");
1566 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1567 LOGE("failed to create videobin. continuing without video");
1571 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1572 LOGD("creating videosink bin success");
1575 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1576 LOGD("re-using videobin");
1577 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1579 } else if (strstr(name, "text")) {
1580 if (player->pipeline->textbin == NULL) {
1581 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1582 LOGE("failed to create text sink bin. continuing without text");
1586 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1587 player->textsink_linked = 1;
1588 LOGD("creating textsink bin success");
1590 if (!player->textsink_linked) {
1591 LOGD("re-using textbin");
1593 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1594 player->textsink_linked = 1;
1596 /* linked textbin exist which means that the external subtitle path exist already */
1597 LOGW("ignoring internal subtutle since external subtitle is available");
1600 sink_pad_name = "text_sink";
1602 LOGW("unknown mime type %s, ignoring it", name);
1606 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1609 LOGD("[handle: %p] success to create and link sink bin", player);
1611 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1612 * streaming task. if the task blocked, then buffer will not flow to the next element
1613 *(autoplugging element). so this is special hack for streaming. please try to remove it
1615 /* dec stream count. we can remove fakesink if it's zero */
1616 if (player->num_dynamic_pad)
1617 player->num_dynamic_pad--;
1619 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1621 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1622 __mmplayer_pipeline_complete(NULL, player);
1626 MMPLAYER_FREEIF(caps_str);
1629 gst_caps_unref(caps);
1635 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1637 int required_angle = 0; /* Angle required for straight view */
1638 int rotation_angle = 0;
1640 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1641 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1643 /* Counter clockwise */
1644 switch (orientation) {
1649 required_angle = 270;
1652 required_angle = 180;
1655 required_angle = 90;
1659 rotation_angle = display_angle + required_angle;
1660 if (rotation_angle >= 360)
1661 rotation_angle -= 360;
1663 /* chech if supported or not */
1664 if (rotation_angle % 90) {
1665 LOGD("not supported rotation angle = %d", rotation_angle);
1669 switch (rotation_angle) {
1671 *value = MM_DISPLAY_ROTATION_NONE;
1674 *value = MM_DISPLAY_ROTATION_90;
1677 *value = MM_DISPLAY_ROTATION_180;
1680 *value = MM_DISPLAY_ROTATION_270;
1684 LOGD("setting rotation property value : %d", *value);
1690 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1692 /* check video sinkbin is created */
1693 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1695 player->pipeline->videobin &&
1696 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1697 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1698 MM_ERROR_PLAYER_NOT_INITIALIZED);
1700 return MM_ERROR_NONE;
1704 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1706 int display_rotation = 0;
1707 gchar *org_orient = NULL;
1708 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1711 LOGE("cannot get content attribute");
1712 return MM_ERROR_PLAYER_INTERNAL;
1715 if (display_angle) {
1716 /* update user roation */
1717 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1719 /* Counter clockwise */
1720 switch (display_rotation) {
1721 case MM_DISPLAY_ROTATION_NONE:
1724 case MM_DISPLAY_ROTATION_90:
1725 *display_angle = 90;
1727 case MM_DISPLAY_ROTATION_180:
1728 *display_angle = 180;
1730 case MM_DISPLAY_ROTATION_270:
1731 *display_angle = 270;
1734 LOGW("wrong angle type : %d", display_rotation);
1737 LOGD("check user angle: %d", *display_angle);
1741 /* Counter clockwise */
1742 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1745 if (!strcmp(org_orient, "rotate-90"))
1747 else if (!strcmp(org_orient, "rotate-180"))
1749 else if (!strcmp(org_orient, "rotate-270"))
1752 LOGD("original rotation is %s", org_orient);
1754 LOGD("content_video_orientation get fail");
1757 LOGD("check orientation: %d", *orientation);
1760 return MM_ERROR_NONE;
1764 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1766 int rotation_value = 0;
1767 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1768 int display_angle = 0;
1771 /* check video sinkbin is created */
1772 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1775 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1777 /* get rotation value to set */
1778 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1779 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1780 LOGD("set video param : rotate %d", rotation_value);
1784 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1786 MMHandleType attrs = 0;
1790 /* check video sinkbin is created */
1791 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1794 attrs = MMPLAYER_GET_ATTRS(player);
1795 MMPLAYER_RETURN_IF_FAIL(attrs);
1797 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1798 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1799 LOGD("set video param : visible %d", visible);
1803 __mmplayer_video_param_set_display_method(mm_player_t *player)
1805 MMHandleType attrs = 0;
1806 int display_method = 0;
1809 /* check video sinkbin is created */
1810 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1813 attrs = MMPLAYER_GET_ATTRS(player);
1814 MMPLAYER_RETURN_IF_FAIL(attrs);
1816 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1817 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1818 LOGD("set video param : method %d", display_method);
1822 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1824 MMHandleType attrs = 0;
1825 void *handle = NULL;
1828 /* check video sinkbin is created */
1829 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1830 LOGW("There is no video sink");
1834 attrs = MMPLAYER_GET_ATTRS(player);
1835 MMPLAYER_RETURN_IF_FAIL(attrs);
1836 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1838 gst_video_overlay_set_video_roi_area(
1839 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1840 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1841 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1842 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1847 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1849 MMHandleType attrs = 0;
1850 void *handle = NULL;
1854 int win_roi_width = 0;
1855 int win_roi_height = 0;
1858 /* check video sinkbin is created */
1859 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1860 LOGW("There is no video sink");
1864 attrs = MMPLAYER_GET_ATTRS(player);
1865 MMPLAYER_RETURN_IF_FAIL(attrs);
1867 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1870 /* It should be set after setting window */
1871 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1872 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1873 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1874 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1876 /* After setting window handle, set display roi area */
1877 gst_video_overlay_set_display_roi_area(
1878 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1879 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1880 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1881 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1886 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1888 MMHandleType attrs = 0;
1889 void *handle = NULL;
1891 /* check video sinkbin is created */
1892 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1895 attrs = MMPLAYER_GET_ATTRS(player);
1896 MMPLAYER_RETURN_IF_FAIL(attrs);
1898 /* common case if using overlay surface */
1899 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1902 /* default is using wl_surface_id */
1903 unsigned int wl_surface_id = 0;
1904 wl_surface_id = *(int *)handle;
1905 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1906 gst_video_overlay_set_wl_window_wl_surface_id(
1907 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1910 /* FIXIT : is it error case? */
1911 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1916 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1918 gboolean update_all_param = FALSE;
1921 /* check video sinkbin is created */
1922 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1923 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1925 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1926 LOGE("can not find tizenwlsink");
1927 return MM_ERROR_PLAYER_INTERNAL;
1930 LOGD("param_name : %s", param_name);
1931 if (!g_strcmp0(param_name, "update_all_param"))
1932 update_all_param = TRUE;
1934 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1935 __mmplayer_video_param_set_display_overlay(player);
1936 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1937 __mmplayer_video_param_set_display_method(player);
1938 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1939 __mmplayer_video_param_set_display_visible(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1941 __mmplayer_video_param_set_display_rotation(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1943 __mmplayer_video_param_set_roi_area(player);
1944 if (update_all_param)
1945 __mmplayer_video_param_set_video_roi_area(player);
1947 return MM_ERROR_NONE;
1951 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1953 MMHandleType attrs = 0;
1954 int surface_type = 0;
1955 int ret = MM_ERROR_NONE;
1959 /* check video sinkbin is created */
1960 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1961 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1963 attrs = MMPLAYER_GET_ATTRS(player);
1965 LOGE("cannot get content attribute");
1966 return MM_ERROR_PLAYER_INTERNAL;
1968 LOGD("param_name : %s", param_name);
1970 /* update display surface */
1971 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1972 LOGD("check display surface type attribute: %d", surface_type);
1974 /* configuring display */
1975 switch (surface_type) {
1976 case MM_DISPLAY_SURFACE_OVERLAY:
1978 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1979 if (ret != MM_ERROR_NONE)
1987 return MM_ERROR_NONE;
1991 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1993 gboolean disable_overlay = FALSE;
1994 mm_player_t *player = (mm_player_t *)hplayer;
1995 int ret = MM_ERROR_NONE;
1998 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1999 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2000 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2001 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2003 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2004 LOGW("Display control is not supported");
2005 return MM_ERROR_PLAYER_INTERNAL;
2008 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2010 if (audio_only == (bool)disable_overlay) {
2011 LOGE("It's the same with current setting: (%d)", audio_only);
2012 return MM_ERROR_NONE;
2016 LOGE("disable overlay");
2017 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2019 /* release overlay resource */
2020 if (player->video_overlay_resource != NULL) {
2021 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2022 player->video_overlay_resource);
2023 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2024 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2027 player->video_overlay_resource = NULL;
2030 ret = mm_resource_manager_commit(player->resource_manager);
2031 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2032 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2036 /* mark video overlay for acquire */
2037 if (player->video_overlay_resource == NULL) {
2038 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2039 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2040 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2041 &player->video_overlay_resource);
2042 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2043 LOGE("could not prepare for video_overlay resource");
2048 player->interrupted_by_resource = FALSE;
2049 /* acquire resources for video overlay */
2050 ret = mm_resource_manager_commit(player->resource_manager);
2051 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2052 LOGE("could not acquire resources for video playing");
2056 LOGD("enable overlay");
2057 __mmplayer_video_param_set_display_overlay(player);
2058 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2063 return MM_ERROR_NONE;
2067 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2069 mm_player_t *player = (mm_player_t *)hplayer;
2070 gboolean disable_overlay = FALSE;
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2075 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2077 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2078 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2080 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2081 LOGW("Display control is not supported");
2082 return MM_ERROR_PLAYER_INTERNAL;
2085 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2087 *paudio_only = (bool)disable_overlay;
2089 LOGD("audio_only : %d", *paudio_only);
2093 return MM_ERROR_NONE;
2097 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2099 GList *bucket = element_bucket;
2100 MMPlayerGstElement *element = NULL;
2101 MMPlayerGstElement *prv_element = NULL;
2102 gint successful_link_count = 0;
2106 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2108 prv_element = (MMPlayerGstElement *)bucket->data;
2109 bucket = bucket->next;
2111 for (; bucket; bucket = bucket->next) {
2112 element = (MMPlayerGstElement *)bucket->data;
2114 if (element && element->gst) {
2115 if (prv_element && prv_element->gst) {
2116 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2117 LOGD("linking [%s] to [%s] success",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2120 successful_link_count++;
2122 LOGD("linking [%s] to [%s] failed",
2123 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2124 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2130 prv_element = element;
2135 return successful_link_count;
2139 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2141 GList *bucket = element_bucket;
2142 MMPlayerGstElement *element = NULL;
2143 int successful_add_count = 0;
2147 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2148 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2150 for (; bucket; bucket = bucket->next) {
2151 element = (MMPlayerGstElement *)bucket->data;
2153 if (element && element->gst) {
2154 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2155 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2156 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2157 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2160 successful_add_count++;
2166 return successful_add_count;
2170 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2172 mm_player_t *player = (mm_player_t *)data;
2173 GstCaps *caps = NULL;
2174 GstStructure *str = NULL;
2176 gboolean caps_ret = TRUE;
2180 MMPLAYER_RETURN_IF_FAIL(pad);
2181 MMPLAYER_RETURN_IF_FAIL(unused);
2182 MMPLAYER_RETURN_IF_FAIL(data);
2184 caps = gst_pad_get_current_caps(pad);
2188 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2192 LOGD("name = %s", name);
2194 if (strstr(name, "audio")) {
2195 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2197 if (player->audio_stream_changed_cb) {
2198 LOGE("call the audio stream changed cb");
2199 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2201 } else if (strstr(name, "video")) {
2202 if ((name = gst_structure_get_string(str, "format")))
2203 player->set_mode.video_zc = name[0] == 'S';
2205 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2207 if (player->video_stream_changed_cb) {
2208 LOGE("call the video stream changed cb");
2209 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2212 LOGW("invalid caps info");
2217 gst_caps_unref(caps);
2225 * This function is to create audio pipeline for playing.
2227 * @param player [in] handle of player
2229 * @return This function returns zero on success.
2231 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2233 /* macro for code readability. just for sinkbin-creation functions */
2234 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2236 x_bin[x_id].id = x_id;\
2237 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2238 if (!x_bin[x_id].gst) {\
2239 LOGE("failed to create %s", x_factory);\
2242 if (x_player->ini.set_dump_element_flag)\
2243 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2246 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2250 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2255 MMPLAYER_RETURN_IF_FAIL(player);
2257 if (player->audio_stream_buff_list) {
2258 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2259 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2262 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2263 __mmplayer_audio_stream_send_data(player, tmp);
2265 MMPLAYER_FREEIF(tmp->pcm_data);
2266 MMPLAYER_FREEIF(tmp);
2269 g_list_free(player->audio_stream_buff_list);
2270 player->audio_stream_buff_list = NULL;
2277 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2279 MMPlayerAudioStreamDataType audio_stream = { 0, };
2282 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2284 audio_stream.bitrate = a_buffer->bitrate;
2285 audio_stream.channel = a_buffer->channel;
2286 audio_stream.depth = a_buffer->depth;
2287 audio_stream.is_little_endian = a_buffer->is_little_endian;
2288 audio_stream.channel_mask = a_buffer->channel_mask;
2289 audio_stream.data_size = a_buffer->data_size;
2290 audio_stream.data = a_buffer->pcm_data;
2292 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2293 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2299 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2301 mm_player_t *player = (mm_player_t *)data;
2305 gint endianness = 0;
2306 guint64 channel_mask = 0;
2307 void *a_data = NULL;
2309 mm_player_audio_stream_buff_t *a_buffer = NULL;
2310 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2314 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2316 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2317 a_data = mapinfo.data;
2318 a_size = mapinfo.size;
2320 GstCaps *caps = gst_pad_get_current_caps(pad);
2321 GstStructure *structure = gst_caps_get_structure(caps, 0);
2323 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2324 gst_structure_get_int(structure, "rate", &rate);
2325 gst_structure_get_int(structure, "channels", &channel);
2326 gst_structure_get_int(structure, "depth", &depth);
2327 gst_structure_get_int(structure, "endianness", &endianness);
2328 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2329 gst_caps_unref(GST_CAPS(caps));
2331 /* In case of the sync is false, use buffer list. *
2332 * The num of buffer list depends on the num of audio channels */
2333 if (player->audio_stream_buff_list) {
2334 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2335 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2337 if (channel_mask == tmp->channel_mask) {
2338 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2339 if (tmp->data_size + a_size < tmp->buff_size) {
2340 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2341 tmp->data_size += a_size;
2343 /* send data to client */
2344 __mmplayer_audio_stream_send_data(player, tmp);
2346 if (a_size > tmp->buff_size) {
2347 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2348 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2349 if (tmp->pcm_data == NULL) {
2350 LOGE("failed to realloc data.");
2353 tmp->buff_size = a_size;
2355 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2356 memcpy(tmp->pcm_data, a_data, a_size);
2357 tmp->data_size = a_size;
2362 LOGE("data is empty in list.");
2368 /* create new audio stream data */
2369 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2370 if (a_buffer == NULL) {
2371 LOGE("failed to alloc data.");
2374 a_buffer->bitrate = rate;
2375 a_buffer->channel = channel;
2376 a_buffer->depth = depth;
2377 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2378 a_buffer->channel_mask = channel_mask;
2379 a_buffer->data_size = a_size;
2381 if (!player->audio_stream_sink_sync) {
2382 /* If sync is FALSE, use buffer list to reduce the IPC. */
2383 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2384 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2385 if (a_buffer->pcm_data == NULL) {
2386 LOGE("failed to alloc data.");
2387 MMPLAYER_FREEIF(a_buffer);
2390 memcpy(a_buffer->pcm_data, a_data, a_size);
2391 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2392 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2394 /* If sync is TRUE, send data directly. */
2395 a_buffer->pcm_data = a_data;
2396 __mmplayer_audio_stream_send_data(player, a_buffer);
2397 MMPLAYER_FREEIF(a_buffer);
2401 gst_buffer_unmap(buffer, &mapinfo);
2406 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2408 mm_player_t *player = (mm_player_t *)data;
2409 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2410 GstPad *sinkpad = NULL;
2411 GstElement *queue = NULL, *sink = NULL;
2414 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2416 queue = gst_element_factory_make("queue", NULL);
2417 if (queue == NULL) {
2418 LOGD("fail make queue");
2422 sink = gst_element_factory_make("fakesink", NULL);
2424 LOGD("fail make fakesink");
2428 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2430 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2431 LOGW("failed to link queue & sink");
2435 sinkpad = gst_element_get_static_pad(queue, "sink");
2437 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2438 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2442 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2444 gst_object_unref(sinkpad);
2445 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2446 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2448 gst_element_set_state(sink, GST_STATE_PAUSED);
2449 gst_element_set_state(queue, GST_STATE_PAUSED);
2451 __mmplayer_add_signal_connection(player,
2453 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2455 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2462 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2464 gst_object_unref(GST_OBJECT(queue));
2468 gst_object_unref(GST_OBJECT(sink));
2472 gst_object_unref(GST_OBJECT(sinkpad));
2480 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2482 #define MAX_PROPS_LEN 128
2483 gint latency_mode = 0;
2484 gchar *stream_type = NULL;
2485 gchar *latency = NULL;
2487 gchar stream_props[MAX_PROPS_LEN] = {0,};
2488 GstStructure *props = NULL;
2491 * It should be set after player creation through attribute.
2492 * But, it can not be changed during playing.
2495 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2497 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2498 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2501 LOGE("stream_type is null.");
2503 if (player->sound.focus_id)
2504 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2505 stream_type, stream_id, player->sound.focus_id);
2507 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2508 stream_type, stream_id);
2509 props = gst_structure_from_string(stream_props, NULL);
2510 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2511 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2512 stream_type, stream_id, player->sound.focus_id, stream_props);
2513 gst_structure_free(props);
2516 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2518 switch (latency_mode) {
2519 case AUDIO_LATENCY_MODE_LOW:
2520 latency = g_strndup("low", 3);
2522 case AUDIO_LATENCY_MODE_MID:
2523 latency = g_strndup("mid", 3);
2525 case AUDIO_LATENCY_MODE_HIGH:
2526 latency = g_strndup("high", 4);
2530 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2534 LOGD("audiosink property - latency=%s", latency);
2536 MMPLAYER_FREEIF(latency);
2542 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2544 MMPlayerGstElement *audiobin = NULL;
2547 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2549 audiobin = player->pipeline->audiobin;
2551 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2552 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2555 if (player->video360_yaw_radians <= M_PI &&
2556 player->video360_yaw_radians >= -M_PI &&
2557 player->video360_pitch_radians <= M_PI_2 &&
2558 player->video360_pitch_radians >= -M_PI_2) {
2559 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2560 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2561 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2562 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", player->video360_metadata.init_view_heading,
2565 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2572 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2574 MMPlayerGstElement *audiobin = NULL;
2575 MMHandleType attrs = 0;
2576 GList *element_bucket = NULL;
2577 GstCaps *acaps = NULL;
2578 GstPad *sink_pad = NULL;
2581 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2582 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2584 audiobin = player->pipeline->audiobin;
2585 attrs = MMPLAYER_GET_ATTRS(player);
2587 if (player->build_audio_offload) { /* skip all the audio filters */
2588 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2589 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2590 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2591 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2596 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2598 /* replaygain volume */
2599 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2600 if (player->sound.rg_enable)
2601 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2603 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2606 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2608 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2609 gchar *dst_format = NULL;
2611 int dst_samplerate = 0;
2612 int dst_channels = 0;
2613 GstCaps *caps = NULL;
2614 char *caps_str = NULL;
2616 /* get conf. values */
2617 mm_attrs_multiple_get(player->attrs, NULL,
2618 "pcm_audioformat", &dst_format, &dst_len,
2619 "pcm_extraction_samplerate", &dst_samplerate,
2620 "pcm_extraction_channels", &dst_channels,
2623 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2626 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2627 caps = gst_caps_new_simple("audio/x-raw",
2628 "format", G_TYPE_STRING, dst_format,
2629 "rate", G_TYPE_INT, dst_samplerate,
2630 "channels", G_TYPE_INT, dst_channels,
2633 caps_str = gst_caps_to_string(caps);
2634 LOGD("new caps : %s", caps_str);
2636 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2639 gst_caps_unref(caps);
2640 MMPLAYER_FREEIF(caps_str);
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2644 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2646 /* raw pad handling signal, audiosink will be added after getting signal */
2647 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2648 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2652 /* normal playback */
2655 /* for logical volume control */
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2659 if (player->sound.mute) {
2660 LOGD("mute enabled");
2661 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2664 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2666 /* audio effect element. if audio effect is enabled */
2667 if ((strcmp(player->ini.audioeffect_element, ""))
2669 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2672 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2674 if ((!player->bypass_audio_effect)
2675 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2676 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2677 if (!_mmplayer_audio_effect_custom_apply(player))
2678 LOGI("apply audio effect(custom) setting success");
2682 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2683 && (player->set_mode.rich_audio))
2684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2687 /* create audio sink */
2688 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2689 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2690 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2692 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2693 if (player->is_360_feature_enabled &&
2694 player->is_content_spherical &&
2696 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2697 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2698 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2700 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2702 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2705 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2706 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2707 gst_caps_unref(acaps);
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2711 player->is_openal_plugin_used = TRUE;
2713 if (player->is_360_feature_enabled && player->is_content_spherical)
2714 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2718 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2719 (player->videodec_linked && player->ini.use_system_clock)) {
2720 LOGD("system clock will be used.");
2721 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2724 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2725 __mmplayer_gst_set_pulsesink_property(player, attrs);
2726 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2727 __mmplayer_gst_set_openalsink_property(player);
2730 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2733 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2734 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2735 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2736 gst_object_unref(GST_OBJECT(sink_pad));
2738 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2742 *bucket = element_bucket;
2745 return MM_ERROR_NONE;
2748 g_list_free(element_bucket);
2752 return MM_ERROR_PLAYER_INTERNAL;
2756 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2758 MMPlayerGstElement *first_element = NULL;
2759 MMPlayerGstElement *audiobin = NULL;
2761 GstPad *ghostpad = NULL;
2762 GList *element_bucket = NULL;
2766 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2769 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2771 LOGE("failed to allocate memory for audiobin");
2772 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2776 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2777 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2778 if (!audiobin[MMPLAYER_A_BIN].gst) {
2779 LOGE("failed to create audiobin");
2784 player->pipeline->audiobin = audiobin;
2786 /* create audio filters and audiosink */
2787 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2790 /* adding created elements to bin */
2791 LOGD("adding created elements to bin");
2792 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2795 /* linking elements in the bucket by added order. */
2796 LOGD("Linking elements in the bucket by added order.");
2797 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2800 /* get first element's sinkpad for creating ghostpad */
2801 first_element = (MMPlayerGstElement *)element_bucket->data;
2802 if (!first_element) {
2803 LOGE("failed to get first elem");
2807 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2809 LOGE("failed to get pad from first element of audiobin");
2813 ghostpad = gst_ghost_pad_new("sink", pad);
2815 LOGE("failed to create ghostpad");
2819 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2820 LOGE("failed to add ghostpad to audiobin");
2824 gst_object_unref(pad);
2826 g_list_free(element_bucket);
2829 return MM_ERROR_NONE;
2832 LOGD("ERROR : releasing audiobin");
2835 gst_object_unref(GST_OBJECT(pad));
2838 gst_object_unref(GST_OBJECT(ghostpad));
2841 g_list_free(element_bucket);
2843 /* release element which are not added to bin */
2844 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2845 /* NOTE : skip bin */
2846 if (audiobin[i].gst) {
2847 GstObject *parent = NULL;
2848 parent = gst_element_get_parent(audiobin[i].gst);
2851 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2852 audiobin[i].gst = NULL;
2854 gst_object_unref(GST_OBJECT(parent));
2858 /* release audiobin with it's childs */
2859 if (audiobin[MMPLAYER_A_BIN].gst)
2860 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2862 MMPLAYER_FREEIF(audiobin);
2864 player->pipeline->audiobin = NULL;
2866 return MM_ERROR_PLAYER_INTERNAL;
2870 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2872 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2876 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2878 int ret = MM_ERROR_NONE;
2880 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2881 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2883 MMPLAYER_VIDEO_BO_LOCK(player);
2885 if (player->video_bo_list) {
2886 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2887 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2888 if (tmp && tmp->bo == bo) {
2890 LOGD("release bo %p", bo);
2891 tbm_bo_unref(tmp->bo);
2892 MMPLAYER_VIDEO_BO_UNLOCK(player);
2893 MMPLAYER_VIDEO_BO_SIGNAL(player);
2898 /* hw codec is running or the list was reset for DRC. */
2899 LOGW("there is no bo list.");
2901 MMPLAYER_VIDEO_BO_UNLOCK(player);
2903 LOGW("failed to find bo %p", bo);
2908 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2913 MMPLAYER_RETURN_IF_FAIL(player);
2915 MMPLAYER_VIDEO_BO_LOCK(player);
2916 if (player->video_bo_list) {
2917 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2918 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2919 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2922 tbm_bo_unref(tmp->bo);
2926 g_list_free(player->video_bo_list);
2927 player->video_bo_list = NULL;
2929 player->video_bo_size = 0;
2930 MMPLAYER_VIDEO_BO_UNLOCK(player);
2937 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2940 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2941 gboolean ret = TRUE;
2943 /* check DRC, if it is, destroy the prev bo list to create again */
2944 if (player->video_bo_size != size) {
2945 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2946 __mmplayer_video_stream_destroy_bo_list(player);
2947 player->video_bo_size = size;
2950 MMPLAYER_VIDEO_BO_LOCK(player);
2952 if ((!player->video_bo_list) ||
2953 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2955 /* create bo list */
2957 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2959 if (player->video_bo_list) {
2960 /* if bo list did not created all, try it again. */
2961 idx = g_list_length(player->video_bo_list);
2962 LOGD("bo list exist(len: %d)", idx);
2965 for (; idx < player->ini.num_of_video_bo; idx++) {
2966 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2968 LOGE("Fail to alloc bo_info.");
2971 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2973 LOGE("Fail to tbm_bo_alloc.");
2974 MMPLAYER_FREEIF(bo_info);
2977 bo_info->used = FALSE;
2978 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2981 /* update video num buffers */
2982 player->video_num_buffers = idx;
2983 if (idx == player->ini.num_of_video_bo)
2984 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2987 MMPLAYER_VIDEO_BO_UNLOCK(player);
2991 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2995 /* get bo from list*/
2996 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2997 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2998 if (tmp && (tmp->used == FALSE)) {
2999 LOGD("found bo %p to use", tmp->bo);
3001 MMPLAYER_VIDEO_BO_UNLOCK(player);
3002 return tbm_bo_ref(tmp->bo);
3006 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3007 MMPLAYER_VIDEO_BO_UNLOCK(player);
3011 if (player->ini.video_bo_timeout <= 0) {
3012 MMPLAYER_VIDEO_BO_WAIT(player);
3014 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3015 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3022 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3024 mm_player_t *player = (mm_player_t *)data;
3026 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3028 /* send prerolled pkt */
3029 player->video_stream_prerolled = false;
3031 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3033 /* not to send prerolled pkt again */
3034 player->video_stream_prerolled = true;
3038 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3040 mm_player_t *player = (mm_player_t *)data;
3041 MMPlayerVideoStreamDataType *stream = NULL;
3042 GstMemory *mem = NULL;
3045 MMPLAYER_RETURN_IF_FAIL(player);
3046 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3048 if (player->video_stream_prerolled) {
3049 player->video_stream_prerolled = false;
3050 LOGD("skip the prerolled pkt not to send it again");
3054 /* clear stream data structure */
3055 stream = __mmplayer_create_stream_from_pad(pad);
3057 LOGE("failed to alloc stream");
3061 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3063 /* set size and timestamp */
3064 mem = gst_buffer_peek_memory(buffer, 0);
3065 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3066 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3068 /* check zero-copy */
3069 if (player->set_mode.video_zc &&
3070 player->set_mode.media_packet_video_stream &&
3071 gst_is_tizen_memory(mem)) {
3072 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3073 stream->internal_buffer = gst_buffer_ref(buffer);
3074 } else { /* sw codec */
3075 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3078 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3082 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3083 LOGE("failed to send video stream data.");
3090 LOGE("release video stream resource.");
3091 if (gst_is_tizen_memory(mem)) {
3093 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3095 tbm_bo_unref(stream->bo[i]);
3098 /* unref gst buffer */
3099 if (stream->internal_buffer)
3100 gst_buffer_unref(stream->internal_buffer);
3103 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3105 MMPLAYER_FREEIF(stream);
3110 __mmplayer_gst_set_video360_property(mm_player_t *player)
3112 MMPlayerGstElement *videobin = NULL;
3115 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3117 videobin = player->pipeline->videobin;
3119 /* Set spatial media metadata and/or user settings to the element.
3121 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3122 "projection-type", player->video360_metadata.projection_type, NULL);
3124 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3125 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3127 if (player->video360_metadata.full_pano_width_pixels &&
3128 player->video360_metadata.full_pano_height_pixels &&
3129 player->video360_metadata.cropped_area_image_width &&
3130 player->video360_metadata.cropped_area_image_height) {
3131 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3132 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3133 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3134 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3135 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3136 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3137 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3141 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3142 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3143 "horizontal-fov", player->video360_horizontal_fov,
3144 "vertical-fov", player->video360_vertical_fov, NULL);
3147 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3148 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3149 "zoom", 1.0f / player->video360_zoom, NULL);
3152 if (player->video360_yaw_radians <= M_PI &&
3153 player->video360_yaw_radians >= -M_PI &&
3154 player->video360_pitch_radians <= M_PI_2 &&
3155 player->video360_pitch_radians >= -M_PI_2) {
3156 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3157 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3158 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3159 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3160 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3161 "pose-yaw", player->video360_metadata.init_view_heading,
3162 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3165 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3166 "passthrough", !player->is_video360_enabled, NULL);
3173 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3175 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3176 GList *element_bucket = NULL;
3179 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3181 /* create video360 filter */
3182 if (player->is_360_feature_enabled && player->is_content_spherical) {
3183 LOGD("create video360 element");
3184 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3185 __mmplayer_gst_set_video360_property(player);
3189 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3190 LOGD("skip creating the videoconv and rotator");
3191 return MM_ERROR_NONE;
3194 /* in case of sw codec & overlay surface type, except 360 playback.
3195 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3196 LOGD("create video converter: %s", video_csc);
3197 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3199 /* set video rotator */
3200 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3203 *bucket = element_bucket;
3205 return MM_ERROR_NONE;
3207 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3208 g_list_free(element_bucket);
3212 return MM_ERROR_PLAYER_INTERNAL;
3216 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3218 gchar *factory_name = NULL;
3220 switch (surface_type) {
3221 case MM_DISPLAY_SURFACE_OVERLAY:
3222 if (strlen(player->ini.videosink_element_overlay) > 0)
3223 factory_name = player->ini.videosink_element_overlay;
3225 case MM_DISPLAY_SURFACE_REMOTE:
3226 case MM_DISPLAY_SURFACE_NULL:
3227 if (strlen(player->ini.videosink_element_fake) > 0)
3228 factory_name = player->ini.videosink_element_fake;
3231 LOGE("unidentified surface type");
3235 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3236 return factory_name;
3240 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3242 gchar *factory_name = NULL;
3243 MMPlayerGstElement *videobin = NULL;
3248 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3250 videobin = player->pipeline->videobin;
3251 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3253 attrs = MMPLAYER_GET_ATTRS(player);
3255 LOGE("cannot get content attribute");
3256 return MM_ERROR_PLAYER_INTERNAL;
3259 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3260 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3261 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3263 /* support shard memory with S/W codec on HawkP */
3264 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3265 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3266 "use-tbm", use_tbm, NULL);
3270 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3271 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3274 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3276 LOGD("disable last-sample");
3277 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3280 if (player->set_mode.media_packet_video_stream) {
3282 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3283 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3284 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3286 __mmplayer_add_signal_connection(player,
3287 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3288 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3290 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3293 __mmplayer_add_signal_connection(player,
3294 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3295 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3297 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3301 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3302 return MM_ERROR_PLAYER_INTERNAL;
3304 if (videobin[MMPLAYER_V_SINK].gst) {
3305 GstPad *sink_pad = NULL;
3306 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3308 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3309 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3310 gst_object_unref(GST_OBJECT(sink_pad));
3312 LOGE("failed to get sink pad from videosink");
3316 return MM_ERROR_NONE;
3321 * - video overlay surface(arm/x86) : tizenwlsink
3324 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3327 GList *element_bucket = NULL;
3328 MMPlayerGstElement *first_element = NULL;
3329 MMPlayerGstElement *videobin = NULL;
3330 gchar *videosink_factory_name = NULL;
3333 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3336 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3338 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3340 player->pipeline->videobin = videobin;
3343 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3344 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3345 if (!videobin[MMPLAYER_V_BIN].gst) {
3346 LOGE("failed to create videobin");
3350 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3353 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3354 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3356 /* additional setting for sink plug-in */
3357 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3358 LOGE("failed to set video property");
3362 /* store it as it's sink element */
3363 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3365 /* adding created elements to bin */
3366 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3367 LOGE("failed to add elements");
3371 /* Linking elements in the bucket by added order */
3372 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3373 LOGE("failed to link elements");
3377 /* get first element's sinkpad for creating ghostpad */
3378 first_element = (MMPlayerGstElement *)element_bucket->data;
3379 if (!first_element) {
3380 LOGE("failed to get first element from bucket");
3384 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3386 LOGE("failed to get pad from first element");
3390 /* create ghostpad */
3391 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3392 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3393 LOGE("failed to add ghostpad to videobin");
3396 gst_object_unref(pad);
3398 /* done. free allocated variables */
3399 g_list_free(element_bucket);
3403 return MM_ERROR_NONE;
3406 LOGE("ERROR : releasing videobin");
3407 g_list_free(element_bucket);
3410 gst_object_unref(GST_OBJECT(pad));
3412 /* release videobin with it's childs */
3413 if (videobin[MMPLAYER_V_BIN].gst)
3414 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3416 MMPLAYER_FREEIF(videobin);
3417 player->pipeline->videobin = NULL;
3419 return MM_ERROR_PLAYER_INTERNAL;
3423 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3425 GList *element_bucket = NULL;
3426 MMPlayerGstElement *textbin = player->pipeline->textbin;
3428 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3429 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3430 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3431 "signal-handoffs", FALSE,
3434 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3435 __mmplayer_add_signal_connection(player,
3436 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3437 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3439 G_CALLBACK(__mmplayer_update_subtitle),
3442 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3443 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3445 if (!player->play_subtitle) {
3446 LOGD("add textbin sink as sink element of whole pipeline.");
3447 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3450 /* adding created elements to bin */
3451 LOGD("adding created elements to bin");
3452 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3453 LOGE("failed to add elements");
3457 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3458 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3459 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3461 /* linking elements in the bucket by added order. */
3462 LOGD("Linking elements in the bucket by added order.");
3463 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3464 LOGE("failed to link elements");
3468 /* done. free allocated variables */
3469 g_list_free(element_bucket);
3471 if (textbin[MMPLAYER_T_QUEUE].gst) {
3473 GstPad *ghostpad = NULL;
3475 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3477 LOGE("failed to get sink pad of text queue");
3481 ghostpad = gst_ghost_pad_new("text_sink", pad);
3482 gst_object_unref(pad);
3485 LOGE("failed to create ghostpad of textbin");
3489 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3490 LOGE("failed to add ghostpad to textbin");
3491 gst_object_unref(ghostpad);
3496 return MM_ERROR_NONE;
3499 g_list_free(element_bucket);
3501 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3502 LOGE("remove textbin sink from sink list");
3503 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3506 /* release element at __mmplayer_gst_create_text_sink_bin */
3507 return MM_ERROR_PLAYER_INTERNAL;
3511 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3513 MMPlayerGstElement *textbin = NULL;
3514 GList *element_bucket = NULL;
3515 int surface_type = 0;
3520 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3523 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3525 LOGE("failed to allocate memory for textbin");
3526 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3530 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3531 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3532 if (!textbin[MMPLAYER_T_BIN].gst) {
3533 LOGE("failed to create textbin");
3538 player->pipeline->textbin = textbin;
3541 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3542 LOGD("surface type for subtitle : %d", surface_type);
3543 switch (surface_type) {
3544 case MM_DISPLAY_SURFACE_OVERLAY:
3545 case MM_DISPLAY_SURFACE_NULL:
3546 case MM_DISPLAY_SURFACE_REMOTE:
3547 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3548 LOGE("failed to make plain text elements");
3559 return MM_ERROR_NONE;
3563 LOGD("ERROR : releasing textbin");
3565 g_list_free(element_bucket);
3567 /* release signal */
3568 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3570 /* release element which are not added to bin */
3571 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3572 /* NOTE : skip bin */
3573 if (textbin[i].gst) {
3574 GstObject *parent = NULL;
3575 parent = gst_element_get_parent(textbin[i].gst);
3578 gst_object_unref(GST_OBJECT(textbin[i].gst));
3579 textbin[i].gst = NULL;
3581 gst_object_unref(GST_OBJECT(parent));
3586 /* release textbin with it's childs */
3587 if (textbin[MMPLAYER_T_BIN].gst)
3588 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3590 MMPLAYER_FREEIF(player->pipeline->textbin);
3591 player->pipeline->textbin = NULL;
3594 return MM_ERROR_PLAYER_INTERNAL;
3598 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3600 MMPlayerGstElement *mainbin = NULL;
3601 MMPlayerGstElement *textbin = NULL;
3602 MMHandleType attrs = 0;
3603 GstElement *subsrc = NULL;
3604 GstElement *subparse = NULL;
3605 gchar *subtitle_uri = NULL;
3606 const gchar *charset = NULL;
3612 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3614 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3616 mainbin = player->pipeline->mainbin;
3618 attrs = MMPLAYER_GET_ATTRS(player);
3620 LOGE("cannot get content attribute");
3621 return MM_ERROR_PLAYER_INTERNAL;
3624 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3625 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3626 LOGE("subtitle uri is not proper filepath.");
3627 return MM_ERROR_PLAYER_INVALID_URI;
3630 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3631 LOGE("failed to get storage info of subtitle path");
3632 return MM_ERROR_PLAYER_INVALID_URI;
3635 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3637 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3638 player->subtitle_language_list = NULL;
3639 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3641 /* create the subtitle source */
3642 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3644 LOGE("failed to create filesrc element");
3647 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3649 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3650 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3652 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3653 LOGW("failed to add queue");
3654 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3655 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3656 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3661 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3663 LOGE("failed to create subparse element");
3667 charset = util_get_charset(subtitle_uri);
3669 LOGD("detected charset is %s", charset);
3670 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3673 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3674 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3676 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3677 LOGW("failed to add subparse");
3678 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3679 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3680 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3684 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3685 LOGW("failed to link subsrc and subparse");
3689 player->play_subtitle = TRUE;
3690 player->adjust_subtitle_pos = 0;
3692 LOGD("play subtitle using subtitle file");
3694 if (player->pipeline->textbin == NULL) {
3695 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3696 LOGE("failed to create text sink bin. continuing without text");
3700 textbin = player->pipeline->textbin;
3702 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3703 LOGW("failed to add textbin");
3705 /* release signal */
3706 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3708 /* release textbin with it's childs */
3709 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3710 MMPLAYER_FREEIF(player->pipeline->textbin);
3711 player->pipeline->textbin = textbin = NULL;
3715 LOGD("link text input selector and textbin ghost pad");
3717 player->textsink_linked = 1;
3718 player->external_text_idx = 0;
3719 LOGI("textsink is linked");
3721 textbin = player->pipeline->textbin;
3722 LOGD("text bin has been created. reuse it.");
3723 player->external_text_idx = 1;
3726 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3727 LOGW("failed to link subparse and textbin");
3731 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3733 LOGE("failed to get sink pad from textsink to probe data");
3737 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3738 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3740 gst_object_unref(pad);
3743 /* create dot. for debugging */
3744 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3747 return MM_ERROR_NONE;
3750 /* release text pipeline resource */
3751 player->textsink_linked = 0;
3753 /* release signal */
3754 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3756 if (player->pipeline->textbin) {
3757 LOGE("remove textbin");
3759 /* release textbin with it's childs */
3760 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3761 MMPLAYER_FREEIF(player->pipeline->textbin);
3762 player->pipeline->textbin = NULL;
3766 /* release subtitle elem */
3767 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3768 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3770 return MM_ERROR_PLAYER_INTERNAL;
3774 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3776 mm_player_t *player = (mm_player_t *)data;
3777 MMMessageParamType msg = {0, };
3778 GstClockTime duration = 0;
3779 gpointer text = NULL;
3780 guint text_size = 0;
3781 gboolean ret = TRUE;
3782 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3786 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3787 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3789 if (player->is_subtitle_force_drop) {
3790 LOGW("subtitle is dropped forcedly.");
3794 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3795 text = mapinfo.data;
3796 text_size = mapinfo.size;
3797 duration = GST_BUFFER_DURATION(buffer);
3799 if (player->set_mode.subtitle_off) {
3800 LOGD("subtitle is OFF.");
3804 if (!text || (text_size == 0)) {
3805 LOGD("There is no subtitle to be displayed.");
3809 msg.data = (void *)text;
3810 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3812 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3814 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3815 gst_buffer_unmap(buffer, &mapinfo);
3822 static GstPadProbeReturn
3823 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3825 mm_player_t *player = (mm_player_t *)u_data;
3826 GstClockTime cur_timestamp = 0;
3827 gint64 adjusted_timestamp = 0;
3828 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3830 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3832 if (player->set_mode.subtitle_off) {
3833 LOGD("subtitle is OFF.");
3837 if (player->adjust_subtitle_pos == 0) {
3838 LOGD("nothing to do");
3842 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3843 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3845 if (adjusted_timestamp < 0) {
3846 LOGD("adjusted_timestamp under zero");
3851 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3852 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3853 GST_TIME_ARGS(cur_timestamp),
3854 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3856 return GST_PAD_PROBE_OK;
3860 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3864 /* check player and subtitlebin are created */
3865 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3866 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3868 if (position == 0) {
3869 LOGD("nothing to do");
3871 return MM_ERROR_NONE;
3875 case MM_PLAYER_POS_FORMAT_TIME:
3877 /* check current postion */
3878 player->adjust_subtitle_pos = position;
3880 LOGD("save adjust_subtitle_pos in player") ;
3886 LOGW("invalid format.");
3888 return MM_ERROR_INVALID_ARGUMENT;
3894 return MM_ERROR_NONE;
3898 * This function is to create audio or video pipeline for playing.
3900 * @param player [in] handle of player
3902 * @return This function returns zero on success.
3907 __mmplayer_gst_create_pipeline(mm_player_t *player)
3909 int ret = MM_ERROR_NONE;
3910 MMPlayerGstElement *mainbin = NULL;
3911 MMHandleType attrs = 0;
3914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3916 /* get profile attribute */
3917 attrs = MMPLAYER_GET_ATTRS(player);
3919 LOGE("failed to get content attribute");
3923 /* create pipeline handles */
3924 if (player->pipeline) {
3925 LOGE("pipeline should be released before create new one");
3929 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3930 if (player->pipeline == NULL)
3933 /* create mainbin */
3934 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3935 if (mainbin == NULL)
3938 /* create pipeline */
3939 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3940 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3941 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3942 LOGE("failed to create pipeline");
3947 player->pipeline->mainbin = mainbin;
3949 /* create the source and decoder elements */
3950 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3951 ret = __mmplayer_gst_build_es_pipeline(player);
3953 ret = __mmplayer_gst_build_pipeline(player);
3955 if (ret != MM_ERROR_NONE) {
3956 LOGE("failed to create some elements");
3960 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3961 if (__mmplayer_check_subtitle(player)
3962 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3963 LOGE("failed to create text pipeline");
3966 ret = __mmplayer_gst_add_bus_watch(player);
3967 if (ret != MM_ERROR_NONE) {
3968 LOGE("failed to add bus watch");
3973 return MM_ERROR_NONE;
3976 __mmplayer_gst_destroy_pipeline(player);
3977 return MM_ERROR_PLAYER_INTERNAL;
3981 __mmplayer_reset_gapless_state(mm_player_t *player)
3984 MMPLAYER_RETURN_IF_FAIL(player
3986 && player->pipeline->audiobin
3987 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3989 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
3996 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
3999 int ret = MM_ERROR_NONE;
4003 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4005 /* cleanup stuffs */
4006 MMPLAYER_FREEIF(player->type);
4007 player->no_more_pad = FALSE;
4008 player->num_dynamic_pad = 0;
4009 player->demux_pad_index = 0;
4011 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4012 player->subtitle_language_list = NULL;
4013 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4015 __mmplayer_reset_gapless_state(player);
4017 if (player->streamer) {
4018 __mm_player_streaming_initialize(player->streamer, FALSE);
4019 __mm_player_streaming_destroy(player->streamer);
4020 player->streamer = NULL;
4023 /* cleanup unlinked mime type */
4024 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4025 MMPLAYER_FREEIF(player->unlinked_video_mime);
4026 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4028 /* cleanup running stuffs */
4029 __mmplayer_cancel_eos_timer(player);
4031 /* cleanup gst stuffs */
4032 if (player->pipeline) {
4033 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4034 GstTagList *tag_list = player->pipeline->tag_list;
4036 /* first we need to disconnect all signal hander */
4037 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4040 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4041 MMPlayerGstElement *videobin = player->pipeline->videobin;
4042 MMPlayerGstElement *textbin = player->pipeline->textbin;
4043 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4044 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4045 gst_object_unref(bus);
4047 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4048 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4049 if (ret != MM_ERROR_NONE) {
4050 LOGE("fail to change state to NULL");
4051 return MM_ERROR_PLAYER_INTERNAL;
4054 LOGW("succeeded in changing state to NULL");
4056 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4059 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4060 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4062 /* free avsysaudiosink
4063 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4064 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4066 MMPLAYER_FREEIF(audiobin);
4067 MMPLAYER_FREEIF(videobin);
4068 MMPLAYER_FREEIF(textbin);
4069 MMPLAYER_FREEIF(mainbin);
4073 gst_tag_list_unref(tag_list);
4075 MMPLAYER_FREEIF(player->pipeline);
4077 MMPLAYER_FREEIF(player->album_art);
4079 if (player->v_stream_caps) {
4080 gst_caps_unref(player->v_stream_caps);
4081 player->v_stream_caps = NULL;
4084 if (player->a_stream_caps) {
4085 gst_caps_unref(player->a_stream_caps);
4086 player->a_stream_caps = NULL;
4089 if (player->s_stream_caps) {
4090 gst_caps_unref(player->s_stream_caps);
4091 player->s_stream_caps = NULL;
4093 __mmplayer_track_destroy(player);
4095 if (player->sink_elements)
4096 g_list_free(player->sink_elements);
4097 player->sink_elements = NULL;
4099 if (player->bufmgr) {
4100 tbm_bufmgr_deinit(player->bufmgr);
4101 player->bufmgr = NULL;
4104 LOGW("finished destroy pipeline");
4112 __mmplayer_gst_realize(mm_player_t *player)
4115 int ret = MM_ERROR_NONE;
4119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4121 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4123 ret = __mmplayer_gst_create_pipeline(player);
4125 LOGE("failed to create pipeline");
4129 /* set pipeline state to READY */
4130 /* NOTE : state change to READY must be performed sync. */
4131 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4132 ret = __mmplayer_gst_set_state(player,
4133 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4135 if (ret != MM_ERROR_NONE) {
4136 /* return error if failed to set state */
4137 LOGE("failed to set READY state");
4141 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4143 /* create dot before error-return. for debugging */
4144 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4152 __mmplayer_gst_unrealize(mm_player_t *player)
4154 int ret = MM_ERROR_NONE;
4158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4160 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4161 MMPLAYER_PRINT_STATE(player);
4163 /* release miscellaneous information */
4164 __mmplayer_release_misc(player);
4166 /* destroy pipeline */
4167 ret = __mmplayer_gst_destroy_pipeline(player);
4168 if (ret != MM_ERROR_NONE) {
4169 LOGE("failed to destory pipeline");
4173 /* release miscellaneous information.
4174 these info needs to be released after pipeline is destroyed. */
4175 __mmplayer_release_misc_post(player);
4177 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4185 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4190 LOGW("set_message_callback is called with invalid player handle");
4191 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4194 player->msg_cb = callback;
4195 player->msg_cb_param = user_param;
4197 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4201 return MM_ERROR_NONE;
4205 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4207 int ret = MM_ERROR_NONE;
4212 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4213 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4214 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4216 memset(data, 0, sizeof(MMPlayerParseProfile));
4218 if (strstr(uri, "es_buff://")) {
4219 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4220 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4221 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4222 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4224 tmp = g_ascii_strdown(uri, strlen(uri));
4225 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4226 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4228 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4230 } else if (strstr(uri, "mms://")) {
4231 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4232 } else if ((path = strstr(uri, "mem://"))) {
4233 ret = __mmplayer_set_mem_uri(data, path, param);
4235 ret = __mmplayer_set_file_uri(data, uri);
4238 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4239 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4240 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4241 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4243 /* dump parse result */
4244 SECURE_LOGW("incoming uri : %s", uri);
4245 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4246 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4254 __mmplayer_can_do_interrupt(mm_player_t *player)
4256 if (!player || !player->pipeline || !player->attrs) {
4257 LOGW("not initialized");
4261 if (player->audio_stream_render_cb) {
4262 LOGW("not support in pcm extraction mode");
4266 /* check if seeking */
4267 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4268 MMMessageParamType msg_param;
4269 memset(&msg_param, 0, sizeof(MMMessageParamType));
4270 msg_param.code = MM_ERROR_PLAYER_SEEK;
4271 player->seek_state = MMPLAYER_SEEK_NONE;
4272 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4276 /* check other thread */
4277 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4278 LOGW("locked already, cmd state : %d", player->cmd);
4280 /* check application command */
4281 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4282 LOGW("playing.. should wait cmd lock then, will be interrupted");
4284 /* lock will be released at mrp_resource_release_cb() */
4285 MMPLAYER_CMD_LOCK(player);
4288 LOGW("nothing to do");
4291 LOGW("can interrupt immediately");
4295 FAILED: /* with CMD UNLOCKED */
4298 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4303 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4306 mm_player_t *player = NULL;
4310 if (user_data == NULL) {
4311 LOGE("- user_data is null");
4314 player = (mm_player_t *)user_data;
4316 /* do something to release resource here.
4317 * player stop and interrupt forwarding */
4318 if (!__mmplayer_can_do_interrupt(player)) {
4319 LOGW("no need to interrupt, so leave");
4321 MMMessageParamType msg = {0, };
4324 player->interrupted_by_resource = TRUE;
4326 /* get last play position */
4327 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4328 LOGW("failed to get play position.");
4330 msg.union_type = MM_MSG_UNION_TIME;
4331 msg.time.elapsed = pos;
4332 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4334 LOGD("video resource conflict so, resource will be freed by unrealizing");
4335 if (_mmplayer_unrealize((MMHandleType)player))
4336 LOGW("failed to unrealize");
4338 /* lock is called in __mmplayer_can_do_interrupt() */
4339 MMPLAYER_CMD_UNLOCK(player);
4342 if (res == player->video_overlay_resource)
4343 player->video_overlay_resource = FALSE;
4345 player->video_decoder_resource = FALSE;
4353 __mmplayer_initialize_video_roi(mm_player_t *player)
4355 player->video_roi.scale_x = 0.0;
4356 player->video_roi.scale_y = 0.0;
4357 player->video_roi.scale_width = 1.0;
4358 player->video_roi.scale_height = 1.0;
4362 _mmplayer_create_player(MMHandleType handle)
4364 int ret = MM_ERROR_PLAYER_INTERNAL;
4365 bool enabled = false;
4367 mm_player_t *player = MM_PLAYER_CAST(handle);
4371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4373 /* initialize player state */
4374 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4375 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4376 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4377 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4379 /* check current state */
4380 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4382 /* construct attributes */
4383 player->attrs = _mmplayer_construct_attribute(handle);
4385 if (!player->attrs) {
4386 LOGE("Failed to construct attributes");
4390 /* initialize gstreamer with configured parameter */
4391 if (!__mmplayer_init_gstreamer(player)) {
4392 LOGE("Initializing gstreamer failed");
4393 _mmplayer_deconstruct_attribute(handle);
4397 /* create lock. note that g_tread_init() has already called in gst_init() */
4398 g_mutex_init(&player->fsink_lock);
4400 /* create update tag lock */
4401 g_mutex_init(&player->update_tag_lock);
4403 /* create gapless play mutex */
4404 g_mutex_init(&player->gapless_play_thread_mutex);
4406 /* create gapless play cond */
4407 g_cond_init(&player->gapless_play_thread_cond);
4409 /* create gapless play thread */
4410 player->gapless_play_thread =
4411 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4412 if (!player->gapless_play_thread) {
4413 LOGE("failed to create gapless play thread");
4414 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4415 g_mutex_clear(&player->gapless_play_thread_mutex);
4416 g_cond_clear(&player->gapless_play_thread_cond);
4420 player->bus_msg_q = g_queue_new();
4421 if (!player->bus_msg_q) {
4422 LOGE("failed to create queue for bus_msg");
4423 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4427 ret = _mmplayer_initialize_video_capture(player);
4428 if (ret != MM_ERROR_NONE) {
4429 LOGE("failed to initialize video capture");
4433 /* initialize resource manager */
4434 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4435 __resource_release_cb, player, &player->resource_manager)
4436 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4437 LOGE("failed to initialize resource manager");
4438 ret = MM_ERROR_PLAYER_INTERNAL;
4442 /* create video bo lock and cond */
4443 g_mutex_init(&player->video_bo_mutex);
4444 g_cond_init(&player->video_bo_cond);
4446 /* create media stream callback mutex */
4447 g_mutex_init(&player->media_stream_cb_lock);
4449 /* create subtitle info lock and cond */
4450 g_mutex_init(&player->subtitle_info_mutex);
4451 g_cond_init(&player->subtitle_info_cond);
4453 player->streaming_type = STREAMING_SERVICE_NONE;
4455 /* give default value of audio effect setting */
4456 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4457 player->sound.rg_enable = false;
4458 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4460 player->play_subtitle = FALSE;
4461 player->has_closed_caption = FALSE;
4462 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4463 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4464 player->pending_resume = FALSE;
4465 if (player->ini.dump_element_keyword[0][0] == '\0')
4466 player->ini.set_dump_element_flag = FALSE;
4468 player->ini.set_dump_element_flag = TRUE;
4470 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4471 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4472 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4474 /* Set video360 settings to their defaults for just-created player.
4477 player->is_360_feature_enabled = FALSE;
4478 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4479 LOGI("spherical feature info: %d", enabled);
4481 player->is_360_feature_enabled = TRUE;
4483 LOGE("failed to get spherical feature info");
4486 player->is_content_spherical = FALSE;
4487 player->is_video360_enabled = TRUE;
4488 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4489 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4490 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4491 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4492 player->video360_zoom = 1.0f;
4493 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4494 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4496 __mmplayer_initialize_video_roi(player);
4498 /* set player state to null */
4499 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4500 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4504 return MM_ERROR_NONE;
4508 g_mutex_clear(&player->fsink_lock);
4509 /* free update tag lock */
4510 g_mutex_clear(&player->update_tag_lock);
4511 g_queue_free(player->bus_msg_q);
4512 /* free gapless play thread */
4513 if (player->gapless_play_thread) {
4514 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4515 player->gapless_play_thread_exit = TRUE;
4516 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4517 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4519 g_thread_join(player->gapless_play_thread);
4520 player->gapless_play_thread = NULL;
4522 g_mutex_clear(&player->gapless_play_thread_mutex);
4523 g_cond_clear(&player->gapless_play_thread_cond);
4526 /* release attributes */
4527 _mmplayer_deconstruct_attribute(handle);
4535 __mmplayer_init_gstreamer(mm_player_t *player)
4537 static gboolean initialized = FALSE;
4538 static const int max_argc = 50;
4540 gchar **argv = NULL;
4541 gchar **argv2 = NULL;
4547 LOGD("gstreamer already initialized.");
4552 argc = malloc(sizeof(int));
4553 argv = malloc(sizeof(gchar *) * max_argc);
4554 argv2 = malloc(sizeof(gchar *) * max_argc);
4556 if (!argc || !argv || !argv2)
4559 memset(argv, 0, sizeof(gchar *) * max_argc);
4560 memset(argv2, 0, sizeof(gchar *) * max_argc);
4564 argv[0] = g_strdup("mmplayer");
4567 for (i = 0; i < 5; i++) {
4568 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4569 if (strlen(player->ini.gst_param[i]) > 0) {
4570 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4575 /* we would not do fork for scanning plugins */
4576 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4579 /* check disable registry scan */
4580 if (player->ini.skip_rescan) {
4581 argv[*argc] = g_strdup("--gst-disable-registry-update");
4585 /* check disable segtrap */
4586 if (player->ini.disable_segtrap) {
4587 argv[*argc] = g_strdup("--gst-disable-segtrap");
4591 LOGD("initializing gstreamer with following parameter");
4592 LOGD("argc : %d", *argc);
4595 for (i = 0; i < arg_count; i++) {
4597 LOGD("argv[%d] : %s", i, argv2[i]);
4600 /* initializing gstreamer */
4601 if (!gst_init_check(argc, &argv, &err)) {
4602 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4609 for (i = 0; i < arg_count; i++) {
4610 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4611 MMPLAYER_FREEIF(argv2[i]);
4614 MMPLAYER_FREEIF(argv);
4615 MMPLAYER_FREEIF(argv2);
4616 MMPLAYER_FREEIF(argc);
4626 for (i = 0; i < arg_count; i++) {
4627 LOGD("free[%d] : %s", i, argv2[i]);
4628 MMPLAYER_FREEIF(argv2[i]);
4631 MMPLAYER_FREEIF(argv);
4632 MMPLAYER_FREEIF(argv2);
4633 MMPLAYER_FREEIF(argc);
4639 __mmplayer_check_async_state_transition(mm_player_t *player)
4641 GstState element_state = GST_STATE_VOID_PENDING;
4642 GstState element_pending_state = GST_STATE_VOID_PENDING;
4643 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4644 GstElement *element = NULL;
4645 gboolean async = FALSE;
4647 /* check player handle */
4648 MMPLAYER_RETURN_IF_FAIL(player &&
4650 player->pipeline->mainbin &&
4651 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4654 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4656 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4657 LOGD("don't need to check the pipeline state");
4661 MMPLAYER_PRINT_STATE(player);
4663 /* wait for state transition */
4664 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4665 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4667 if (ret == GST_STATE_CHANGE_FAILURE) {
4668 LOGE(" [%s] state : %s pending : %s",
4669 GST_ELEMENT_NAME(element),
4670 gst_element_state_get_name(element_state),
4671 gst_element_state_get_name(element_pending_state));
4673 /* dump state of all element */
4674 __mmplayer_dump_pipeline_state(player);
4679 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4684 _mmplayer_destroy(MMHandleType handle)
4686 mm_player_t *player = MM_PLAYER_CAST(handle);
4690 /* check player handle */
4691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4693 /* destroy can called at anytime */
4694 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4696 /* check async state transition */
4697 __mmplayer_check_async_state_transition(player);
4699 /* release gapless play thread */
4700 if (player->gapless_play_thread) {
4701 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4702 player->gapless_play_thread_exit = TRUE;
4703 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4704 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4706 LOGD("waitting for gapless play thread exit");
4707 g_thread_join(player->gapless_play_thread);
4708 g_mutex_clear(&player->gapless_play_thread_mutex);
4709 g_cond_clear(&player->gapless_play_thread_cond);
4710 LOGD("gapless play thread released");
4713 _mmplayer_release_video_capture(player);
4715 /* de-initialize resource manager */
4716 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4717 player->resource_manager))
4718 LOGE("failed to deinitialize resource manager");
4720 /* release pipeline */
4721 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4722 LOGE("failed to destory pipeline");
4723 return MM_ERROR_PLAYER_INTERNAL;
4726 g_queue_free(player->bus_msg_q);
4728 /* release subtitle info lock and cond */
4729 g_mutex_clear(&player->subtitle_info_mutex);
4730 g_cond_clear(&player->subtitle_info_cond);
4732 __mmplayer_release_dump_list(player->dump_list);
4734 /* release miscellaneous information */
4735 __mmplayer_release_misc(player);
4737 /* release miscellaneous information.
4738 these info needs to be released after pipeline is destroyed. */
4739 __mmplayer_release_misc_post(player);
4741 /* release attributes */
4742 _mmplayer_deconstruct_attribute(handle);
4745 g_mutex_clear(&player->fsink_lock);
4748 g_mutex_clear(&player->update_tag_lock);
4750 /* release video bo lock and cond */
4751 g_mutex_clear(&player->video_bo_mutex);
4752 g_cond_clear(&player->video_bo_cond);
4754 /* release media stream callback lock */
4755 g_mutex_clear(&player->media_stream_cb_lock);
4759 return MM_ERROR_NONE;
4763 _mmplayer_realize(MMHandleType hplayer)
4765 mm_player_t *player = (mm_player_t *)hplayer;
4768 MMHandleType attrs = 0;
4769 int ret = MM_ERROR_NONE;
4773 /* check player handle */
4774 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4776 /* check current state */
4777 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4779 attrs = MMPLAYER_GET_ATTRS(player);
4781 LOGE("fail to get attributes.");
4782 return MM_ERROR_PLAYER_INTERNAL;
4784 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4785 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4787 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4788 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4790 if (ret != MM_ERROR_NONE) {
4791 LOGE("failed to parse profile");
4796 if (uri && (strstr(uri, "es_buff://"))) {
4797 if (strstr(uri, "es_buff://push_mode"))
4798 player->es_player_push_mode = TRUE;
4800 player->es_player_push_mode = FALSE;
4803 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4804 LOGW("mms protocol is not supported format.");
4805 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4808 if (MMPLAYER_IS_STREAMING(player))
4809 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4811 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4813 player->smooth_streaming = FALSE;
4814 player->videodec_linked = 0;
4815 player->audiodec_linked = 0;
4816 player->textsink_linked = 0;
4817 player->is_external_subtitle_present = FALSE;
4818 player->is_external_subtitle_added_now = FALSE;
4819 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4820 player->video360_metadata.is_spherical = -1;
4821 player->is_openal_plugin_used = FALSE;
4822 player->demux_pad_index = 0;
4823 player->subtitle_language_list = NULL;
4824 player->is_subtitle_force_drop = FALSE;
4825 player->last_multiwin_status = FALSE;
4827 __mmplayer_track_initialize(player);
4828 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4830 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4831 gint prebuffer_ms = 0, rebuffer_ms = 0;
4833 player->streamer = __mm_player_streaming_create();
4834 __mm_player_streaming_initialize(player->streamer, TRUE);
4836 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4837 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4839 if (prebuffer_ms > 0) {
4840 prebuffer_ms = MAX(prebuffer_ms, 1000);
4841 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4844 if (rebuffer_ms > 0) {
4845 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4846 rebuffer_ms = MAX(rebuffer_ms, 1000);
4847 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4850 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4851 player->streamer->buffering_req.rebuffer_time);
4854 /* realize pipeline */
4855 ret = __mmplayer_gst_realize(player);
4856 if (ret != MM_ERROR_NONE)
4857 LOGE("fail to realize the player.");
4859 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4867 _mmplayer_unrealize(MMHandleType hplayer)
4869 mm_player_t *player = (mm_player_t *)hplayer;
4870 int ret = MM_ERROR_NONE;
4874 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4876 MMPLAYER_CMD_UNLOCK(player);
4877 /* destroy the gst bus msg thread which is created during realize.
4878 this funct have to be called before getting cmd lock. */
4879 __mmplayer_bus_msg_thread_destroy(player);
4880 MMPLAYER_CMD_LOCK(player);
4882 /* check current state */
4883 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4885 /* check async state transition */
4886 __mmplayer_check_async_state_transition(player);
4888 /* unrealize pipeline */
4889 ret = __mmplayer_gst_unrealize(player);
4891 /* set asm stop if success */
4892 if (MM_ERROR_NONE == ret) {
4893 if (!player->interrupted_by_resource) {
4894 if (player->video_decoder_resource != NULL) {
4895 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4896 player->video_decoder_resource);
4897 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4898 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4900 player->video_decoder_resource = NULL;
4903 if (player->video_overlay_resource != NULL) {
4904 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4905 player->video_overlay_resource);
4906 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4907 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4909 player->video_overlay_resource = NULL;
4912 ret = mm_resource_manager_commit(player->resource_manager);
4913 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4914 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4917 LOGE("failed and don't change asm state to stop");
4925 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4927 mm_player_t *player = (mm_player_t *)hplayer;
4929 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4931 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4935 _mmplayer_get_state(MMHandleType hplayer, int *state)
4937 mm_player_t *player = (mm_player_t *)hplayer;
4939 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4941 *state = MMPLAYER_CURRENT_STATE(player);
4943 return MM_ERROR_NONE;
4948 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4950 mm_player_t *player = (mm_player_t *)hplayer;
4951 GstElement *vol_element = NULL;
4956 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4958 LOGD("volume [L]=%f:[R]=%f",
4959 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4961 /* invalid factor range or not */
4962 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4963 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4964 LOGE("Invalid factor!(valid factor:0~1.0)");
4965 return MM_ERROR_INVALID_ARGUMENT;
4969 /* not support to set other value into each channel */
4970 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4971 return MM_ERROR_INVALID_ARGUMENT;
4973 /* Save volume to handle. Currently the first array element will be saved. */
4974 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
4976 /* check pipeline handle */
4977 if (!player->pipeline || !player->pipeline->audiobin) {
4978 LOGD("audiobin is not created yet");
4979 LOGD("but, current stored volume will be set when it's created.");
4981 /* NOTE : stored volume will be used in create_audiobin
4982 * returning MM_ERROR_NONE here makes application to able to
4983 * set volume at anytime.
4985 return MM_ERROR_NONE;
4988 /* setting volume to volume element */
4989 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
4992 LOGD("volume is set [%f]", player->sound.volume);
4993 g_object_set(vol_element, "volume", player->sound.volume, NULL);
4998 return MM_ERROR_NONE;
5002 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5004 mm_player_t *player = (mm_player_t *)hplayer;
5009 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5010 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5012 /* returning stored volume */
5013 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5014 volume->level[i] = player->sound.volume;
5018 return MM_ERROR_NONE;
5022 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5024 mm_player_t *player = (mm_player_t *)hplayer;
5025 GstElement *vol_element = NULL;
5029 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5031 /* mute value shoud 0 or 1 */
5032 if (mute != 0 && mute != 1) {
5033 LOGE("bad mute value");
5035 /* FIXIT : definitly, we need _BAD_PARAM error code */
5036 return MM_ERROR_INVALID_ARGUMENT;
5039 player->sound.mute = mute;
5041 /* just hold mute value if pipeline is not ready */
5042 if (!player->pipeline || !player->pipeline->audiobin) {
5043 LOGD("pipeline is not ready. holding mute value");
5044 return MM_ERROR_NONE;
5047 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5049 /* NOTE : volume will only created when the bt is enabled */
5051 LOGD("mute : %d", mute);
5052 g_object_set(vol_element, "mute", mute, NULL);
5054 LOGD("volume elemnet is not created. using volume in audiosink");
5058 return MM_ERROR_NONE;
5062 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5064 mm_player_t *player = (mm_player_t *)hplayer;
5068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5069 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5071 /* just hold mute value if pipeline is not ready */
5072 if (!player->pipeline || !player->pipeline->audiobin) {
5073 LOGD("pipeline is not ready. returning stored value");
5074 *pmute = player->sound.mute;
5075 return MM_ERROR_NONE;
5078 *pmute = player->sound.mute;
5082 return MM_ERROR_NONE;
5086 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5088 mm_player_t *player = (mm_player_t *)hplayer;
5092 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5094 player->video_stream_changed_cb = callback;
5095 player->video_stream_changed_cb_user_param = user_param;
5096 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5100 return MM_ERROR_NONE;
5104 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5106 mm_player_t *player = (mm_player_t *)hplayer;
5110 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5112 player->audio_stream_changed_cb = callback;
5113 player->audio_stream_changed_cb_user_param = user_param;
5114 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5118 return MM_ERROR_NONE;
5122 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5124 mm_player_t *player = (mm_player_t *)hplayer;
5128 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5130 player->audio_stream_render_cb = callback;
5131 player->audio_stream_cb_user_param = user_param;
5132 player->audio_stream_sink_sync = sync;
5133 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5137 return MM_ERROR_NONE;
5141 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5143 mm_player_t *player = (mm_player_t *)hplayer;
5147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 if (callback && !player->bufmgr)
5150 player->bufmgr = tbm_bufmgr_init(-1);
5152 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5153 player->video_stream_cb = callback;
5154 player->video_stream_cb_user_param = user_param;
5156 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5160 return MM_ERROR_NONE;
5164 _mmplayer_start(MMHandleType hplayer)
5166 mm_player_t *player = (mm_player_t *)hplayer;
5167 gint ret = MM_ERROR_NONE;
5171 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5173 /* check current state */
5174 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5176 /* start pipeline */
5177 ret = __mmplayer_gst_start(player);
5178 if (ret != MM_ERROR_NONE)
5179 LOGE("failed to start player.");
5181 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5182 LOGD("force playing start even during buffering");
5183 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5191 /* NOTE: post "not supported codec message" to application
5192 * when one codec is not found during AUTOPLUGGING in MSL.
5193 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5194 * And, if any codec is not found, don't send message here.
5195 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5198 __mmplayer_handle_missed_plugin(mm_player_t *player)
5200 MMMessageParamType msg_param;
5201 memset(&msg_param, 0, sizeof(MMMessageParamType));
5202 gboolean post_msg_direct = FALSE;
5206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5208 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5209 player->not_supported_codec, player->can_support_codec);
5211 if (player->not_found_demuxer) {
5212 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5213 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5215 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5216 MMPLAYER_FREEIF(msg_param.data);
5218 return MM_ERROR_NONE;
5221 if (player->not_supported_codec) {
5222 if (player->can_support_codec) {
5223 // There is one codec to play
5224 post_msg_direct = TRUE;
5226 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5227 post_msg_direct = TRUE;
5230 if (post_msg_direct) {
5231 MMMessageParamType msg_param;
5232 memset(&msg_param, 0, sizeof(MMMessageParamType));
5234 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5235 LOGW("not found AUDIO codec, posting error code to application.");
5237 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5238 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5239 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5240 LOGW("not found VIDEO codec, posting error code to application.");
5242 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5243 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5246 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5248 MMPLAYER_FREEIF(msg_param.data);
5250 return MM_ERROR_NONE;
5252 // no any supported codec case
5253 LOGW("not found any codec, posting error code to application.");
5255 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5256 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5257 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5259 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5260 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5263 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5265 MMPLAYER_FREEIF(msg_param.data);
5271 return MM_ERROR_NONE;
5275 __mmplayer_check_pipeline(mm_player_t *player)
5277 GstState element_state = GST_STATE_VOID_PENDING;
5278 GstState element_pending_state = GST_STATE_VOID_PENDING;
5280 int ret = MM_ERROR_NONE;
5282 if (!player->gapless.reconfigure)
5285 LOGW("pipeline is under construction.");
5287 MMPLAYER_PLAYBACK_LOCK(player);
5288 MMPLAYER_PLAYBACK_UNLOCK(player);
5290 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5292 /* wait for state transition */
5293 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5294 if (ret == GST_STATE_CHANGE_FAILURE)
5295 LOGE("failed to change pipeline state within %d sec", timeout);
5298 /* NOTE : it should be able to call 'stop' anytime*/
5300 _mmplayer_stop(MMHandleType hplayer)
5302 mm_player_t *player = (mm_player_t *)hplayer;
5303 int ret = MM_ERROR_NONE;
5307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5309 /* check current state */
5310 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5312 /* check pipline building state */
5313 __mmplayer_check_pipeline(player);
5314 __mmplayer_reset_gapless_state(player);
5316 /* NOTE : application should not wait for EOS after calling STOP */
5317 __mmplayer_cancel_eos_timer(player);
5320 player->seek_state = MMPLAYER_SEEK_NONE;
5323 ret = __mmplayer_gst_stop(player);
5325 if (ret != MM_ERROR_NONE)
5326 LOGE("failed to stop player.");
5334 _mmplayer_pause(MMHandleType hplayer)
5336 mm_player_t *player = (mm_player_t *)hplayer;
5337 gint64 pos_nsec = 0;
5338 gboolean async = FALSE;
5339 gint ret = MM_ERROR_NONE;
5343 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5345 /* check current state */
5346 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5348 /* check pipline building state */
5349 __mmplayer_check_pipeline(player);
5351 switch (MMPLAYER_CURRENT_STATE(player)) {
5352 case MM_PLAYER_STATE_READY:
5354 /* check prepare async or not.
5355 * In the case of streaming playback, it's recommned to avoid blocking wait.
5357 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5358 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5360 /* Changing back sync of rtspsrc to async */
5361 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5362 LOGD("async prepare working mode for rtsp");
5368 case MM_PLAYER_STATE_PLAYING:
5370 /* NOTE : store current point to overcome some bad operation
5371 *(returning zero when getting current position in paused state) of some
5374 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5375 LOGW("getting current position failed in paused");
5377 player->last_position = pos_nsec;
5379 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5380 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5381 This causes problem is position calculation during normal pause resume scenarios also.
5382 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5383 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5384 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5385 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5391 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5392 LOGD("doing async pause in case of ms buff src");
5396 /* pause pipeline */
5397 ret = __mmplayer_gst_pause(player, async);
5399 if (ret != MM_ERROR_NONE)
5400 LOGE("failed to pause player. ret : 0x%x", ret);
5402 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5403 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5404 LOGE("failed to update display_rotation");
5412 /* in case of streaming, pause could take long time.*/
5414 _mmplayer_abort_pause(MMHandleType hplayer)
5416 mm_player_t *player = (mm_player_t *)hplayer;
5417 int ret = MM_ERROR_NONE;
5421 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5423 player->pipeline->mainbin,
5424 MM_ERROR_PLAYER_NOT_INITIALIZED);
5426 LOGD("set the pipeline state to READY");
5428 /* set state to READY */
5429 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5430 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5431 if (ret != MM_ERROR_NONE) {
5432 LOGE("fail to change state to READY");
5433 return MM_ERROR_PLAYER_INTERNAL;
5436 LOGD("succeeded in changing state to READY");
5441 _mmplayer_resume(MMHandleType hplayer)
5443 mm_player_t *player = (mm_player_t *)hplayer;
5444 int ret = MM_ERROR_NONE;
5445 gboolean async = FALSE;
5449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5451 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5452 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5453 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5457 /* Changing back sync mode rtspsrc to async */
5458 LOGD("async resume for rtsp case");
5462 /* check current state */
5463 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5465 ret = __mmplayer_gst_resume(player, async);
5466 if (ret != MM_ERROR_NONE)
5467 LOGE("failed to resume player.");
5469 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5470 LOGD("force resume even during buffering");
5471 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5480 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5482 mm_player_t *player = (mm_player_t *)hplayer;
5483 gint64 pos_nsec = 0;
5484 int ret = MM_ERROR_NONE;
5486 signed long long start = 0, stop = 0;
5487 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5490 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5491 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5493 /* The sound of video is not supported under 0.0 and over 2.0. */
5494 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5495 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5498 _mmplayer_set_mute(hplayer, mute);
5500 if (player->playback_rate == rate)
5501 return MM_ERROR_NONE;
5503 /* If the position is reached at start potion during fast backward, EOS is posted.
5504 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5506 player->playback_rate = rate;
5508 current_state = MMPLAYER_CURRENT_STATE(player);
5510 if (current_state != MM_PLAYER_STATE_PAUSED)
5511 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5513 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5515 if ((current_state == MM_PLAYER_STATE_PAUSED)
5516 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5517 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5518 pos_nsec = player->last_position;
5523 stop = GST_CLOCK_TIME_NONE;
5525 start = GST_CLOCK_TIME_NONE;
5529 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5530 player->playback_rate,
5532 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5533 GST_SEEK_TYPE_SET, start,
5534 GST_SEEK_TYPE_SET, stop)) {
5535 LOGE("failed to set speed playback");
5536 return MM_ERROR_PLAYER_SEEK;
5539 LOGD("succeeded to set speed playback as %0.1f", rate);
5543 return MM_ERROR_NONE;;
5547 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5549 mm_player_t *player = (mm_player_t *)hplayer;
5550 int ret = MM_ERROR_NONE;
5554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5556 /* check pipline building state */
5557 __mmplayer_check_pipeline(player);
5559 ret = __mmplayer_gst_set_position(player, position, FALSE);
5567 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5569 mm_player_t *player = (mm_player_t *)hplayer;
5570 int ret = MM_ERROR_NONE;
5572 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5574 ret = __mmplayer_gst_get_position(player, position);
5580 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5582 mm_player_t *player = (mm_player_t *)hplayer;
5583 int ret = MM_ERROR_NONE;
5585 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5586 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5588 if (g_strrstr(player->type, "video/mpegts"))
5589 __mmplayer_update_duration_value(player);
5591 *duration = player->duration;
5596 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5598 mm_player_t *player = (mm_player_t *)hplayer;
5599 int ret = MM_ERROR_NONE;
5601 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5603 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5609 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5611 mm_player_t *player = (mm_player_t *)hplayer;
5612 int ret = MM_ERROR_NONE;
5616 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5618 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5626 __mmplayer_is_midi_type(gchar *str_caps)
5628 if ((g_strrstr(str_caps, "audio/midi")) ||
5629 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5630 (g_strrstr(str_caps, "application/x-smaf")) ||
5631 (g_strrstr(str_caps, "audio/x-imelody")) ||
5632 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5633 (g_strrstr(str_caps, "audio/xmf")) ||
5634 (g_strrstr(str_caps, "audio/mxmf"))) {
5643 __mmplayer_is_only_mp3_type(gchar *str_caps)
5645 if (g_strrstr(str_caps, "application/x-id3") ||
5646 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5652 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5654 GstStructure *caps_structure = NULL;
5655 gint samplerate = 0;
5659 MMPLAYER_RETURN_IF_FAIL(player && caps);
5661 caps_structure = gst_caps_get_structure(caps, 0);
5663 /* set stream information */
5664 gst_structure_get_int(caps_structure, "rate", &samplerate);
5665 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5667 gst_structure_get_int(caps_structure, "channels", &channels);
5668 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5670 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5674 __mmplayer_update_content_type_info(mm_player_t *player)
5677 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5679 if (__mmplayer_is_midi_type(player->type)) {
5680 player->bypass_audio_effect = TRUE;
5684 if (!player->streamer) {
5685 LOGD("no need to check streaming type");
5689 if (g_strrstr(player->type, "application/x-hls")) {
5690 /* If it can't know exact type when it parses uri because of redirection case,
5691 * it will be fixed by typefinder or when doing autoplugging.
5693 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5694 player->streamer->is_adaptive_streaming = TRUE;
5695 } else if (g_strrstr(player->type, "application/dash+xml")) {
5696 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5697 player->streamer->is_adaptive_streaming = TRUE;
5700 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5701 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5702 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5704 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5705 if (player->streamer->is_adaptive_streaming)
5706 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5708 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5712 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5717 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5718 GstCaps *caps, gpointer data)
5720 mm_player_t *player = (mm_player_t *)data;
5725 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5727 /* store type string */
5728 MMPLAYER_FREEIF(player->type);
5729 player->type = gst_caps_to_string(caps);
5731 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5732 player, player->type, probability, gst_caps_get_size(caps));
5734 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5735 (g_strrstr(player->type, "audio/x-raw-int"))) {
5736 LOGE("not support media format");
5738 if (player->msg_posted == FALSE) {
5739 MMMessageParamType msg_param;
5740 memset(&msg_param, 0, sizeof(MMMessageParamType));
5742 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5743 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5745 /* don't post more if one was sent already */
5746 player->msg_posted = TRUE;
5751 __mmplayer_update_content_type_info(player);
5753 pad = gst_element_get_static_pad(tf, "src");
5755 LOGE("fail to get typefind src pad.");
5759 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5760 gboolean async = FALSE;
5761 LOGE("failed to autoplug %s", player->type);
5763 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5765 if (async && player->msg_posted == FALSE)
5766 __mmplayer_handle_missed_plugin(player);
5772 gst_object_unref(GST_OBJECT(pad));
5780 __mmplayer_gst_make_decodebin(mm_player_t *player)
5782 GstElement *decodebin = NULL;
5786 /* create decodebin */
5787 decodebin = gst_element_factory_make("decodebin", NULL);
5790 LOGE("fail to create decodebin");
5794 /* raw pad handling signal */
5795 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5796 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5798 /* no-more-pad pad handling signal */
5799 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5800 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5802 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5803 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5805 /* This signal is emitted when a pad for which there is no further possible
5806 decoding is added to the decodebin.*/
5807 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5808 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5810 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5811 before looking for any elements that can handle that stream.*/
5812 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5813 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5815 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5816 before looking for any elements that can handle that stream.*/
5817 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5818 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5820 /* This signal is emitted once decodebin has finished decoding all the data.*/
5821 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5822 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5824 /* This signal is emitted when a element is added to the bin.*/
5825 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5826 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5833 __mmplayer_gst_make_queue2(mm_player_t *player)
5835 GstElement *queue2 = NULL;
5836 gint64 dur_bytes = 0L;
5837 MMPlayerGstElement *mainbin = NULL;
5838 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5841 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5843 mainbin = player->pipeline->mainbin;
5845 queue2 = gst_element_factory_make("queue2", "queue2");
5847 LOGE("failed to create buffering queue element");
5851 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5852 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5854 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5856 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5857 * skip the pull mode(file or ring buffering) setting. */
5858 if (dur_bytes > 0) {
5859 if (!g_strrstr(player->type, "video/mpegts")) {
5860 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5861 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5867 __mm_player_streaming_set_queue2(player->streamer,
5871 (guint64)dur_bytes); /* no meaning at the moment */
5877 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5879 MMPlayerGstElement *mainbin = NULL;
5880 GstElement *decodebin = NULL;
5881 GstElement *queue2 = NULL;
5882 GstPad *sinkpad = NULL;
5883 GstPad *qsrcpad = NULL;
5886 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5888 mainbin = player->pipeline->mainbin;
5890 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5892 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5893 LOGW("need to check: muxed buffer is not null");
5896 queue2 = __mmplayer_gst_make_queue2(player);
5898 LOGE("failed to make queue2");
5902 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5903 LOGE("failed to add buffering queue");
5907 sinkpad = gst_element_get_static_pad(queue2, "sink");
5908 qsrcpad = gst_element_get_static_pad(queue2, "src");
5910 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5911 LOGE("failed to link [%s:%s]-[%s:%s]",
5912 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5916 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5917 LOGE("failed to sync queue2 state with parent");
5921 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5922 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5926 gst_object_unref(GST_OBJECT(sinkpad));
5930 /* create decodebin */
5931 decodebin = __mmplayer_gst_make_decodebin(player);
5933 LOGE("failed to make decodebin");
5937 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5938 LOGE("failed to add decodebin");
5942 /* to force caps on the decodebin element and avoid reparsing stuff by
5943 * typefind. It also avoids a deadlock in the way typefind activates pads in
5944 * the state change */
5945 g_object_set(decodebin, "sink-caps", caps, NULL);
5947 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5949 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5950 LOGE("failed to link [%s:%s]-[%s:%s]",
5951 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5955 gst_object_unref(GST_OBJECT(sinkpad));
5958 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5959 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5961 /* set decodebin property about buffer in streaming playback. *
5962 * in case of HLS/DASH, it does not need to have big buffer *
5963 * because it is kind of adaptive streaming. */
5964 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5965 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5966 gint high_percent = 0;
5968 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5969 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5971 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5973 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5975 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
5976 "high-percent", high_percent,
5977 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
5978 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
5979 "max-size-buffers", 0, NULL); // disable or automatic
5982 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
5983 LOGE("failed to sync decodebin state with parent");
5994 gst_object_unref(GST_OBJECT(sinkpad));
5997 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
5998 * You need to explicitly set elements to the NULL state before
5999 * dropping the final reference, to allow them to clean up.
6001 gst_element_set_state(queue2, GST_STATE_NULL);
6003 /* And, it still has a parent "player".
6004 * You need to let the parent manage the object instead of unreffing the object directly.
6006 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6007 gst_object_unref(queue2);
6012 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6013 * You need to explicitly set elements to the NULL state before
6014 * dropping the final reference, to allow them to clean up.
6016 gst_element_set_state(decodebin, GST_STATE_NULL);
6018 /* And, it still has a parent "player".
6019 * You need to let the parent manage the object instead of unreffing the object directly.
6022 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6023 gst_object_unref(decodebin);
6031 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6036 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6038 LOGD("class : %s, mime : %s", factory_class, mime);
6040 /* add missing plugin */
6041 /* NOTE : msl should check missing plugin for image mime type.
6042 * Some motion jpeg clips can have playable audio track.
6043 * So, msl have to play audio after displaying popup written video format not supported.
6045 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6046 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6047 LOGD("not found demuxer");
6048 player->not_found_demuxer = TRUE;
6049 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6055 if (!g_strrstr(factory_class, "Demuxer")) {
6056 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6057 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6058 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6060 /* check that clip have multi tracks or not */
6061 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6062 LOGD("video plugin is already linked");
6064 LOGW("add VIDEO to missing plugin");
6065 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6066 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6068 } else if (g_str_has_prefix(mime, "audio")) {
6069 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6070 LOGD("audio plugin is already linked");
6072 LOGW("add AUDIO to missing plugin");
6073 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6074 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6082 return MM_ERROR_NONE;
6086 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6088 mm_player_t *player = (mm_player_t *)data;
6092 MMPLAYER_RETURN_IF_FAIL(player);
6094 /* remove fakesink. */
6095 if (!__mmplayer_gst_remove_fakesink(player,
6096 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6097 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6098 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6099 * source element are not same. To overcome this situation, this function will called
6100 * several places and several times. Therefore, this is not an error case.
6105 LOGD("[handle: %p] pipeline has completely constructed", player);
6107 if ((player->ini.async_start) &&
6108 (player->msg_posted == FALSE) &&
6109 (player->cmd >= MMPLAYER_COMMAND_START))
6110 __mmplayer_handle_missed_plugin(player);
6112 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6116 __mmplayer_check_profile(void)
6119 static int profile_tv = -1;
6121 if (__builtin_expect(profile_tv != -1, 1))
6124 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6125 switch (*profileName) {
6140 __mmplayer_get_next_uri(mm_player_t *player)
6142 MMPlayerParseProfile profile;
6144 guint num_of_list = 0;
6147 num_of_list = g_list_length(player->uri_info.uri_list);
6148 uri_idx = player->uri_info.uri_idx;
6150 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6151 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6152 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6154 LOGW("next uri does not exist");
6158 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6159 LOGE("failed to parse profile");
6163 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6164 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6165 LOGW("uri type is not supported(%d)", profile.uri_type);
6169 LOGD("success to find next uri %d", uri_idx);
6173 if (uri_idx == num_of_list) {
6174 LOGE("failed to find next uri");
6178 player->uri_info.uri_idx = uri_idx;
6179 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6181 if (mm_attrs_commit_all(player->attrs)) {
6182 LOGE("failed to commit");
6186 SECURE_LOGD("next playback uri: %s", uri);
6191 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6193 #define REPEAT_COUNT_INFINITELY -1
6194 #define REPEAT_COUNT_MIN 2
6196 MMHandleType attrs = 0;
6200 guint num_of_list = 0;
6201 int profile_tv = -1;
6205 LOGD("checking for gapless play option");
6207 if (player->pipeline->textbin) {
6208 LOGE("subtitle path is enabled. gapless play is not supported.");
6212 attrs = MMPLAYER_GET_ATTRS(player);
6214 LOGE("fail to get attributes.");
6218 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6220 /* gapless playback is not supported in case of video at TV profile. */
6221 profile_tv = __mmplayer_check_profile();
6222 if (profile_tv && video) {
6223 LOGW("not support video gapless playback");
6227 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6228 LOGE("failed to get play count");
6230 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6231 LOGE("failed to get gapless mode");
6233 /* check repeat count in case of audio */
6235 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6236 LOGW("gapless is disabled");
6240 num_of_list = g_list_length(player->uri_info.uri_list);
6242 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6244 if (num_of_list == 0) {
6245 /* audio looping path */
6246 if (count >= REPEAT_COUNT_MIN) {
6247 /* decrease play count */
6248 /* we succeeded to rewind. update play count and then wait for next EOS */
6250 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6251 /* commit attribute */
6252 if (mm_attrs_commit_all(attrs))
6253 LOGE("failed to commit attribute");
6255 } else if (count != REPEAT_COUNT_INFINITELY) {
6256 LOGD("there is no next uri and no repeat");
6259 LOGD("looping cnt %d", count);
6261 /* gapless playback path */
6262 if (!__mmplayer_get_next_uri(player)) {
6263 LOGE("failed to get next uri");
6270 LOGE("unable to play gapless path. EOS will be posted soon");
6275 __mmplayer_initialize_gapless_play(mm_player_t *player)
6281 player->smooth_streaming = FALSE;
6282 player->videodec_linked = 0;
6283 player->audiodec_linked = 0;
6284 player->textsink_linked = 0;
6285 player->is_external_subtitle_present = FALSE;
6286 player->is_external_subtitle_added_now = FALSE;
6287 player->not_supported_codec = MISSING_PLUGIN_NONE;
6288 player->can_support_codec = FOUND_PLUGIN_NONE;
6289 player->pending_seek.is_pending = false;
6290 player->pending_seek.pos = 0;
6291 player->msg_posted = FALSE;
6292 player->has_many_types = FALSE;
6293 player->no_more_pad = FALSE;
6294 player->not_found_demuxer = 0;
6295 player->seek_state = MMPLAYER_SEEK_NONE;
6296 player->is_subtitle_force_drop = FALSE;
6297 player->play_subtitle = FALSE;
6298 player->adjust_subtitle_pos = 0;
6300 player->total_bitrate = 0;
6301 player->total_maximum_bitrate = 0;
6303 __mmplayer_track_initialize(player);
6304 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6306 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6307 player->bitrate[i] = 0;
6308 player->maximum_bitrate[i] = 0;
6311 if (player->v_stream_caps) {
6312 gst_caps_unref(player->v_stream_caps);
6313 player->v_stream_caps = NULL;
6316 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6318 /* clean found parsers */
6319 if (player->parsers) {
6320 GList *parsers = player->parsers;
6321 for (; parsers; parsers = g_list_next(parsers)) {
6322 gchar *name = parsers->data;
6323 MMPLAYER_FREEIF(name);
6325 g_list_free(player->parsers);
6326 player->parsers = NULL;
6329 /* clean found audio decoders */
6330 if (player->audio_decoders) {
6331 GList *a_dec = player->audio_decoders;
6332 for (; a_dec; a_dec = g_list_next(a_dec)) {
6333 gchar *name = a_dec->data;
6334 MMPLAYER_FREEIF(name);
6336 g_list_free(player->audio_decoders);
6337 player->audio_decoders = NULL;
6344 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6346 MMPlayerGstElement *mainbin = NULL;
6347 MMMessageParamType msg_param = {0,};
6348 GstElement *element = NULL;
6349 MMHandleType attrs = 0;
6351 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6355 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6356 LOGE("player is not initialized");
6360 mainbin = player->pipeline->mainbin;
6361 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6363 attrs = MMPLAYER_GET_ATTRS(player);
6365 LOGE("fail to get attributes");
6369 /* Initialize Player values */
6370 __mmplayer_initialize_gapless_play(player);
6372 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6374 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6375 LOGE("failed to parse profile");
6376 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6380 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6381 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6382 LOGE("dash or hls is not supportable");
6383 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6387 element = __mmplayer_gst_create_source(player);
6389 LOGE("no source element was created");
6393 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6394 LOGE("failed to add source element to pipeline");
6395 gst_object_unref(GST_OBJECT(element));
6400 /* take source element */
6401 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6402 mainbin[MMPLAYER_M_SRC].gst = element;
6406 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6407 if (player->streamer == NULL) {
6408 player->streamer = __mm_player_streaming_create();
6409 __mm_player_streaming_initialize(player->streamer, TRUE);
6412 elem_idx = MMPLAYER_M_TYPEFIND;
6413 element = gst_element_factory_make("typefind", "typefinder");
6414 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6415 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6417 elem_idx = MMPLAYER_M_AUTOPLUG;
6418 element = __mmplayer_gst_make_decodebin(player);
6421 /* check autoplug element is OK */
6423 LOGE("can not create element(%d)", elem_idx);
6427 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6428 LOGE("failed to add sinkbin to pipeline");
6429 gst_object_unref(GST_OBJECT(element));
6434 mainbin[elem_idx].id = elem_idx;
6435 mainbin[elem_idx].gst = element;
6437 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6438 LOGE("Failed to link src - autoplug(or typefind)");
6442 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6443 LOGE("Failed to change state of src element");
6447 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6448 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6449 LOGE("Failed to change state of decodebin");
6453 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6454 LOGE("Failed to change state of src element");
6459 player->gapless.stream_changed = TRUE;
6460 player->gapless.running = TRUE;
6466 MMPLAYER_PLAYBACK_UNLOCK(player);
6468 if (!player->msg_posted) {
6469 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6470 player->msg_posted = TRUE;
6477 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6479 mm_player_selector_t *selector = &player->selector[type];
6480 MMPlayerGstElement *sinkbin = NULL;
6481 enum MainElementID selectorId = MMPLAYER_M_NUM;
6482 enum MainElementID sinkId = MMPLAYER_M_NUM;
6483 GstPad *srcpad = NULL;
6484 GstPad *sinkpad = NULL;
6485 gboolean send_notice = FALSE;
6488 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6490 LOGD("type %d", type);
6493 case MM_PLAYER_TRACK_TYPE_AUDIO:
6494 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6495 sinkId = MMPLAYER_A_BIN;
6496 sinkbin = player->pipeline->audiobin;
6498 case MM_PLAYER_TRACK_TYPE_VIDEO:
6499 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6500 sinkId = MMPLAYER_V_BIN;
6501 sinkbin = player->pipeline->videobin;
6504 case MM_PLAYER_TRACK_TYPE_TEXT:
6505 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6506 sinkId = MMPLAYER_T_BIN;
6507 sinkbin = player->pipeline->textbin;
6510 LOGE("requested type is not supportable");
6515 if (player->pipeline->mainbin[selectorId].gst) {
6518 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6520 if (selector->event_probe_id != 0)
6521 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6522 selector->event_probe_id = 0;
6524 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6525 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6527 if (srcpad && sinkpad) {
6528 /* after getting drained signal there is no data flows, so no need to do pad_block */
6529 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6530 gst_pad_unlink(srcpad, sinkpad);
6532 /* send custom event to sink pad to handle it at video sink */
6534 LOGD("send custom event to sinkpad");
6535 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6536 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6537 gst_pad_send_event(sinkpad, event);
6541 gst_object_unref(sinkpad);
6544 gst_object_unref(srcpad);
6547 LOGD("selector release");
6549 /* release and unref requests pad from the selector */
6550 for (n = 0; n < selector->channels->len; n++) {
6551 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6552 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6554 g_ptr_array_set_size(selector->channels, 0);
6556 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6557 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6559 player->pipeline->mainbin[selectorId].gst = NULL;
6567 __mmplayer_deactivate_old_path(mm_player_t *player)
6570 MMPLAYER_RETURN_IF_FAIL(player);
6572 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6573 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6574 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6575 LOGE("deactivate selector error");
6579 __mmplayer_track_destroy(player);
6580 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6582 if (player->streamer) {
6583 __mm_player_streaming_initialize(player->streamer, FALSE);
6584 __mm_player_streaming_destroy(player->streamer);
6585 player->streamer = NULL;
6588 MMPLAYER_PLAYBACK_LOCK(player);
6589 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6596 if (!player->msg_posted) {
6597 MMMessageParamType msg = {0,};
6600 msg.code = MM_ERROR_PLAYER_INTERNAL;
6601 LOGE("gapless_uri_play> deactivate error");
6603 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6604 player->msg_posted = TRUE;
6610 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6612 int result = MM_ERROR_NONE;
6613 mm_player_t *player = (mm_player_t *)hplayer;
6616 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6618 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6619 if (mm_attrs_commit_all(player->attrs)) {
6620 LOGE("failed to commit the original uri.");
6621 result = MM_ERROR_PLAYER_INTERNAL;
6623 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6624 LOGE("failed to add the original uri in the uri list.");
6632 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6634 mm_player_t *player = (mm_player_t *)hplayer;
6635 guint num_of_list = 0;
6639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6640 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6642 if (player->pipeline && player->pipeline->textbin) {
6643 LOGE("subtitle path is enabled.");
6644 return MM_ERROR_PLAYER_INVALID_STATE;
6647 num_of_list = g_list_length(player->uri_info.uri_list);
6649 if (is_first_path) {
6650 if (num_of_list == 0) {
6651 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6652 LOGD("add original path : %s", uri);
6654 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6655 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6657 LOGD("change original path : %s", uri);
6660 MMHandleType attrs = 0;
6661 attrs = MMPLAYER_GET_ATTRS(player);
6663 if (num_of_list == 0) {
6664 char *original_uri = NULL;
6667 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6669 if (!original_uri) {
6670 LOGE("there is no original uri.");
6671 return MM_ERROR_PLAYER_INVALID_STATE;
6674 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6675 player->uri_info.uri_idx = 0;
6677 LOGD("add original path at first : %s", original_uri);
6681 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6682 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6686 return MM_ERROR_NONE;
6690 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6692 mm_player_t *player = (mm_player_t *)hplayer;
6693 char *next_uri = NULL;
6694 guint num_of_list = 0;
6697 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6699 num_of_list = g_list_length(player->uri_info.uri_list);
6701 if (num_of_list > 0) {
6702 gint uri_idx = player->uri_info.uri_idx;
6704 if (uri_idx < num_of_list-1)
6709 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6710 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6712 *uri = g_strdup(next_uri);
6716 return MM_ERROR_NONE;
6720 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6721 GstCaps *caps, gpointer data)
6723 mm_player_t *player = (mm_player_t *)data;
6724 const gchar *klass = NULL;
6725 const gchar *mime = NULL;
6726 gchar *caps_str = NULL;
6728 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6729 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6730 caps_str = gst_caps_to_string(caps);
6732 LOGW("unknown type of caps : %s from %s",
6733 caps_str, GST_ELEMENT_NAME(elem));
6735 MMPLAYER_FREEIF(caps_str);
6737 /* There is no available codec. */
6738 __mmplayer_check_not_supported_codec(player, klass, mime);
6742 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6743 GstCaps *caps, gpointer data)
6745 mm_player_t *player = (mm_player_t *)data;
6746 const char *mime = NULL;
6747 gboolean ret = TRUE;
6749 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6750 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6752 if (g_str_has_prefix(mime, "audio")) {
6753 GstStructure *caps_structure = NULL;
6754 gint samplerate = 0;
6756 gchar *caps_str = NULL;
6758 caps_structure = gst_caps_get_structure(caps, 0);
6759 gst_structure_get_int(caps_structure, "rate", &samplerate);
6760 gst_structure_get_int(caps_structure, "channels", &channels);
6762 if ((channels > 0 && samplerate == 0)) {
6763 LOGD("exclude audio...");
6767 caps_str = gst_caps_to_string(caps);
6768 /* set it directly because not sent by TAG */
6769 if (g_strrstr(caps_str, "mobile-xmf"))
6770 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6771 MMPLAYER_FREEIF(caps_str);
6772 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6773 MMMessageParamType msg_param;
6774 memset(&msg_param, 0, sizeof(MMMessageParamType));
6775 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6776 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6777 LOGD("video file is not supported on this device");
6779 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6780 LOGD("already video linked");
6783 LOGD("found new stream");
6790 __mmplayer_check_offload_path(mm_player_t *player)
6792 gboolean ret = FALSE;
6793 GstElementFactory *factory = NULL;
6796 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6798 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6799 /* FIXME : 1. need to consider the current audio output path and
6800 player have to know whether it support offload or not.
6801 2. could be added new condition about content length */
6802 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6803 if (!__mmplayer_is_only_mp3_type(player->type))
6806 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6810 LOGD("can setup the audio offload path");
6811 gst_object_unref(factory);
6820 static GstAutoplugSelectResult
6821 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6823 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6825 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6826 int audio_offload = 0;
6828 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6829 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6831 if (audio_offload && __mmplayer_check_offload_path(player)) {
6832 LOGD("expose audio path to build offload path");
6833 player->build_audio_offload = TRUE;
6834 /* update codec info */
6835 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6836 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6837 player->audiodec_linked = 1;
6839 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6843 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6845 LOGD("audio codec type: %d", codec_type);
6846 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6847 /* sw codec will be skipped */
6848 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6849 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6850 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6851 ret = GST_AUTOPLUG_SELECT_SKIP;
6855 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6856 /* hw codec will be skipped */
6857 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6858 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6859 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6860 ret = GST_AUTOPLUG_SELECT_SKIP;
6865 /* set stream information */
6866 if (!player->audiodec_linked)
6867 __mmplayer_set_audio_attrs(player, caps);
6869 /* update codec info */
6870 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6871 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6872 player->audiodec_linked = 1;
6874 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6876 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6878 LOGD("video codec type: %d", codec_type);
6879 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6880 /* sw codec is skipped */
6881 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6882 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6883 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6884 ret = GST_AUTOPLUG_SELECT_SKIP;
6888 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6889 /* hw codec is skipped */
6890 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6891 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6892 ret = GST_AUTOPLUG_SELECT_SKIP;
6897 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6898 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6900 /* mark video decoder for acquire */
6901 if (player->video_decoder_resource == NULL) {
6902 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6903 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6904 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6905 &player->video_decoder_resource)
6906 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6907 LOGE("could not mark video_decoder resource for acquire");
6908 ret = GST_AUTOPLUG_SELECT_SKIP;
6912 LOGW("video decoder resource is already acquired, skip it.");
6913 ret = GST_AUTOPLUG_SELECT_SKIP;
6917 player->interrupted_by_resource = FALSE;
6918 /* acquire resources for video playing */
6919 if (mm_resource_manager_commit(player->resource_manager)
6920 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6921 LOGE("could not acquire resources for video decoding");
6922 ret = GST_AUTOPLUG_SELECT_SKIP;
6927 /* update codec info */
6928 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6929 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6930 player->videodec_linked = 1;
6938 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6939 GstCaps *caps, GstElementFactory *factory, gpointer data)
6941 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6942 mm_player_t *player = (mm_player_t *)data;
6944 gchar *factory_name = NULL;
6945 gchar *caps_str = NULL;
6946 const gchar *klass = NULL;
6949 factory_name = GST_OBJECT_NAME(factory);
6950 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6951 caps_str = gst_caps_to_string(caps);
6953 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6955 /* store type string */
6956 if (player->type == NULL) {
6957 player->type = gst_caps_to_string(caps);
6958 __mmplayer_update_content_type_info(player);
6961 /* filtering exclude keyword */
6962 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6963 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6964 LOGW("skipping [%s] by exculde keyword [%s]",
6965 factory_name, player->ini.exclude_element_keyword[idx]);
6967 result = GST_AUTOPLUG_SELECT_SKIP;
6972 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6973 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6974 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6975 factory_name, player->ini.unsupported_codec_keyword[idx]);
6976 result = GST_AUTOPLUG_SELECT_SKIP;
6981 /* exclude webm format */
6982 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
6983 * because webm format is not supportable.
6984 * If webm is disabled in "autoplug-continue", there is no state change
6985 * failure or error because the decodebin will expose the pad directly.
6986 * It make MSL invoke _prepare_async_callback.
6987 * So, we need to disable webm format in "autoplug-select" */
6988 if (caps_str && strstr(caps_str, "webm")) {
6989 LOGW("webm is not supported");
6990 result = GST_AUTOPLUG_SELECT_SKIP;
6994 /* check factory class for filtering */
6995 /* NOTE : msl don't need to use image plugins.
6996 * So, those plugins should be skipped for error handling.
6998 if (g_strrstr(klass, "Codec/Decoder/Image")) {
6999 LOGD("skipping [%s] by not required", factory_name);
7000 result = GST_AUTOPLUG_SELECT_SKIP;
7004 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7005 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7006 // TO CHECK : subtitle if needed, add subparse exception.
7007 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7008 result = GST_AUTOPLUG_SELECT_SKIP;
7012 if (g_strrstr(factory_name, "mpegpsdemux")) {
7013 LOGD("skipping PS container - not support");
7014 result = GST_AUTOPLUG_SELECT_SKIP;
7018 if (g_strrstr(factory_name, "mssdemux"))
7019 player->smooth_streaming = TRUE;
7021 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7022 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7025 GstStructure *str = NULL;
7026 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7028 /* don't make video because of not required */
7029 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7030 (!player->set_mode.media_packet_video_stream)) {
7031 LOGD("no need video decoding, expose pad");
7032 result = GST_AUTOPLUG_SELECT_EXPOSE;
7036 /* get w/h for omx state-tune */
7037 /* FIXME: deprecated? */
7038 str = gst_caps_get_structure(caps, 0);
7039 gst_structure_get_int(str, "width", &width);
7042 if (player->v_stream_caps) {
7043 gst_caps_unref(player->v_stream_caps);
7044 player->v_stream_caps = NULL;
7047 player->v_stream_caps = gst_caps_copy(caps);
7048 LOGD("take caps for video state tune");
7049 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7053 if (g_strrstr(klass, "Codec/Decoder")) {
7054 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7055 if (result != GST_AUTOPLUG_SELECT_TRY) {
7056 LOGW("skip add decoder");
7062 MMPLAYER_FREEIF(caps_str);
7068 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7071 //mm_player_t *player = (mm_player_t *)data;
7072 GstCaps *caps = NULL;
7074 LOGD("[Decodebin2] pad-removed signal");
7076 caps = gst_pad_query_caps(new_pad, NULL);
7078 LOGW("query caps is NULL");
7082 gchar *caps_str = NULL;
7083 caps_str = gst_caps_to_string(caps);
7085 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7087 MMPLAYER_FREEIF(caps_str);
7088 gst_caps_unref(caps);
7092 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7094 mm_player_t *player = (mm_player_t *)data;
7095 GstIterator *iter = NULL;
7096 GValue item = { 0, };
7098 gboolean done = FALSE;
7099 gboolean is_all_drained = TRUE;
7102 MMPLAYER_RETURN_IF_FAIL(player);
7104 LOGD("__mmplayer_gst_decode_drained");
7106 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7107 LOGW("Fail to get cmd lock");
7111 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7112 !__mmplayer_verify_gapless_play_path(player)) {
7113 LOGD("decoding is finished.");
7114 __mmplayer_reset_gapless_state(player);
7115 MMPLAYER_CMD_UNLOCK(player);
7119 player->gapless.reconfigure = TRUE;
7121 /* check decodebin src pads whether they received EOS or not */
7122 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7125 switch (gst_iterator_next(iter, &item)) {
7126 case GST_ITERATOR_OK:
7127 pad = g_value_get_object(&item);
7128 if (pad && !GST_PAD_IS_EOS(pad)) {
7129 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7130 is_all_drained = FALSE;
7133 g_value_reset(&item);
7135 case GST_ITERATOR_RESYNC:
7136 gst_iterator_resync(iter);
7138 case GST_ITERATOR_ERROR:
7139 case GST_ITERATOR_DONE:
7144 g_value_unset(&item);
7145 gst_iterator_free(iter);
7147 if (!is_all_drained) {
7148 LOGD("Wait util the all pads get EOS.");
7149 MMPLAYER_CMD_UNLOCK(player);
7154 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7155 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7157 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7158 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7159 __mmplayer_deactivate_old_path(player);
7160 MMPLAYER_CMD_UNLOCK(player);
7166 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7168 mm_player_t *player = (mm_player_t *)data;
7169 const gchar *klass = NULL;
7170 gchar *factory_name = NULL;
7172 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7173 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7175 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7177 if (__mmplayer_add_dump_buffer_probe(player, element))
7178 LOGD("add buffer probe");
7181 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7182 gchar *selected = NULL;
7183 selected = g_strdup(GST_ELEMENT_NAME(element));
7184 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7188 if (g_strrstr(klass, "Parser")) {
7189 gchar *selected = NULL;
7191 selected = g_strdup(factory_name);
7192 player->parsers = g_list_append(player->parsers, selected);
7195 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7196 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7197 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7199 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7200 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7202 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7203 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7204 "max-video-width", player->adaptive_info.limit.width,
7205 "max-video-height", player->adaptive_info.limit.height, NULL);
7207 } else if (g_strrstr(klass, "Demuxer")) {
7208 //LOGD("plugged element is demuxer. take it");
7209 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7210 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7213 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7214 int surface_type = 0;
7216 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7219 // to support trust-zone only
7220 if (g_strrstr(factory_name, "asfdemux")) {
7221 LOGD("set file-location %s", player->profile.uri);
7222 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7223 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7224 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7225 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7226 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7227 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7228 (__mmplayer_is_only_mp3_type(player->type))) {
7229 LOGD("[mpegaudioparse] set streaming pull mode.");
7230 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7232 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7233 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7236 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7237 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7238 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7240 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7241 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7243 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7244 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7245 (MMPLAYER_IS_DASH_STREAMING(player))) {
7246 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7247 __mm_player_streaming_set_multiqueue(player->streamer, element);
7248 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7257 __mmplayer_release_misc(mm_player_t *player)
7260 bool cur_mode = player->set_mode.rich_audio;
7263 MMPLAYER_RETURN_IF_FAIL(player);
7265 player->video_stream_cb = NULL;
7266 player->video_stream_cb_user_param = NULL;
7267 player->video_stream_prerolled = false;
7269 player->audio_stream_render_cb = NULL;
7270 player->audio_stream_cb_user_param = NULL;
7271 player->audio_stream_sink_sync = false;
7273 player->video_stream_changed_cb = NULL;
7274 player->video_stream_changed_cb_user_param = NULL;
7276 player->audio_stream_changed_cb = NULL;
7277 player->audio_stream_changed_cb_user_param = NULL;
7279 player->sent_bos = FALSE;
7280 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7282 player->seek_state = MMPLAYER_SEEK_NONE;
7284 player->total_bitrate = 0;
7285 player->total_maximum_bitrate = 0;
7287 player->not_found_demuxer = 0;
7289 player->last_position = 0;
7290 player->duration = 0;
7291 player->http_content_size = 0;
7292 player->not_supported_codec = MISSING_PLUGIN_NONE;
7293 player->can_support_codec = FOUND_PLUGIN_NONE;
7294 player->pending_seek.is_pending = false;
7295 player->pending_seek.pos = 0;
7296 player->msg_posted = FALSE;
7297 player->has_many_types = FALSE;
7298 player->is_subtitle_force_drop = FALSE;
7299 player->play_subtitle = FALSE;
7300 player->adjust_subtitle_pos = 0;
7301 player->last_multiwin_status = FALSE;
7302 player->has_closed_caption = FALSE;
7303 player->set_mode.media_packet_video_stream = false;
7304 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7305 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7307 player->set_mode.rich_audio = cur_mode;
7309 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7310 player->bitrate[i] = 0;
7311 player->maximum_bitrate[i] = 0;
7314 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7316 /* remove media stream cb(appsrc cb) */
7317 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7318 player->media_stream_buffer_status_cb[i] = NULL;
7319 player->media_stream_seek_data_cb[i] = NULL;
7320 player->buffer_cb_user_param[i] = NULL;
7321 player->seek_cb_user_param[i] = NULL;
7323 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7325 /* free memory related to audio effect */
7326 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7328 if (player->adaptive_info.var_list) {
7329 g_list_free_full(player->adaptive_info.var_list, g_free);
7330 player->adaptive_info.var_list = NULL;
7333 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7334 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7335 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7337 /* Reset video360 settings to their defaults in case if the pipeline is to be
7340 player->video360_metadata.is_spherical = -1;
7341 player->is_openal_plugin_used = FALSE;
7343 player->is_content_spherical = FALSE;
7344 player->is_video360_enabled = TRUE;
7345 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7346 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7347 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7348 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7349 player->video360_zoom = 1.0f;
7350 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7351 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7353 player->sound.rg_enable = false;
7355 __mmplayer_initialize_video_roi(player);
7360 __mmplayer_release_misc_post(mm_player_t *player)
7362 char *original_uri = NULL;
7365 /* player->pipeline is already released before. */
7367 MMPLAYER_RETURN_IF_FAIL(player);
7369 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7371 /* clean found parsers */
7372 if (player->parsers) {
7373 GList *parsers = player->parsers;
7374 for (; parsers; parsers = g_list_next(parsers)) {
7375 gchar *name = parsers->data;
7376 MMPLAYER_FREEIF(name);
7378 g_list_free(player->parsers);
7379 player->parsers = NULL;
7382 /* clean found audio decoders */
7383 if (player->audio_decoders) {
7384 GList *a_dec = player->audio_decoders;
7385 for (; a_dec; a_dec = g_list_next(a_dec)) {
7386 gchar *name = a_dec->data;
7387 MMPLAYER_FREEIF(name);
7389 g_list_free(player->audio_decoders);
7390 player->audio_decoders = NULL;
7393 /* clean the uri list except original uri */
7394 if (player->uri_info.uri_list) {
7395 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7397 if (player->attrs) {
7398 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7399 LOGD("restore original uri = %s", original_uri);
7401 if (mm_attrs_commit_all(player->attrs))
7402 LOGE("failed to commit the original uri.");
7405 GList *uri_list = player->uri_info.uri_list;
7406 for (; uri_list; uri_list = g_list_next(uri_list)) {
7407 gchar *uri = uri_list->data;
7408 MMPLAYER_FREEIF(uri);
7410 g_list_free(player->uri_info.uri_list);
7411 player->uri_info.uri_list = NULL;
7414 /* clear the audio stream buffer list */
7415 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7417 /* clear the video stream bo list */
7418 __mmplayer_video_stream_destroy_bo_list(player);
7419 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7421 if (player->profile.input_mem.buf) {
7422 free(player->profile.input_mem.buf);
7423 player->profile.input_mem.buf = NULL;
7425 player->profile.input_mem.len = 0;
7426 player->profile.input_mem.offset = 0;
7428 player->uri_info.uri_idx = 0;
7433 __mmplayer_check_subtitle(mm_player_t *player)
7435 MMHandleType attrs = 0;
7436 char *subtitle_uri = NULL;
7440 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7442 /* get subtitle attribute */
7443 attrs = MMPLAYER_GET_ATTRS(player);
7447 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7448 if (!subtitle_uri || !strlen(subtitle_uri))
7451 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7452 player->is_external_subtitle_present = TRUE;
7460 __mmplayer_cancel_eos_timer(mm_player_t *player)
7462 MMPLAYER_RETURN_IF_FAIL(player);
7464 if (player->eos_timer) {
7465 LOGD("cancel eos timer");
7466 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7467 player->eos_timer = 0;
7474 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7478 MMPLAYER_RETURN_IF_FAIL(player);
7479 MMPLAYER_RETURN_IF_FAIL(sink);
7481 player->sink_elements = g_list_append(player->sink_elements, sink);
7487 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7491 MMPLAYER_RETURN_IF_FAIL(player);
7492 MMPLAYER_RETURN_IF_FAIL(sink);
7494 player->sink_elements = g_list_remove(player->sink_elements, sink);
7500 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7501 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7503 MMPlayerSignalItem *item = NULL;
7506 MMPLAYER_RETURN_IF_FAIL(player);
7508 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7509 LOGE("invalid signal type [%d]", type);
7513 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7515 LOGE("cannot connect signal [%s]", signal);
7520 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7521 player->signals[type] = g_list_append(player->signals[type], item);
7527 /* NOTE : be careful with calling this api. please refer to below glib comment
7528 * glib comment : Note that there is a bug in GObject that makes this function much
7529 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7530 * will no longer be called, but, the signal handler is not currently disconnected.
7531 * If the instance is itself being freed at the same time than this doesn't matter,
7532 * since the signal will automatically be removed, but if instance persists,
7533 * then the signal handler will leak. You should not remove the signal yourself
7534 * because in a future versions of GObject, the handler will automatically be
7537 * It's possible to work around this problem in a way that will continue to work
7538 * with future versions of GObject by checking that the signal handler is still
7539 * connected before disconnected it:
7541 * if (g_signal_handler_is_connected(instance, id))
7542 * g_signal_handler_disconnect(instance, id);
7545 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7547 GList *sig_list = NULL;
7548 MMPlayerSignalItem *item = NULL;
7552 MMPLAYER_RETURN_IF_FAIL(player);
7554 LOGD("release signals type : %d", type);
7556 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7557 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7558 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7559 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7560 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7561 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7565 sig_list = player->signals[type];
7567 for (; sig_list; sig_list = sig_list->next) {
7568 item = sig_list->data;
7570 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7571 if (g_signal_handler_is_connected(item->obj, item->sig))
7572 g_signal_handler_disconnect(item->obj, item->sig);
7575 MMPLAYER_FREEIF(item);
7578 g_list_free(player->signals[type]);
7579 player->signals[type] = NULL;
7587 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7589 mm_player_t *player = 0;
7590 int prev_display_surface_type = 0;
7591 void *prev_display_overlay = NULL;
7595 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7596 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7598 player = MM_PLAYER_CAST(handle);
7600 /* check video sinkbin is created */
7601 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7602 LOGE("Videosink is already created");
7603 return MM_ERROR_NONE;
7606 LOGD("videosink element is not yet ready");
7608 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7609 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7611 return MM_ERROR_INVALID_ARGUMENT;
7614 /* load previous attributes */
7615 if (player->attrs) {
7616 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7617 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7618 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7619 if (prev_display_surface_type == surface_type) {
7620 LOGD("incoming display surface type is same as previous one, do nothing..");
7622 return MM_ERROR_NONE;
7625 LOGE("failed to load attributes");
7627 return MM_ERROR_PLAYER_INTERNAL;
7630 /* videobin is not created yet, so we just set attributes related to display surface */
7631 LOGD("store display attribute for given surface type(%d)", surface_type);
7632 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7633 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7634 if (mm_attrs_commit_all(player->attrs)) {
7635 LOGE("failed to commit attribute");
7637 return MM_ERROR_PLAYER_INTERNAL;
7641 return MM_ERROR_NONE;
7644 /* Note : if silent is true, then subtitle would not be displayed. :*/
7646 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7648 mm_player_t *player = (mm_player_t *)hplayer;
7652 /* check player handle */
7653 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7655 player->set_mode.subtitle_off = silent;
7657 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7661 return MM_ERROR_NONE;
7665 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7667 MMPlayerGstElement *mainbin = NULL;
7668 MMPlayerGstElement *textbin = NULL;
7669 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7670 GstState current_state = GST_STATE_VOID_PENDING;
7671 GstState element_state = GST_STATE_VOID_PENDING;
7672 GstState element_pending_state = GST_STATE_VOID_PENDING;
7674 GstEvent *event = NULL;
7675 int result = MM_ERROR_NONE;
7677 GstClock *curr_clock = NULL;
7678 GstClockTime base_time, start_time, curr_time;
7683 /* check player handle */
7684 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7686 player->pipeline->mainbin &&
7687 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7689 mainbin = player->pipeline->mainbin;
7690 textbin = player->pipeline->textbin;
7692 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7694 // sync clock with current pipeline
7695 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7696 curr_time = gst_clock_get_time(curr_clock);
7698 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7699 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7701 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7702 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7704 if (current_state > GST_STATE_READY) {
7705 // sync state with current pipeline
7706 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7707 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7708 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7710 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7711 if (GST_STATE_CHANGE_FAILURE == ret) {
7712 LOGE("fail to state change.");
7713 result = MM_ERROR_PLAYER_INTERNAL;
7717 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7718 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7721 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7722 gst_object_unref(curr_clock);
7725 // seek to current position
7726 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7727 result = MM_ERROR_PLAYER_INVALID_STATE;
7728 LOGE("gst_element_query_position failed, invalid state");
7732 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7733 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);
7735 __mmplayer_gst_send_event_to_sink(player, event);
7737 result = MM_ERROR_PLAYER_INTERNAL;
7738 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7742 /* sync state with current pipeline */
7743 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7744 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7745 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7747 return MM_ERROR_NONE;
7750 /* release text pipeline resource */
7751 player->textsink_linked = 0;
7753 /* release signal */
7754 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7756 /* release textbin with it's childs */
7757 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7758 MMPLAYER_FREEIF(player->pipeline->textbin);
7759 player->pipeline->textbin = NULL;
7761 /* release subtitle elem */
7762 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7763 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7769 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7771 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7772 GstState current_state = GST_STATE_VOID_PENDING;
7774 MMHandleType attrs = 0;
7775 MMPlayerGstElement *mainbin = NULL;
7776 MMPlayerGstElement *textbin = NULL;
7778 gchar *subtitle_uri = NULL;
7779 int result = MM_ERROR_NONE;
7780 const gchar *charset = NULL;
7784 /* check player handle */
7785 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7787 player->pipeline->mainbin &&
7788 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7789 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7791 mainbin = player->pipeline->mainbin;
7792 textbin = player->pipeline->textbin;
7794 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7795 if (current_state < GST_STATE_READY) {
7796 result = MM_ERROR_PLAYER_INVALID_STATE;
7797 LOGE("Pipeline is not in proper state");
7801 attrs = MMPLAYER_GET_ATTRS(player);
7803 LOGE("cannot get content attribute");
7804 result = MM_ERROR_PLAYER_INTERNAL;
7808 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7809 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7810 LOGE("subtitle uri is not proper filepath");
7811 result = MM_ERROR_PLAYER_INVALID_URI;
7815 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7816 LOGE("failed to get storage info of subtitle path");
7817 result = MM_ERROR_PLAYER_INVALID_URI;
7821 LOGD("old subtitle file path is [%s]", subtitle_uri);
7822 LOGD("new subtitle file path is [%s]", filepath);
7824 if (!strcmp(filepath, subtitle_uri)) {
7825 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7828 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7829 if (mm_attrs_commit_all(player->attrs)) {
7830 LOGE("failed to commit.");
7835 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7836 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7837 player->subtitle_language_list = NULL;
7838 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7840 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7841 if (ret != GST_STATE_CHANGE_SUCCESS) {
7842 LOGE("failed to change state of textbin to READY");
7843 result = MM_ERROR_PLAYER_INTERNAL;
7847 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7848 if (ret != GST_STATE_CHANGE_SUCCESS) {
7849 LOGE("failed to change state of subparse to READY");
7850 result = MM_ERROR_PLAYER_INTERNAL;
7854 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7855 if (ret != GST_STATE_CHANGE_SUCCESS) {
7856 LOGE("failed to change state of filesrc to READY");
7857 result = MM_ERROR_PLAYER_INTERNAL;
7861 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7863 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7865 charset = util_get_charset(filepath);
7867 LOGD("detected charset is %s", charset);
7868 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7871 result = _mmplayer_sync_subtitle_pipeline(player);
7878 /* API to switch between external subtitles */
7880 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7882 int result = MM_ERROR_NONE;
7883 mm_player_t *player = (mm_player_t *)hplayer;
7888 /* check player handle */
7889 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7891 /* filepath can be null in idle state */
7893 /* check file path */
7894 if ((path = strstr(filepath, "file://")))
7895 result = util_exist_file_path(path + 7);
7897 result = util_exist_file_path(filepath);
7899 if (result != MM_ERROR_NONE) {
7900 LOGE("invalid subtitle path 0x%X", result);
7901 return result; /* file not found or permission denied */
7905 if (!player->pipeline) {
7907 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7908 if (mm_attrs_commit_all(player->attrs)) {
7909 LOGE("failed to commit"); /* subtitle path will not be created */
7910 return MM_ERROR_PLAYER_INTERNAL;
7913 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7914 /* check filepath */
7915 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7917 if (!__mmplayer_check_subtitle(player)) {
7918 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7919 if (mm_attrs_commit_all(player->attrs)) {
7920 LOGE("failed to commit");
7921 return MM_ERROR_PLAYER_INTERNAL;
7924 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7925 LOGE("fail to create text pipeline");
7926 return MM_ERROR_PLAYER_INTERNAL;
7929 result = _mmplayer_sync_subtitle_pipeline(player);
7931 result = __mmplayer_change_external_subtitle_language(player, filepath);
7934 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7935 player->is_external_subtitle_added_now = TRUE;
7937 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7938 if (!player->subtitle_language_list) {
7939 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7940 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7941 LOGW("subtitle language list is not updated yet");
7943 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7951 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7953 int result = MM_ERROR_NONE;
7954 gchar *change_pad_name = NULL;
7955 GstPad *sinkpad = NULL;
7956 MMPlayerGstElement *mainbin = NULL;
7957 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7958 GstCaps *caps = NULL;
7959 gint total_track_num = 0;
7963 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7964 MM_ERROR_PLAYER_NOT_INITIALIZED);
7966 LOGD("Change Track(%d) to %d", type, index);
7968 mainbin = player->pipeline->mainbin;
7970 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7971 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7972 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7973 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7975 /* Changing Video Track is not supported. */
7976 LOGE("Track Type Error");
7980 if (mainbin[elem_idx].gst == NULL) {
7981 result = MM_ERROR_PLAYER_NO_OP;
7982 LOGD("Req track doesn't exist");
7986 total_track_num = player->selector[type].total_track_num;
7987 if (total_track_num <= 0) {
7988 result = MM_ERROR_PLAYER_NO_OP;
7989 LOGD("Language list is not available");
7993 if ((index < 0) || (index >= total_track_num)) {
7994 result = MM_ERROR_INVALID_ARGUMENT;
7995 LOGD("Not a proper index : %d", index);
7999 /*To get the new pad from the selector*/
8000 change_pad_name = g_strdup_printf("sink_%u", index);
8001 if (change_pad_name == NULL) {
8002 result = MM_ERROR_PLAYER_INTERNAL;
8003 LOGD("Pad does not exists");
8007 LOGD("new active pad name: %s", change_pad_name);
8009 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8010 if (sinkpad == NULL) {
8011 LOGD("sinkpad is NULL");
8012 result = MM_ERROR_PLAYER_INTERNAL;
8016 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8017 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8019 caps = gst_pad_get_current_caps(sinkpad);
8020 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8023 gst_object_unref(sinkpad);
8025 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8026 __mmplayer_set_audio_attrs(player, caps);
8029 MMPLAYER_FREEIF(change_pad_name);
8034 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8036 int result = MM_ERROR_NONE;
8037 mm_player_t *player = NULL;
8038 MMPlayerGstElement *mainbin = NULL;
8040 gint current_active_index = 0;
8042 GstState current_state = GST_STATE_VOID_PENDING;
8043 GstEvent *event = NULL;
8048 player = (mm_player_t *)hplayer;
8049 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8051 if (!player->pipeline) {
8052 LOGE("Track %d pre setting -> %d", type, index);
8054 player->selector[type].active_pad_index = index;
8058 mainbin = player->pipeline->mainbin;
8060 current_active_index = player->selector[type].active_pad_index;
8062 /*If index is same as running index no need to change the pad*/
8063 if (current_active_index == index)
8066 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8067 result = MM_ERROR_PLAYER_INVALID_STATE;
8071 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8072 if (current_state < GST_STATE_PAUSED) {
8073 result = MM_ERROR_PLAYER_INVALID_STATE;
8074 LOGW("Pipeline not in porper state");
8078 result = __mmplayer_change_selector_pad(player, type, index);
8079 if (result != MM_ERROR_NONE) {
8080 LOGE("change selector pad error");
8084 player->selector[type].active_pad_index = index;
8086 if (current_state == GST_STATE_PLAYING) {
8087 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8088 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8089 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8091 __mmplayer_gst_send_event_to_sink(player, event);
8093 result = MM_ERROR_PLAYER_INTERNAL;
8103 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8105 mm_player_t *player = (mm_player_t *)hplayer;
8109 /* check player handle */
8110 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8112 *silent = player->set_mode.subtitle_off;
8114 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8118 return MM_ERROR_NONE;
8122 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8124 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8125 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8127 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8128 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8132 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8133 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8134 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8135 mm_player_dump_t *dump_s;
8136 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8137 if (dump_s == NULL) {
8138 LOGE("malloc fail");
8142 dump_s->dump_element_file = NULL;
8143 dump_s->dump_pad = NULL;
8144 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8146 if (dump_s->dump_pad) {
8147 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8148 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]);
8149 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8150 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);
8151 /* add list for removed buffer probe and close FILE */
8152 player->dump_list = g_list_append(player->dump_list, dump_s);
8153 LOGD("%s sink pad added buffer probe for dump", factory_name);
8156 MMPLAYER_FREEIF(dump_s);
8157 LOGE("failed to get %s sink pad added", factory_name);
8164 static GstPadProbeReturn
8165 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8167 FILE *dump_data = (FILE *)u_data;
8169 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8170 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8172 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8174 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8176 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8178 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8180 return GST_PAD_PROBE_OK;
8184 __mmplayer_release_dump_list(GList *dump_list)
8186 GList *d_list = dump_list;
8191 for (; d_list; d_list = g_list_next(d_list)) {
8192 mm_player_dump_t *dump_s = d_list->data;
8193 if (dump_s->dump_pad) {
8194 if (dump_s->probe_handle_id)
8195 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8197 if (dump_s->dump_element_file) {
8198 fclose(dump_s->dump_element_file);
8199 dump_s->dump_element_file = NULL;
8201 MMPLAYER_FREEIF(dump_s);
8203 g_list_free(dump_list);
8208 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8210 mm_player_t *player = (mm_player_t *)hplayer;
8214 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8215 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8217 *exist = (bool)player->has_closed_caption;
8221 return MM_ERROR_NONE;
8225 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8229 // LOGD("unref internal gst buffer %p", buffer);
8230 gst_buffer_unref((GstBuffer *)buffer);
8237 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8239 mm_player_t *player = (mm_player_t *)hplayer;
8243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8244 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8246 if (MMPLAYER_IS_STREAMING(player))
8247 *timeout = (int)player->ini.live_state_change_timeout;
8249 *timeout = (int)player->ini.localplayback_state_change_timeout;
8251 LOGD("timeout = %d", *timeout);
8254 return MM_ERROR_NONE;
8258 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8260 mm_player_t *player = (mm_player_t *)hplayer;
8264 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8265 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8267 *num = player->video_num_buffers;
8268 *extra_num = player->video_extra_num_buffers;
8270 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8273 return MM_ERROR_NONE;
8277 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8281 MMPLAYER_RETURN_IF_FAIL(player);
8283 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8285 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8286 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8287 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8288 player->storage_info[i].id = -1;
8289 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8291 if (path_type != MMPLAYER_PATH_MAX)
8300 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8302 int ret = MM_ERROR_NONE;
8303 mm_player_t *player = (mm_player_t *)hplayer;
8304 MMMessageParamType msg_param = {0, };
8307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8309 LOGW("state changed storage %d:%d", id, state);
8311 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8312 return MM_ERROR_NONE;
8314 /* FIXME: text path should be handled seperately. */
8315 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8316 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8317 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8318 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8319 LOGW("external storage is removed");
8321 if (player->msg_posted == FALSE) {
8322 memset(&msg_param, 0, sizeof(MMMessageParamType));
8323 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8324 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8325 player->msg_posted = TRUE;
8328 /* unrealize the player */
8329 ret = _mmplayer_unrealize(hplayer);
8330 if (ret != MM_ERROR_NONE)
8331 LOGE("failed to unrealize");
8339 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8341 int ret = MM_ERROR_NONE;
8342 mm_player_t *player = (mm_player_t *)hplayer;
8343 int idx = 0, total = 0;
8344 gchar *result = NULL, *tmp = NULL;
8347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8348 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8350 total = *num = g_list_length(player->adaptive_info.var_list);
8352 LOGW("There is no stream variant info.");
8356 result = g_strdup("");
8357 for (idx = 0 ; idx < total ; idx++) {
8358 VariantData *v_data = NULL;
8359 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8362 gchar data[64] = {0};
8363 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8365 tmp = g_strconcat(result, data, NULL);
8369 LOGW("There is no variant data in %d", idx);
8374 *var_info = (char *)result;
8376 LOGD("variant info %d:%s", *num, *var_info);
8382 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8384 int ret = MM_ERROR_NONE;
8385 mm_player_t *player = (mm_player_t *)hplayer;
8388 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8390 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8392 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8393 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8394 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8396 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8397 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8398 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8399 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8401 /* FIXME: seek to current position for applying new variant limitation */
8410 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8412 int ret = MM_ERROR_NONE;
8413 mm_player_t *player = (mm_player_t *)hplayer;
8416 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8417 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8419 *bandwidth = player->adaptive_info.limit.bandwidth;
8420 *width = player->adaptive_info.limit.width;
8421 *height = player->adaptive_info.limit.height;
8423 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8430 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8432 int ret = MM_ERROR_NONE;
8433 mm_player_t *player = (mm_player_t *)hplayer;
8436 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8437 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8438 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8440 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8442 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8443 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8444 else /* live case */
8445 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8447 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8454 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8456 #define IDX_FIRST_SW_CODEC 0
8457 mm_player_t *player = (mm_player_t *)hplayer;
8458 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8459 MMHandleType attrs = 0;
8462 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8464 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8465 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8466 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8468 switch (stream_type) {
8469 case MM_PLAYER_STREAM_TYPE_AUDIO:
8470 /* to support audio codec selection, codec info have to be added in ini file as below.
8471 audio codec element hw = xxxx
8472 audio codec element sw = avdec */
8473 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8474 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8475 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8476 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8477 LOGE("There is no audio codec info for codec_type %d", codec_type);
8478 return MM_ERROR_PLAYER_NO_OP;
8481 case MM_PLAYER_STREAM_TYPE_VIDEO:
8482 /* to support video codec selection, codec info have to be added in ini file as below.
8483 video codec element hw = omx
8484 video codec element sw = avdec */
8485 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8486 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8487 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8488 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8489 LOGE("There is no video codec info for codec_type %d", codec_type);
8490 return MM_ERROR_PLAYER_NO_OP;
8494 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8495 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8499 LOGD("update %s codec_type to %d", attr_name, codec_type);
8501 attrs = MMPLAYER_GET_ATTRS(player);
8502 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8504 if (mm_attrs_commit_all(player->attrs)) {
8505 LOGE("failed to commit codec_type attributes");
8506 return MM_ERROR_PLAYER_INTERNAL;
8510 return MM_ERROR_NONE;
8514 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8516 mm_player_t *player = (mm_player_t *)hplayer;
8517 GstElement *rg_vol_element = NULL;
8521 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8523 player->sound.rg_enable = enabled;
8525 /* just hold rgvolume enable value if pipeline is not ready */
8526 if (!player->pipeline || !player->pipeline->audiobin) {
8527 LOGD("pipeline is not ready. holding rgvolume enable value");
8528 return MM_ERROR_NONE;
8531 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8533 if (!rg_vol_element) {
8534 LOGD("rgvolume element is not created");
8535 return MM_ERROR_PLAYER_INTERNAL;
8539 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8541 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8545 return MM_ERROR_NONE;
8549 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8551 mm_player_t *player = (mm_player_t *)hplayer;
8552 GstElement *rg_vol_element = NULL;
8553 gboolean enable = FALSE;
8557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8558 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8560 /* just hold enable_rg value if pipeline is not ready */
8561 if (!player->pipeline || !player->pipeline->audiobin) {
8562 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8563 *enabled = player->sound.rg_enable;
8564 return MM_ERROR_NONE;
8567 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8569 if (!rg_vol_element) {
8570 LOGD("rgvolume element is not created");
8571 return MM_ERROR_PLAYER_INTERNAL;
8574 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8575 *enabled = (bool)enable;
8579 return MM_ERROR_NONE;
8583 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8585 mm_player_t *player = (mm_player_t *)hplayer;
8586 MMHandleType attrs = 0;
8587 void *handle = NULL;
8588 int ret = MM_ERROR_NONE;
8592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8594 attrs = MMPLAYER_GET_ATTRS(player);
8595 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8597 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8599 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8600 return MM_ERROR_PLAYER_INTERNAL;
8603 player->video_roi.scale_x = scale_x;
8604 player->video_roi.scale_y = scale_y;
8605 player->video_roi.scale_width = scale_width;
8606 player->video_roi.scale_height = scale_height;
8608 /* check video sinkbin is created */
8609 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8610 return MM_ERROR_NONE;
8612 if (!gst_video_overlay_set_video_roi_area(
8613 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8614 scale_x, scale_y, scale_width, scale_height))
8615 ret = MM_ERROR_PLAYER_INTERNAL;
8617 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8618 scale_x, scale_y, scale_width, scale_height);
8626 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8628 mm_player_t *player = (mm_player_t *)hplayer;
8629 int ret = MM_ERROR_NONE;
8633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8634 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8636 *scale_x = player->video_roi.scale_x;
8637 *scale_y = player->video_roi.scale_y;
8638 *scale_width = player->video_roi.scale_width;
8639 *scale_height = player->video_roi.scale_height;
8641 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8642 *scale_x, *scale_y, *scale_width, *scale_height);
8648 __mmplayer_update_duration_value(mm_player_t *player)
8650 gboolean ret = FALSE;
8651 gint64 dur_nsec = 0;
8652 LOGD("try to update duration");
8654 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8655 player->duration = dur_nsec;
8656 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8660 if (player->duration < 0) {
8661 LOGW("duration is Non-Initialized !!!");
8662 player->duration = 0;
8665 /* update streaming service type */
8666 player->streaming_type = __mmplayer_get_stream_service_type(player);
8668 /* check duration is OK */
8669 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8670 /* FIXIT : find another way to get duration here. */
8671 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8677 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8679 /* update audio params
8680 NOTE : We need original audio params and it can be only obtained from src pad of audio
8681 decoder. Below code only valid when we are not using 'resampler' just before
8682 'audioconverter'. */
8683 GstCaps *caps_a = NULL;
8685 gint samplerate = 0, channels = 0;
8686 GstStructure *p = NULL;
8688 LOGD("try to update audio attrs");
8690 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8693 pad = gst_element_get_static_pad(
8694 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8697 LOGW("failed to get pad from audiosink");
8701 caps_a = gst_pad_get_current_caps(pad);
8703 LOGW("not ready to get audio caps");
8704 gst_object_unref(pad);
8708 p = gst_caps_get_structure(caps_a, 0);
8710 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8712 gst_structure_get_int(p, "rate", &samplerate);
8713 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8715 gst_structure_get_int(p, "channels", &channels);
8716 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8718 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8720 gst_caps_unref(caps_a);
8721 gst_object_unref(pad);
8727 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8729 LOGD("try to update video attrs");
8731 GstCaps *caps_v = NULL;
8735 GstStructure *p = NULL;
8737 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8738 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8740 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8742 LOGD("no videosink sink pad");
8746 caps_v = gst_pad_get_current_caps(pad);
8747 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8748 if (!caps_v && player->v_stream_caps) {
8749 caps_v = player->v_stream_caps;
8750 gst_caps_ref(caps_v);
8754 LOGD("no negitiated caps from videosink");
8755 gst_object_unref(pad);
8759 p = gst_caps_get_structure(caps_v, 0);
8760 gst_structure_get_int(p, "width", &width);
8761 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8763 gst_structure_get_int(p, "height", &height);
8764 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8766 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8768 SECURE_LOGD("width : %d height : %d", width, height);
8770 gst_caps_unref(caps_v);
8771 gst_object_unref(pad);
8774 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8775 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8782 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8784 gboolean ret = FALSE;
8785 guint64 data_size = 0;
8789 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8790 if (!player->duration)
8793 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8794 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8795 if (stat(path, &sb) == 0)
8796 data_size = (guint64)sb.st_size;
8798 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8799 data_size = player->http_content_size;
8802 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8805 guint64 bitrate = 0;
8806 guint64 msec_dur = 0;
8808 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8810 bitrate = data_size * 8 * 1000 / msec_dur;
8811 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8812 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8816 LOGD("player duration is less than 0");
8820 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8821 if (player->total_bitrate) {
8822 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8831 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8833 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8834 data->uri_type = uri_type;
8838 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8840 int ret = MM_ERROR_PLAYER_INVALID_URI;
8842 char *buffer = NULL;
8843 char *seperator = strchr(path, ',');
8844 char ext[100] = {0,}, size[100] = {0,};
8847 if ((buffer = strstr(path, "ext="))) {
8848 buffer += strlen("ext=");
8850 if (strlen(buffer)) {
8851 strncpy(ext, buffer, 99);
8853 if ((seperator = strchr(ext, ','))
8854 || (seperator = strchr(ext, ' '))
8855 || (seperator = strchr(ext, '\0'))) {
8856 seperator[0] = '\0';
8861 if ((buffer = strstr(path, "size="))) {
8862 buffer += strlen("size=");
8864 if (strlen(buffer) > 0) {
8865 strncpy(size, buffer, 99);
8867 if ((seperator = strchr(size, ','))
8868 || (seperator = strchr(size, ' '))
8869 || (seperator = strchr(size, '\0'))) {
8870 seperator[0] = '\0';
8873 mem_size = atoi(size);
8878 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8880 if (mem_size && param) {
8881 if (data->input_mem.buf)
8882 free(data->input_mem.buf);
8883 data->input_mem.buf = malloc(mem_size);
8885 if (data->input_mem.buf) {
8886 memcpy(data->input_mem.buf, param, mem_size);
8887 data->input_mem.len = mem_size;
8888 ret = MM_ERROR_NONE;
8890 LOGE("failed to alloc mem %d", mem_size);
8891 ret = MM_ERROR_PLAYER_INTERNAL;
8894 data->input_mem.offset = 0;
8895 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8902 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8904 gchar *location = NULL;
8907 int ret = MM_ERROR_NONE;
8909 if ((path = strstr(uri, "file://"))) {
8910 location = g_filename_from_uri(uri, NULL, &err);
8911 if (!location || (err != NULL)) {
8912 LOGE("Invalid URI '%s' for filesrc: %s", path,
8913 (err != NULL) ? err->message : "unknown error");
8917 MMPLAYER_FREEIF(location);
8919 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8920 return MM_ERROR_PLAYER_INVALID_URI;
8922 LOGD("path from uri: %s", location);
8925 path = (location != NULL) ? (location) : ((char *)uri);
8928 ret = util_exist_file_path(path);
8930 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8931 if (ret == MM_ERROR_NONE) {
8932 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8933 if (util_is_sdp_file(path)) {
8934 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8935 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8937 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8939 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8940 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8942 LOGE("invalid uri, could not play..");
8943 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8946 MMPLAYER_FREEIF(location);
8951 static MMPlayerVideoStreamDataType *
8952 __mmplayer_create_stream_from_pad(GstPad *pad)
8954 GstCaps *caps = NULL;
8955 GstStructure *structure = NULL;
8956 unsigned int fourcc = 0;
8957 const gchar *string_format = NULL;
8958 MMPlayerVideoStreamDataType *stream = NULL;
8960 MMPixelFormatType format;
8962 caps = gst_pad_get_current_caps(pad);
8964 LOGE("Caps is NULL.");
8968 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8969 structure = gst_caps_get_structure(caps, 0);
8970 gst_structure_get_int(structure, "width", &width);
8971 gst_structure_get_int(structure, "height", &height);
8972 string_format = gst_structure_get_string(structure, "format");
8974 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8975 format = util_get_pixtype(fourcc);
8976 gst_caps_unref(caps);
8979 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
8980 LOGE("Wrong condition!!");
8984 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
8986 LOGE("failed to alloc mem for video data");
8990 stream->width = width;
8991 stream->height = height;
8992 stream->format = format;
8998 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9000 unsigned int pitch = 0;
9002 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9004 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9005 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9006 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9007 stream->stride[index] = pitch;
9008 stream->elevation[index] = stream->height;
9013 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9015 if (stream->format == MM_PIXEL_FORMAT_I420) {
9016 int ret = TBM_SURFACE_ERROR_NONE;
9017 tbm_surface_h surface;
9018 tbm_surface_info_s info;
9020 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9022 ret = tbm_surface_get_info(surface, &info);
9023 if (ret != TBM_SURFACE_ERROR_NONE) {
9024 tbm_surface_destroy(surface);
9028 tbm_surface_destroy(surface);
9029 stream->stride[0] = info.planes[0].stride;
9030 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9031 stream->stride[1] = info.planes[1].stride;
9032 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9033 stream->stride[2] = info.planes[2].stride;
9034 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9035 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9036 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9037 stream->stride[0] = stream->width * 4;
9038 stream->elevation[0] = stream->height;
9039 stream->bo_size = stream->stride[0] * stream->height;
9041 LOGE("Not support format %d", stream->format);
9049 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9051 tbm_bo_handle thandle;
9053 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9054 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9055 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9059 unsigned char *src = NULL;
9060 unsigned char *dest = NULL;
9061 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9063 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9065 LOGE("fail to gst_memory_map");
9069 if (!mapinfo.data) {
9070 LOGE("data pointer is wrong");
9074 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9075 if (!stream->bo[0]) {
9076 LOGE("Fail to tbm_bo_alloc!!");
9080 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9082 LOGE("thandle pointer is wrong");
9086 if (stream->format == MM_PIXEL_FORMAT_I420) {
9087 src_stride[0] = GST_ROUND_UP_4(stream->width);
9088 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9089 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9090 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9093 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9094 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9096 for (i = 0; i < 3; i++) {
9097 src = mapinfo.data + src_offset[i];
9098 dest = thandle.ptr + dest_offset[i];
9103 for (j = 0; j < stream->height >> k; j++) {
9104 memcpy(dest, src, stream->width>>k);
9105 src += src_stride[i];
9106 dest += stream->stride[i];
9109 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9110 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9112 LOGE("Not support format %d", stream->format);
9116 tbm_bo_unmap(stream->bo[0]);
9117 gst_memory_unmap(mem, &mapinfo);
9123 tbm_bo_unmap(stream->bo[0]);
9126 gst_memory_unmap(mem, &mapinfo);
9132 __mmplayer_set_pause_state(mm_player_t *player)
9134 if (player->sent_bos)
9137 /* rtsp case, get content attrs by GstMessage */
9138 if (MMPLAYER_IS_RTSP_STREAMING(player))
9141 /* it's first time to update all content attrs. */
9142 __mmplayer_update_content_attrs(player, ATTR_ALL);
9146 __mmplayer_set_playing_state(mm_player_t *player)
9148 gchar *audio_codec = NULL;
9150 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9151 /* initialize because auto resume is done well. */
9152 player->resumed_by_rewind = FALSE;
9153 player->playback_rate = 1.0;
9156 if (player->sent_bos)
9159 /* try to get content metadata */
9161 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9162 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9163 * legacy mmfw-player api
9165 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9167 if ((player->cmd == MMPLAYER_COMMAND_START)
9168 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9169 __mmplayer_handle_missed_plugin(player);
9172 /* check audio codec field is set or not
9173 * we can get it from typefinder or codec's caps.
9175 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9177 /* The codec format can't be sent for audio only case like amr, mid etc.
9178 * Because, parser don't make related TAG.
9179 * So, if it's not set yet, fill it with found data.
9182 if (g_strrstr(player->type, "audio/midi"))
9183 audio_codec = "MIDI";
9184 else if (g_strrstr(player->type, "audio/x-amr"))
9185 audio_codec = "AMR";
9186 else if (g_strrstr(player->type, "audio/mpeg")
9187 && !g_strrstr(player->type, "mpegversion= (int)1"))
9188 audio_codec = "AAC";
9190 audio_codec = "unknown";
9192 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9194 if (mm_attrs_commit_all(player->attrs))
9195 LOGE("failed to update attributes");
9197 LOGD("set audio codec type with caps");