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);
1062 gst_object_unref(GST_OBJECT(srcpad));
1069 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1071 mm_player_t *player = (mm_player_t *)data;
1072 GstElement *selector = NULL;
1073 GstCaps *caps = NULL;
1074 GstStructure *str = NULL;
1075 const gchar *name = NULL;
1076 GstPad *sinkpad = NULL;
1077 gboolean first_track = FALSE;
1078 gboolean caps_ret = TRUE;
1080 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1081 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1084 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1085 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1087 LOGD("pad-added signal handling");
1089 /* get mimetype from caps */
1090 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1094 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1095 /* LOGD("detected mimetype : %s", name); */
1097 if (strstr(name, "video")) {
1099 gchar *caps_str = NULL;
1101 caps_str = gst_caps_to_string(caps);
1102 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1103 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1104 player->set_mode.video_zc = true;
1106 MMPLAYER_FREEIF(caps_str);
1108 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1109 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1111 LOGD("surface type : %d", stype);
1113 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1114 __mmplayer_gst_create_sinkbin(elem, pad, player);
1118 /* in case of exporting video frame, it requires the 360 video filter.
1119 * it will be handled in _no_more_pads(). */
1120 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1121 __mmplayer_gst_make_fakesink(player, pad, name);
1125 LOGD("video selector is required");
1126 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1127 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1128 } else if (strstr(name, "audio")) {
1129 gint samplerate = 0;
1132 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1133 if (player->build_audio_offload)
1134 player->no_more_pad = TRUE; /* remove state holder */
1135 __mmplayer_gst_create_sinkbin(elem, pad, player);
1139 gst_structure_get_int(str, "rate", &samplerate);
1140 gst_structure_get_int(str, "channels", &channels);
1142 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1143 __mmplayer_gst_make_fakesink(player, pad, name);
1147 LOGD("audio selector is required");
1148 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1149 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1151 } else if (strstr(name, "text")) {
1152 LOGD("text selector is required");
1153 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1154 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1156 LOGE("invalid caps info");
1160 /* check selector and create it */
1161 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1162 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1167 LOGD("input-selector is already created.");
1171 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1173 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1175 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1176 LOGE("failed to link selector");
1177 gst_object_unref(GST_OBJECT(selector));
1182 LOGD("this track will be activated");
1183 g_object_set(selector, "active-pad", sinkpad, NULL);
1186 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1192 gst_caps_unref(caps);
1195 gst_object_unref(GST_OBJECT(sinkpad));
1203 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1205 GstPad *srcpad = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1210 LOGD("type %d", type);
1213 LOGD("there is no %d track", type);
1217 srcpad = gst_element_get_static_pad(selector, "src");
1219 LOGE("failed to get srcpad from selector");
1223 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1225 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1227 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1228 if (player->selector[type].block_id) {
1229 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1230 player->selector[type].block_id = 0;
1234 gst_object_unref(GST_OBJECT(srcpad));
1243 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1245 MMHandleType attrs = 0;
1246 gint active_index = 0;
1249 MMPLAYER_RETURN_IF_FAIL(player);
1251 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1253 /* change track to active pad */
1254 active_index = player->selector[type].active_pad_index;
1255 if ((active_index != DEFAULT_TRACK) &&
1256 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1257 LOGW("failed to change %d type track to %d", type, active_index);
1258 player->selector[type].active_pad_index = DEFAULT_TRACK;
1262 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1263 attrs = MMPLAYER_GET_ATTRS(player);
1265 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1266 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1268 if (mm_attrs_commit_all(attrs))
1269 LOGW("failed to commit attrs.");
1271 LOGW("cannot get content attribute");
1280 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1283 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1285 if (!audio_selector) {
1286 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1288 /* in case the source is changed, output can be changed. */
1289 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1290 LOGD("remove previous audiobin if it exist");
1292 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1293 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1295 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1296 MMPLAYER_FREEIF(player->pipeline->audiobin);
1299 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1300 __mmplayer_pipeline_complete(NULL, player);
1305 /* apply the audio track information */
1306 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1308 /* create audio sink path */
1309 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1310 LOGE("failed to create audio sink path");
1319 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1322 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1324 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1325 LOGD("text path is not supproted");
1329 /* apply the text track information */
1330 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1332 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1333 player->has_closed_caption = TRUE;
1335 /* create text decode path */
1336 player->no_more_pad = TRUE;
1338 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1339 LOGE("failed to create text sink path");
1348 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1350 gint64 dur_bytes = 0L;
1353 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1354 player->pipeline->mainbin && player->streamer, FALSE);
1356 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1357 LOGE("fail to get duration.");
1359 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1360 * use file information was already set on Q2 when it was created. */
1361 __mm_player_streaming_set_queue2(player->streamer,
1362 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1363 TRUE, /* use_buffering */
1364 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1365 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1372 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1374 mm_player_t *player = NULL;
1375 GstElement *video_selector = NULL;
1376 GstElement *audio_selector = NULL;
1377 GstElement *text_selector = NULL;
1380 player = (mm_player_t *)data;
1382 LOGD("no-more-pad signal handling");
1384 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1385 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1386 LOGW("player is shutting down");
1390 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1391 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1392 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1393 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1394 LOGE("failed to set queue2 buffering");
1399 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1400 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1401 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1403 if (!video_selector && !audio_selector && !text_selector) {
1404 LOGW("there is no selector");
1405 player->no_more_pad = TRUE;
1409 /* create video path followed by video-select */
1410 if (video_selector && !audio_selector && !text_selector)
1411 player->no_more_pad = TRUE;
1413 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1416 /* create audio path followed by audio-select */
1417 if (audio_selector && !text_selector)
1418 player->no_more_pad = TRUE;
1420 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1423 /* create text path followed by text-select */
1424 __mmplayer_create_text_sink_path(player, text_selector);
1427 if (player->gapless.reconfigure) {
1428 player->gapless.reconfigure = FALSE;
1429 MMPLAYER_PLAYBACK_UNLOCK(player);
1436 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1438 gboolean ret = FALSE;
1439 GstElement *pipeline = NULL;
1440 GstPad *sinkpad = NULL;
1443 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1446 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1448 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1450 LOGE("failed to get pad from sinkbin");
1456 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1457 LOGE("failed to link sinkbin for reusing");
1458 goto EXIT; /* exit either pass or fail */
1462 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1463 LOGE("failed to set state(READY) to sinkbin");
1468 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1469 LOGE("failed to add sinkbin to pipeline");
1474 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1475 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1480 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1481 LOGE("failed to set state(PAUSED) to sinkbin");
1490 gst_object_unref(GST_OBJECT(sinkpad));
1498 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1500 mm_player_t *player = NULL;
1501 GstCaps *caps = NULL;
1502 gchar *caps_str = NULL;
1503 GstStructure *str = NULL;
1504 const gchar *name = NULL;
1505 GstElement *sinkbin = NULL;
1506 gboolean reusing = FALSE;
1507 gboolean caps_ret = TRUE;
1508 gchar *sink_pad_name = "sink";
1511 player = (mm_player_t *)data;
1514 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1517 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1521 caps_str = gst_caps_to_string(caps);
1523 /* LOGD("detected mimetype : %s", name); */
1524 if (strstr(name, "audio")) {
1525 if (player->pipeline->audiobin == NULL) {
1526 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1527 LOGE("failed to create audiobin. continuing without audio");
1531 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1532 LOGD("creating audiobin success");
1535 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1536 LOGD("reusing audiobin");
1537 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1539 } else if (strstr(name, "video")) {
1540 /* 1. zero copy is updated at _decode_pad_added()
1541 * 2. NULL surface type is handled in _decode_pad_added() */
1542 LOGD("zero copy %d", player->set_mode.video_zc);
1543 if (player->pipeline->videobin == NULL) {
1544 int surface_type = 0;
1545 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1546 LOGD("display_surface_type (%d)", surface_type);
1548 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1549 LOGD("mark video overlay for acquire");
1550 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1551 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1552 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1553 &player->video_overlay_resource)
1554 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1555 LOGE("could not mark video_overlay resource for acquire");
1560 player->interrupted_by_resource = FALSE;
1562 if (mm_resource_manager_commit(player->resource_manager) !=
1563 MM_RESOURCE_MANAGER_ERROR_NONE) {
1564 LOGE("could not acquire resources for video playing");
1568 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1569 LOGE("failed to create videobin. continuing without video");
1573 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1574 LOGD("creating videosink bin success");
1577 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1578 LOGD("re-using videobin");
1579 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1581 } else if (strstr(name, "text")) {
1582 if (player->pipeline->textbin == NULL) {
1583 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1584 LOGE("failed to create text sink bin. continuing without text");
1588 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1589 player->textsink_linked = 1;
1590 LOGD("creating textsink bin success");
1592 if (!player->textsink_linked) {
1593 LOGD("re-using textbin");
1595 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1596 player->textsink_linked = 1;
1598 /* linked textbin exist which means that the external subtitle path exist already */
1599 LOGW("ignoring internal subtutle since external subtitle is available");
1602 sink_pad_name = "text_sink";
1604 LOGW("unknown mime type %s, ignoring it", name);
1608 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1611 LOGD("[handle: %p] success to create and link sink bin", player);
1613 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1614 * streaming task. if the task blocked, then buffer will not flow to the next element
1615 *(autoplugging element). so this is special hack for streaming. please try to remove it
1617 /* dec stream count. we can remove fakesink if it's zero */
1618 if (player->num_dynamic_pad)
1619 player->num_dynamic_pad--;
1621 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1623 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1624 __mmplayer_pipeline_complete(NULL, player);
1628 MMPLAYER_FREEIF(caps_str);
1631 gst_caps_unref(caps);
1637 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1639 int required_angle = 0; /* Angle required for straight view */
1640 int rotation_angle = 0;
1642 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1643 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1645 /* Counter clockwise */
1646 switch (orientation) {
1651 required_angle = 270;
1654 required_angle = 180;
1657 required_angle = 90;
1661 rotation_angle = display_angle + required_angle;
1662 if (rotation_angle >= 360)
1663 rotation_angle -= 360;
1665 /* chech if supported or not */
1666 if (rotation_angle % 90) {
1667 LOGD("not supported rotation angle = %d", rotation_angle);
1671 switch (rotation_angle) {
1673 *value = MM_DISPLAY_ROTATION_NONE;
1676 *value = MM_DISPLAY_ROTATION_90;
1679 *value = MM_DISPLAY_ROTATION_180;
1682 *value = MM_DISPLAY_ROTATION_270;
1686 LOGD("setting rotation property value : %d", *value);
1692 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1694 /* check video sinkbin is created */
1695 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1697 player->pipeline->videobin &&
1698 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1699 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1700 MM_ERROR_PLAYER_NOT_INITIALIZED);
1702 return MM_ERROR_NONE;
1706 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1708 int display_rotation = 0;
1709 gchar *org_orient = NULL;
1710 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1713 LOGE("cannot get content attribute");
1714 return MM_ERROR_PLAYER_INTERNAL;
1717 if (display_angle) {
1718 /* update user roation */
1719 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1721 /* Counter clockwise */
1722 switch (display_rotation) {
1723 case MM_DISPLAY_ROTATION_NONE:
1726 case MM_DISPLAY_ROTATION_90:
1727 *display_angle = 90;
1729 case MM_DISPLAY_ROTATION_180:
1730 *display_angle = 180;
1732 case MM_DISPLAY_ROTATION_270:
1733 *display_angle = 270;
1736 LOGW("wrong angle type : %d", display_rotation);
1739 LOGD("check user angle: %d", *display_angle);
1743 /* Counter clockwise */
1744 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1747 if (!strcmp(org_orient, "rotate-90"))
1749 else if (!strcmp(org_orient, "rotate-180"))
1751 else if (!strcmp(org_orient, "rotate-270"))
1754 LOGD("original rotation is %s", org_orient);
1756 LOGD("content_video_orientation get fail");
1759 LOGD("check orientation: %d", *orientation);
1762 return MM_ERROR_NONE;
1766 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1768 int rotation_value = 0;
1769 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1770 int display_angle = 0;
1773 /* check video sinkbin is created */
1774 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1777 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1779 /* get rotation value to set */
1780 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1781 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1782 LOGD("set video param : rotate %d", rotation_value);
1786 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1788 MMHandleType attrs = 0;
1792 /* check video sinkbin is created */
1793 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1796 attrs = MMPLAYER_GET_ATTRS(player);
1797 MMPLAYER_RETURN_IF_FAIL(attrs);
1799 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1800 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1801 LOGD("set video param : visible %d", visible);
1805 __mmplayer_video_param_set_display_method(mm_player_t *player)
1807 MMHandleType attrs = 0;
1808 int display_method = 0;
1811 /* check video sinkbin is created */
1812 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1815 attrs = MMPLAYER_GET_ATTRS(player);
1816 MMPLAYER_RETURN_IF_FAIL(attrs);
1818 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1819 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1820 LOGD("set video param : method %d", display_method);
1824 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1826 MMHandleType attrs = 0;
1827 void *handle = NULL;
1830 /* check video sinkbin is created */
1831 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1832 LOGW("There is no video sink");
1836 attrs = MMPLAYER_GET_ATTRS(player);
1837 MMPLAYER_RETURN_IF_FAIL(attrs);
1838 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1840 gst_video_overlay_set_video_roi_area(
1841 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1842 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1843 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1844 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1849 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1851 MMHandleType attrs = 0;
1852 void *handle = NULL;
1856 int win_roi_width = 0;
1857 int win_roi_height = 0;
1860 /* check video sinkbin is created */
1861 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1862 LOGW("There is no video sink");
1866 attrs = MMPLAYER_GET_ATTRS(player);
1867 MMPLAYER_RETURN_IF_FAIL(attrs);
1869 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1872 /* It should be set after setting window */
1873 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1874 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1875 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1876 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1878 /* After setting window handle, set display roi area */
1879 gst_video_overlay_set_display_roi_area(
1880 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1881 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1882 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1883 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1888 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1890 MMHandleType attrs = 0;
1891 void *handle = NULL;
1893 /* check video sinkbin is created */
1894 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1897 attrs = MMPLAYER_GET_ATTRS(player);
1898 MMPLAYER_RETURN_IF_FAIL(attrs);
1900 /* common case if using overlay surface */
1901 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1904 /* default is using wl_surface_id */
1905 unsigned int wl_surface_id = 0;
1906 wl_surface_id = *(int *)handle;
1907 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1908 gst_video_overlay_set_wl_window_wl_surface_id(
1909 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1912 /* FIXIT : is it error case? */
1913 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1918 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1920 gboolean update_all_param = FALSE;
1923 /* check video sinkbin is created */
1924 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1925 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1927 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1928 LOGE("can not find tizenwlsink");
1929 return MM_ERROR_PLAYER_INTERNAL;
1932 LOGD("param_name : %s", param_name);
1933 if (!g_strcmp0(param_name, "update_all_param"))
1934 update_all_param = TRUE;
1936 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1937 __mmplayer_video_param_set_display_overlay(player);
1938 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1939 __mmplayer_video_param_set_display_method(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1941 __mmplayer_video_param_set_display_visible(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1943 __mmplayer_video_param_set_display_rotation(player);
1944 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1945 __mmplayer_video_param_set_roi_area(player);
1946 if (update_all_param)
1947 __mmplayer_video_param_set_video_roi_area(player);
1949 return MM_ERROR_NONE;
1953 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1955 MMHandleType attrs = 0;
1956 int surface_type = 0;
1957 int ret = MM_ERROR_NONE;
1961 /* check video sinkbin is created */
1962 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1963 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1965 attrs = MMPLAYER_GET_ATTRS(player);
1967 LOGE("cannot get content attribute");
1968 return MM_ERROR_PLAYER_INTERNAL;
1970 LOGD("param_name : %s", param_name);
1972 /* update display surface */
1973 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1974 LOGD("check display surface type attribute: %d", surface_type);
1976 /* configuring display */
1977 switch (surface_type) {
1978 case MM_DISPLAY_SURFACE_OVERLAY:
1980 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1981 if (ret != MM_ERROR_NONE)
1989 return MM_ERROR_NONE;
1993 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1995 gboolean disable_overlay = FALSE;
1996 mm_player_t *player = (mm_player_t *)hplayer;
1997 int ret = MM_ERROR_NONE;
2000 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2001 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2002 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2003 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2005 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2006 LOGW("Display control is not supported");
2007 return MM_ERROR_PLAYER_INTERNAL;
2010 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2012 if (audio_only == (bool)disable_overlay) {
2013 LOGE("It's the same with current setting: (%d)", audio_only);
2014 return MM_ERROR_NONE;
2018 LOGE("disable overlay");
2019 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2021 /* release overlay resource */
2022 if (player->video_overlay_resource != NULL) {
2023 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2024 player->video_overlay_resource);
2025 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2026 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2029 player->video_overlay_resource = NULL;
2032 ret = mm_resource_manager_commit(player->resource_manager);
2033 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2034 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2038 /* mark video overlay for acquire */
2039 if (player->video_overlay_resource == NULL) {
2040 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2041 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2042 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2043 &player->video_overlay_resource);
2044 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2045 LOGE("could not prepare for video_overlay resource");
2050 player->interrupted_by_resource = FALSE;
2051 /* acquire resources for video overlay */
2052 ret = mm_resource_manager_commit(player->resource_manager);
2053 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2054 LOGE("could not acquire resources for video playing");
2058 LOGD("enable overlay");
2059 __mmplayer_video_param_set_display_overlay(player);
2060 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2065 return MM_ERROR_NONE;
2069 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2071 mm_player_t *player = (mm_player_t *)hplayer;
2072 gboolean disable_overlay = FALSE;
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2077 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2078 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2079 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2080 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2082 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2083 LOGW("Display control is not supported");
2084 return MM_ERROR_PLAYER_INTERNAL;
2087 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2089 *paudio_only = (bool)disable_overlay;
2091 LOGD("audio_only : %d", *paudio_only);
2095 return MM_ERROR_NONE;
2099 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2101 GList *bucket = element_bucket;
2102 MMPlayerGstElement *element = NULL;
2103 MMPlayerGstElement *prv_element = NULL;
2104 gint successful_link_count = 0;
2108 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2110 prv_element = (MMPlayerGstElement *)bucket->data;
2111 bucket = bucket->next;
2113 for (; bucket; bucket = bucket->next) {
2114 element = (MMPlayerGstElement *)bucket->data;
2116 if (element && element->gst) {
2117 if (prv_element && prv_element->gst) {
2118 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2119 LOGD("linking [%s] to [%s] success",
2120 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2121 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2122 successful_link_count++;
2124 LOGD("linking [%s] to [%s] failed",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2132 prv_element = element;
2137 return successful_link_count;
2141 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2143 GList *bucket = element_bucket;
2144 MMPlayerGstElement *element = NULL;
2145 int successful_add_count = 0;
2149 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2150 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2152 for (; bucket; bucket = bucket->next) {
2153 element = (MMPlayerGstElement *)bucket->data;
2155 if (element && element->gst) {
2156 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2157 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2158 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2159 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2162 successful_add_count++;
2168 return successful_add_count;
2172 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2174 mm_player_t *player = (mm_player_t *)data;
2175 GstCaps *caps = NULL;
2176 GstStructure *str = NULL;
2178 gboolean caps_ret = TRUE;
2182 MMPLAYER_RETURN_IF_FAIL(pad);
2183 MMPLAYER_RETURN_IF_FAIL(unused);
2184 MMPLAYER_RETURN_IF_FAIL(data);
2186 caps = gst_pad_get_current_caps(pad);
2190 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2194 LOGD("name = %s", name);
2196 if (strstr(name, "audio")) {
2197 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2199 if (player->audio_stream_changed_cb) {
2200 LOGE("call the audio stream changed cb");
2201 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2203 } else if (strstr(name, "video")) {
2204 if ((name = gst_structure_get_string(str, "format")))
2205 player->set_mode.video_zc = name[0] == 'S';
2207 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2209 if (player->video_stream_changed_cb) {
2210 LOGE("call the video stream changed cb");
2211 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2214 LOGW("invalid caps info");
2219 gst_caps_unref(caps);
2227 * This function is to create audio pipeline for playing.
2229 * @param player [in] handle of player
2231 * @return This function returns zero on success.
2233 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2235 /* macro for code readability. just for sinkbin-creation functions */
2236 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2238 x_bin[x_id].id = x_id;\
2239 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2240 if (!x_bin[x_id].gst) {\
2241 LOGE("failed to create %s", x_factory);\
2244 if (x_player->ini.set_dump_element_flag)\
2245 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2248 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2252 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2257 MMPLAYER_RETURN_IF_FAIL(player);
2259 if (player->audio_stream_buff_list) {
2260 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2261 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2264 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2265 __mmplayer_audio_stream_send_data(player, tmp);
2267 MMPLAYER_FREEIF(tmp->pcm_data);
2268 MMPLAYER_FREEIF(tmp);
2271 g_list_free(player->audio_stream_buff_list);
2272 player->audio_stream_buff_list = NULL;
2279 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2281 MMPlayerAudioStreamDataType audio_stream = { 0, };
2284 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2286 audio_stream.bitrate = a_buffer->bitrate;
2287 audio_stream.channel = a_buffer->channel;
2288 audio_stream.depth = a_buffer->depth;
2289 audio_stream.is_little_endian = a_buffer->is_little_endian;
2290 audio_stream.channel_mask = a_buffer->channel_mask;
2291 audio_stream.data_size = a_buffer->data_size;
2292 audio_stream.data = a_buffer->pcm_data;
2294 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2295 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2301 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2303 mm_player_t *player = (mm_player_t *)data;
2307 gint endianness = 0;
2308 guint64 channel_mask = 0;
2309 void *a_data = NULL;
2311 mm_player_audio_stream_buff_t *a_buffer = NULL;
2312 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2316 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2318 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2319 a_data = mapinfo.data;
2320 a_size = mapinfo.size;
2322 GstCaps *caps = gst_pad_get_current_caps(pad);
2323 GstStructure *structure = gst_caps_get_structure(caps, 0);
2325 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2326 gst_structure_get_int(structure, "rate", &rate);
2327 gst_structure_get_int(structure, "channels", &channel);
2328 gst_structure_get_int(structure, "depth", &depth);
2329 gst_structure_get_int(structure, "endianness", &endianness);
2330 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2331 gst_caps_unref(GST_CAPS(caps));
2333 /* In case of the sync is false, use buffer list. *
2334 * The num of buffer list depends on the num of audio channels */
2335 if (player->audio_stream_buff_list) {
2336 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2337 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2339 if (channel_mask == tmp->channel_mask) {
2340 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2341 if (tmp->data_size + a_size < tmp->buff_size) {
2342 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2343 tmp->data_size += a_size;
2345 /* send data to client */
2346 __mmplayer_audio_stream_send_data(player, tmp);
2348 if (a_size > tmp->buff_size) {
2349 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2350 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2351 if (tmp->pcm_data == NULL) {
2352 LOGE("failed to realloc data.");
2355 tmp->buff_size = a_size;
2357 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2358 memcpy(tmp->pcm_data, a_data, a_size);
2359 tmp->data_size = a_size;
2364 LOGE("data is empty in list.");
2370 /* create new audio stream data */
2371 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2372 if (a_buffer == NULL) {
2373 LOGE("failed to alloc data.");
2376 a_buffer->bitrate = rate;
2377 a_buffer->channel = channel;
2378 a_buffer->depth = depth;
2379 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2380 a_buffer->channel_mask = channel_mask;
2381 a_buffer->data_size = a_size;
2383 if (!player->audio_stream_sink_sync) {
2384 /* If sync is FALSE, use buffer list to reduce the IPC. */
2385 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2386 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2387 if (a_buffer->pcm_data == NULL) {
2388 LOGE("failed to alloc data.");
2389 MMPLAYER_FREEIF(a_buffer);
2392 memcpy(a_buffer->pcm_data, a_data, a_size);
2393 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2394 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2396 /* If sync is TRUE, send data directly. */
2397 a_buffer->pcm_data = a_data;
2398 __mmplayer_audio_stream_send_data(player, a_buffer);
2399 MMPLAYER_FREEIF(a_buffer);
2403 gst_buffer_unmap(buffer, &mapinfo);
2408 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2410 mm_player_t *player = (mm_player_t *)data;
2411 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2412 GstPad *sinkpad = NULL;
2413 GstElement *queue = NULL, *sink = NULL;
2416 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2418 queue = gst_element_factory_make("queue", NULL);
2419 if (queue == NULL) {
2420 LOGD("fail make queue");
2424 sink = gst_element_factory_make("fakesink", NULL);
2426 LOGD("fail make fakesink");
2430 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2432 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2433 LOGW("failed to link queue & sink");
2437 sinkpad = gst_element_get_static_pad(queue, "sink");
2439 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2440 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2444 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2446 gst_object_unref(sinkpad);
2447 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2448 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2450 gst_element_set_state(sink, GST_STATE_PAUSED);
2451 gst_element_set_state(queue, GST_STATE_PAUSED);
2453 __mmplayer_add_signal_connection(player,
2455 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2457 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2464 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2466 gst_object_unref(GST_OBJECT(queue));
2470 gst_object_unref(GST_OBJECT(sink));
2474 gst_object_unref(GST_OBJECT(sinkpad));
2482 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2484 #define MAX_PROPS_LEN 128
2485 gint latency_mode = 0;
2486 gchar *stream_type = NULL;
2487 gchar *latency = NULL;
2489 gchar stream_props[MAX_PROPS_LEN] = {0,};
2490 GstStructure *props = NULL;
2493 * It should be set after player creation through attribute.
2494 * But, it can not be changed during playing.
2497 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2499 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2500 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2503 LOGE("stream_type is null.");
2505 if (player->sound.focus_id)
2506 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2507 stream_type, stream_id, player->sound.focus_id);
2509 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2510 stream_type, stream_id);
2511 props = gst_structure_from_string(stream_props, NULL);
2512 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2513 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2514 stream_type, stream_id, player->sound.focus_id, stream_props);
2515 gst_structure_free(props);
2518 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2520 switch (latency_mode) {
2521 case AUDIO_LATENCY_MODE_LOW:
2522 latency = g_strndup("low", 3);
2524 case AUDIO_LATENCY_MODE_MID:
2525 latency = g_strndup("mid", 3);
2527 case AUDIO_LATENCY_MODE_HIGH:
2528 latency = g_strndup("high", 4);
2532 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2536 LOGD("audiosink property - latency=%s", latency);
2538 MMPLAYER_FREEIF(latency);
2544 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2546 MMPlayerGstElement *audiobin = NULL;
2549 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2551 audiobin = player->pipeline->audiobin;
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2554 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2557 if (player->video360_yaw_radians <= M_PI &&
2558 player->video360_yaw_radians >= -M_PI &&
2559 player->video360_pitch_radians <= M_PI_2 &&
2560 player->video360_pitch_radians >= -M_PI_2) {
2561 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2562 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2563 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2564 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2565 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2566 "source-orientation-y", player->video360_metadata.init_view_heading,
2567 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2574 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2576 MMPlayerGstElement *audiobin = NULL;
2577 MMHandleType attrs = 0;
2578 GList *element_bucket = NULL;
2579 GstCaps *acaps = NULL;
2580 GstPad *sink_pad = NULL;
2581 int pitch_control = 0;
2582 double pitch_value = 1.0;
2585 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2586 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2588 audiobin = player->pipeline->audiobin;
2589 attrs = MMPLAYER_GET_ATTRS(player);
2591 if (player->build_audio_offload) { /* skip all the audio filters */
2592 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2593 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2594 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2595 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2600 mm_attrs_multiple_get(player->attrs, NULL,
2601 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2602 MM_PLAYER_PITCH_VALUE, &pitch_value,
2605 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2606 if (pitch_control && (player->videodec_linked == 0)) {
2607 GstElementFactory *factory;
2609 factory = gst_element_factory_find("pitch");
2611 gst_object_unref(factory);
2614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2617 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2618 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2620 LOGW("there is no pitch element");
2625 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2627 /* replaygain volume */
2628 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2629 if (player->sound.rg_enable)
2630 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2632 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2635 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2637 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2638 gchar *dst_format = NULL;
2640 int dst_samplerate = 0;
2641 int dst_channels = 0;
2642 GstCaps *caps = NULL;
2643 char *caps_str = NULL;
2645 /* get conf. values */
2646 mm_attrs_multiple_get(player->attrs, NULL,
2647 "pcm_audioformat", &dst_format, &dst_len,
2648 "pcm_extraction_samplerate", &dst_samplerate,
2649 "pcm_extraction_channels", &dst_channels,
2652 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2655 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2656 caps = gst_caps_new_simple("audio/x-raw",
2657 "format", G_TYPE_STRING, dst_format,
2658 "rate", G_TYPE_INT, dst_samplerate,
2659 "channels", G_TYPE_INT, dst_channels,
2662 caps_str = gst_caps_to_string(caps);
2663 LOGD("new caps : %s", caps_str);
2665 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2668 gst_caps_unref(caps);
2669 MMPLAYER_FREEIF(caps_str);
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2673 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2675 /* raw pad handling signal, audiosink will be added after getting signal */
2676 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2677 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2681 /* normal playback */
2684 /* for logical volume control */
2685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2686 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2688 if (player->sound.mute) {
2689 LOGD("mute enabled");
2690 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2693 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2695 /* audio effect element. if audio effect is enabled */
2696 if ((strcmp(player->ini.audioeffect_element, ""))
2698 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2699 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2701 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2703 if ((!player->bypass_audio_effect)
2704 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2705 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2706 if (!_mmplayer_audio_effect_custom_apply(player))
2707 LOGI("apply audio effect(custom) setting success");
2711 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2712 && (player->set_mode.rich_audio))
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2716 /* create audio sink */
2717 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2718 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2719 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2721 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2722 if (player->is_360_feature_enabled &&
2723 player->is_content_spherical &&
2725 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2726 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2727 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2729 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2734 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2736 gst_caps_unref(acaps);
2738 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2740 player->is_openal_plugin_used = TRUE;
2742 if (player->is_360_feature_enabled && player->is_content_spherical)
2743 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2744 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2747 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2748 (player->videodec_linked && player->ini.use_system_clock)) {
2749 LOGD("system clock will be used.");
2750 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2753 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2754 __mmplayer_gst_set_pulsesink_property(player, attrs);
2755 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2756 __mmplayer_gst_set_openalsink_property(player);
2759 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2760 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2762 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2763 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2764 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2765 gst_object_unref(GST_OBJECT(sink_pad));
2767 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2771 *bucket = element_bucket;
2774 return MM_ERROR_NONE;
2777 g_list_free(element_bucket);
2781 return MM_ERROR_PLAYER_INTERNAL;
2785 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2787 MMPlayerGstElement *first_element = NULL;
2788 MMPlayerGstElement *audiobin = NULL;
2790 GstPad *ghostpad = NULL;
2791 GList *element_bucket = NULL;
2795 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2798 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2800 LOGE("failed to allocate memory for audiobin");
2801 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2805 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2806 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2807 if (!audiobin[MMPLAYER_A_BIN].gst) {
2808 LOGE("failed to create audiobin");
2813 player->pipeline->audiobin = audiobin;
2815 /* create audio filters and audiosink */
2816 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2819 /* adding created elements to bin */
2820 LOGD("adding created elements to bin");
2821 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2824 /* linking elements in the bucket by added order. */
2825 LOGD("Linking elements in the bucket by added order.");
2826 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2829 /* get first element's sinkpad for creating ghostpad */
2830 first_element = (MMPlayerGstElement *)element_bucket->data;
2831 if (!first_element) {
2832 LOGE("failed to get first elem");
2836 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2838 LOGE("failed to get pad from first element of audiobin");
2842 ghostpad = gst_ghost_pad_new("sink", pad);
2844 LOGE("failed to create ghostpad");
2848 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2849 LOGE("failed to add ghostpad to audiobin");
2853 gst_object_unref(pad);
2855 g_list_free(element_bucket);
2858 return MM_ERROR_NONE;
2861 LOGD("ERROR : releasing audiobin");
2864 gst_object_unref(GST_OBJECT(pad));
2867 gst_object_unref(GST_OBJECT(ghostpad));
2870 g_list_free(element_bucket);
2872 /* release element which are not added to bin */
2873 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2874 /* NOTE : skip bin */
2875 if (audiobin[i].gst) {
2876 GstObject *parent = NULL;
2877 parent = gst_element_get_parent(audiobin[i].gst);
2880 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2881 audiobin[i].gst = NULL;
2883 gst_object_unref(GST_OBJECT(parent));
2887 /* release audiobin with it's childs */
2888 if (audiobin[MMPLAYER_A_BIN].gst)
2889 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2891 MMPLAYER_FREEIF(audiobin);
2893 player->pipeline->audiobin = NULL;
2895 return MM_ERROR_PLAYER_INTERNAL;
2899 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2901 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2905 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2907 int ret = MM_ERROR_NONE;
2909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2910 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2912 MMPLAYER_VIDEO_BO_LOCK(player);
2914 if (player->video_bo_list) {
2915 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2916 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2917 if (tmp && tmp->bo == bo) {
2919 LOGD("release bo %p", bo);
2920 tbm_bo_unref(tmp->bo);
2921 MMPLAYER_VIDEO_BO_UNLOCK(player);
2922 MMPLAYER_VIDEO_BO_SIGNAL(player);
2927 /* hw codec is running or the list was reset for DRC. */
2928 LOGW("there is no bo list.");
2930 MMPLAYER_VIDEO_BO_UNLOCK(player);
2932 LOGW("failed to find bo %p", bo);
2937 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2942 MMPLAYER_RETURN_IF_FAIL(player);
2944 MMPLAYER_VIDEO_BO_LOCK(player);
2945 if (player->video_bo_list) {
2946 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2947 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2948 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2951 tbm_bo_unref(tmp->bo);
2955 g_list_free(player->video_bo_list);
2956 player->video_bo_list = NULL;
2958 player->video_bo_size = 0;
2959 MMPLAYER_VIDEO_BO_UNLOCK(player);
2966 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2969 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2970 gboolean ret = TRUE;
2972 /* check DRC, if it is, destroy the prev bo list to create again */
2973 if (player->video_bo_size != size) {
2974 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2975 __mmplayer_video_stream_destroy_bo_list(player);
2976 player->video_bo_size = size;
2979 MMPLAYER_VIDEO_BO_LOCK(player);
2981 if ((!player->video_bo_list) ||
2982 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2984 /* create bo list */
2986 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2988 if (player->video_bo_list) {
2989 /* if bo list did not created all, try it again. */
2990 idx = g_list_length(player->video_bo_list);
2991 LOGD("bo list exist(len: %d)", idx);
2994 for (; idx < player->ini.num_of_video_bo; idx++) {
2995 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2997 LOGE("Fail to alloc bo_info.");
3000 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3002 LOGE("Fail to tbm_bo_alloc.");
3003 MMPLAYER_FREEIF(bo_info);
3006 bo_info->used = FALSE;
3007 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3010 /* update video num buffers */
3011 player->video_num_buffers = idx;
3012 if (idx == player->ini.num_of_video_bo)
3013 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3016 MMPLAYER_VIDEO_BO_UNLOCK(player);
3020 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3024 /* get bo from list*/
3025 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3026 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3027 if (tmp && (tmp->used == FALSE)) {
3028 LOGD("found bo %p to use", tmp->bo);
3030 MMPLAYER_VIDEO_BO_UNLOCK(player);
3031 return tbm_bo_ref(tmp->bo);
3035 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3036 MMPLAYER_VIDEO_BO_UNLOCK(player);
3040 if (player->ini.video_bo_timeout <= 0) {
3041 MMPLAYER_VIDEO_BO_WAIT(player);
3043 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3044 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3051 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3053 mm_player_t *player = (mm_player_t *)data;
3055 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3057 /* send prerolled pkt */
3058 player->video_stream_prerolled = false;
3060 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3062 /* not to send prerolled pkt again */
3063 player->video_stream_prerolled = true;
3067 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3069 mm_player_t *player = (mm_player_t *)data;
3070 MMPlayerVideoStreamDataType *stream = NULL;
3071 GstMemory *mem = NULL;
3074 MMPLAYER_RETURN_IF_FAIL(player);
3075 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3077 if (player->video_stream_prerolled) {
3078 player->video_stream_prerolled = false;
3079 LOGD("skip the prerolled pkt not to send it again");
3083 /* clear stream data structure */
3084 stream = __mmplayer_create_stream_from_pad(pad);
3086 LOGE("failed to alloc stream");
3090 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3092 /* set size and timestamp */
3093 mem = gst_buffer_peek_memory(buffer, 0);
3094 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3095 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3097 /* check zero-copy */
3098 if (player->set_mode.video_zc &&
3099 player->set_mode.media_packet_video_stream &&
3100 gst_is_tizen_memory(mem)) {
3101 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3102 stream->internal_buffer = gst_buffer_ref(buffer);
3103 } else { /* sw codec */
3104 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3107 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3111 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3112 LOGE("failed to send video stream data.");
3119 LOGE("release video stream resource.");
3120 if (gst_is_tizen_memory(mem)) {
3122 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3124 tbm_bo_unref(stream->bo[i]);
3127 /* unref gst buffer */
3128 if (stream->internal_buffer)
3129 gst_buffer_unref(stream->internal_buffer);
3132 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3134 MMPLAYER_FREEIF(stream);
3139 __mmplayer_gst_set_video360_property(mm_player_t *player)
3141 MMPlayerGstElement *videobin = NULL;
3144 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3146 videobin = player->pipeline->videobin;
3148 /* Set spatial media metadata and/or user settings to the element.
3150 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3151 "projection-type", player->video360_metadata.projection_type, NULL);
3153 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3154 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3156 if (player->video360_metadata.full_pano_width_pixels &&
3157 player->video360_metadata.full_pano_height_pixels &&
3158 player->video360_metadata.cropped_area_image_width &&
3159 player->video360_metadata.cropped_area_image_height) {
3160 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3161 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3162 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3163 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3164 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3165 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3166 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3170 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3171 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3172 "horizontal-fov", player->video360_horizontal_fov,
3173 "vertical-fov", player->video360_vertical_fov, NULL);
3176 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3177 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3178 "zoom", 1.0f / player->video360_zoom, NULL);
3181 if (player->video360_yaw_radians <= M_PI &&
3182 player->video360_yaw_radians >= -M_PI &&
3183 player->video360_pitch_radians <= M_PI_2 &&
3184 player->video360_pitch_radians >= -M_PI_2) {
3185 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3186 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3187 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3188 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3189 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3190 "pose-yaw", player->video360_metadata.init_view_heading,
3191 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3194 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3195 "passthrough", !player->is_video360_enabled, NULL);
3202 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3204 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3205 GList *element_bucket = NULL;
3208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3210 /* create video360 filter */
3211 if (player->is_360_feature_enabled && player->is_content_spherical) {
3212 LOGD("create video360 element");
3213 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3214 __mmplayer_gst_set_video360_property(player);
3218 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3219 LOGD("skip creating the videoconv and rotator");
3220 return MM_ERROR_NONE;
3223 /* in case of sw codec & overlay surface type, except 360 playback.
3224 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3225 LOGD("create video converter: %s", video_csc);
3226 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3229 *bucket = element_bucket;
3231 return MM_ERROR_NONE;
3233 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3234 g_list_free(element_bucket);
3238 return MM_ERROR_PLAYER_INTERNAL;
3242 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3244 gchar *factory_name = NULL;
3246 switch (surface_type) {
3247 case MM_DISPLAY_SURFACE_OVERLAY:
3248 if (strlen(player->ini.videosink_element_overlay) > 0)
3249 factory_name = player->ini.videosink_element_overlay;
3251 case MM_DISPLAY_SURFACE_REMOTE:
3252 case MM_DISPLAY_SURFACE_NULL:
3253 if (strlen(player->ini.videosink_element_fake) > 0)
3254 factory_name = player->ini.videosink_element_fake;
3257 LOGE("unidentified surface type");
3261 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3262 return factory_name;
3266 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3268 gchar *factory_name = NULL;
3269 MMPlayerGstElement *videobin = NULL;
3274 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3276 videobin = player->pipeline->videobin;
3277 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3279 attrs = MMPLAYER_GET_ATTRS(player);
3281 LOGE("cannot get content attribute");
3282 return MM_ERROR_PLAYER_INTERNAL;
3285 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3286 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3287 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3289 /* support shard memory with S/W codec on HawkP */
3290 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3291 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3292 "use-tbm", use_tbm, NULL);
3296 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3297 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3300 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3302 LOGD("disable last-sample");
3303 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3306 if (player->set_mode.media_packet_video_stream) {
3308 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3309 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3310 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3312 __mmplayer_add_signal_connection(player,
3313 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3314 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3316 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3319 __mmplayer_add_signal_connection(player,
3320 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3321 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3323 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3327 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3328 return MM_ERROR_PLAYER_INTERNAL;
3330 if (videobin[MMPLAYER_V_SINK].gst) {
3331 GstPad *sink_pad = NULL;
3332 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3334 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3335 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3336 gst_object_unref(GST_OBJECT(sink_pad));
3338 LOGE("failed to get sink pad from videosink");
3342 return MM_ERROR_NONE;
3347 * - video overlay surface(arm/x86) : tizenwlsink
3350 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3353 GList *element_bucket = NULL;
3354 MMPlayerGstElement *first_element = NULL;
3355 MMPlayerGstElement *videobin = NULL;
3356 gchar *videosink_factory_name = NULL;
3359 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3362 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3364 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3366 player->pipeline->videobin = videobin;
3369 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3370 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3371 if (!videobin[MMPLAYER_V_BIN].gst) {
3372 LOGE("failed to create videobin");
3376 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3379 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3380 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3382 /* additional setting for sink plug-in */
3383 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3384 LOGE("failed to set video property");
3388 /* store it as it's sink element */
3389 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3391 /* adding created elements to bin */
3392 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3393 LOGE("failed to add elements");
3397 /* Linking elements in the bucket by added order */
3398 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3399 LOGE("failed to link elements");
3403 /* get first element's sinkpad for creating ghostpad */
3404 first_element = (MMPlayerGstElement *)element_bucket->data;
3405 if (!first_element) {
3406 LOGE("failed to get first element from bucket");
3410 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3412 LOGE("failed to get pad from first element");
3416 /* create ghostpad */
3417 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3418 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3419 LOGE("failed to add ghostpad to videobin");
3422 gst_object_unref(pad);
3424 /* done. free allocated variables */
3425 g_list_free(element_bucket);
3429 return MM_ERROR_NONE;
3432 LOGE("ERROR : releasing videobin");
3433 g_list_free(element_bucket);
3436 gst_object_unref(GST_OBJECT(pad));
3438 /* release videobin with it's childs */
3439 if (videobin[MMPLAYER_V_BIN].gst)
3440 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3442 MMPLAYER_FREEIF(videobin);
3443 player->pipeline->videobin = NULL;
3445 return MM_ERROR_PLAYER_INTERNAL;
3449 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3451 GList *element_bucket = NULL;
3452 MMPlayerGstElement *textbin = player->pipeline->textbin;
3454 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3455 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3456 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3457 "signal-handoffs", FALSE,
3460 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3461 __mmplayer_add_signal_connection(player,
3462 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3463 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3465 G_CALLBACK(__mmplayer_update_subtitle),
3468 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3469 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3471 if (!player->play_subtitle) {
3472 LOGD("add textbin sink as sink element of whole pipeline.");
3473 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3476 /* adding created elements to bin */
3477 LOGD("adding created elements to bin");
3478 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3479 LOGE("failed to add elements");
3483 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3484 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3485 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3487 /* linking elements in the bucket by added order. */
3488 LOGD("Linking elements in the bucket by added order.");
3489 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3490 LOGE("failed to link elements");
3494 /* done. free allocated variables */
3495 g_list_free(element_bucket);
3497 if (textbin[MMPLAYER_T_QUEUE].gst) {
3499 GstPad *ghostpad = NULL;
3501 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3503 LOGE("failed to get sink pad of text queue");
3507 ghostpad = gst_ghost_pad_new("text_sink", pad);
3508 gst_object_unref(pad);
3511 LOGE("failed to create ghostpad of textbin");
3515 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3516 LOGE("failed to add ghostpad to textbin");
3517 gst_object_unref(ghostpad);
3522 return MM_ERROR_NONE;
3525 g_list_free(element_bucket);
3527 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3528 LOGE("remove textbin sink from sink list");
3529 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3532 /* release element at __mmplayer_gst_create_text_sink_bin */
3533 return MM_ERROR_PLAYER_INTERNAL;
3537 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3539 MMPlayerGstElement *textbin = NULL;
3540 GList *element_bucket = NULL;
3541 int surface_type = 0;
3546 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3549 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3551 LOGE("failed to allocate memory for textbin");
3552 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3556 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3557 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3558 if (!textbin[MMPLAYER_T_BIN].gst) {
3559 LOGE("failed to create textbin");
3564 player->pipeline->textbin = textbin;
3567 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3568 LOGD("surface type for subtitle : %d", surface_type);
3569 switch (surface_type) {
3570 case MM_DISPLAY_SURFACE_OVERLAY:
3571 case MM_DISPLAY_SURFACE_NULL:
3572 case MM_DISPLAY_SURFACE_REMOTE:
3573 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3574 LOGE("failed to make plain text elements");
3585 return MM_ERROR_NONE;
3589 LOGD("ERROR : releasing textbin");
3591 g_list_free(element_bucket);
3593 /* release signal */
3594 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3596 /* release element which are not added to bin */
3597 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3598 /* NOTE : skip bin */
3599 if (textbin[i].gst) {
3600 GstObject *parent = NULL;
3601 parent = gst_element_get_parent(textbin[i].gst);
3604 gst_object_unref(GST_OBJECT(textbin[i].gst));
3605 textbin[i].gst = NULL;
3607 gst_object_unref(GST_OBJECT(parent));
3612 /* release textbin with it's childs */
3613 if (textbin[MMPLAYER_T_BIN].gst)
3614 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3616 MMPLAYER_FREEIF(player->pipeline->textbin);
3617 player->pipeline->textbin = NULL;
3620 return MM_ERROR_PLAYER_INTERNAL;
3624 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3626 MMPlayerGstElement *mainbin = NULL;
3627 MMPlayerGstElement *textbin = NULL;
3628 MMHandleType attrs = 0;
3629 GstElement *subsrc = NULL;
3630 GstElement *subparse = NULL;
3631 gchar *subtitle_uri = NULL;
3632 const gchar *charset = NULL;
3638 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3640 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3642 mainbin = player->pipeline->mainbin;
3644 attrs = MMPLAYER_GET_ATTRS(player);
3646 LOGE("cannot get content attribute");
3647 return MM_ERROR_PLAYER_INTERNAL;
3650 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3651 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3652 LOGE("subtitle uri is not proper filepath.");
3653 return MM_ERROR_PLAYER_INVALID_URI;
3656 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3657 LOGE("failed to get storage info of subtitle path");
3658 return MM_ERROR_PLAYER_INVALID_URI;
3661 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3663 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3664 player->subtitle_language_list = NULL;
3665 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3667 /* create the subtitle source */
3668 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3670 LOGE("failed to create filesrc element");
3673 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3675 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3676 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3678 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3679 LOGW("failed to add queue");
3680 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3681 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3682 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3687 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3689 LOGE("failed to create subparse element");
3693 charset = util_get_charset(subtitle_uri);
3695 LOGD("detected charset is %s", charset);
3696 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3699 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3700 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3702 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3703 LOGW("failed to add subparse");
3704 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3705 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3706 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3710 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3711 LOGW("failed to link subsrc and subparse");
3715 player->play_subtitle = TRUE;
3716 player->adjust_subtitle_pos = 0;
3718 LOGD("play subtitle using subtitle file");
3720 if (player->pipeline->textbin == NULL) {
3721 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3722 LOGE("failed to create text sink bin. continuing without text");
3726 textbin = player->pipeline->textbin;
3728 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3729 LOGW("failed to add textbin");
3731 /* release signal */
3732 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3734 /* release textbin with it's childs */
3735 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3736 MMPLAYER_FREEIF(player->pipeline->textbin);
3737 player->pipeline->textbin = textbin = NULL;
3741 LOGD("link text input selector and textbin ghost pad");
3743 player->textsink_linked = 1;
3744 player->external_text_idx = 0;
3745 LOGI("textsink is linked");
3747 textbin = player->pipeline->textbin;
3748 LOGD("text bin has been created. reuse it.");
3749 player->external_text_idx = 1;
3752 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3753 LOGW("failed to link subparse and textbin");
3757 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3759 LOGE("failed to get sink pad from textsink to probe data");
3763 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3764 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3766 gst_object_unref(pad);
3769 /* create dot. for debugging */
3770 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3773 return MM_ERROR_NONE;
3776 /* release text pipeline resource */
3777 player->textsink_linked = 0;
3779 /* release signal */
3780 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3782 if (player->pipeline->textbin) {
3783 LOGE("remove textbin");
3785 /* release textbin with it's childs */
3786 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3787 MMPLAYER_FREEIF(player->pipeline->textbin);
3788 player->pipeline->textbin = NULL;
3792 /* release subtitle elem */
3793 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3794 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3796 return MM_ERROR_PLAYER_INTERNAL;
3800 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3802 mm_player_t *player = (mm_player_t *)data;
3803 MMMessageParamType msg = {0, };
3804 GstClockTime duration = 0;
3805 gpointer text = NULL;
3806 guint text_size = 0;
3807 gboolean ret = TRUE;
3808 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3812 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3813 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3815 if (player->is_subtitle_force_drop) {
3816 LOGW("subtitle is dropped forcedly.");
3820 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3821 text = mapinfo.data;
3822 text_size = mapinfo.size;
3824 if (player->set_mode.subtitle_off) {
3825 LOGD("subtitle is OFF.");
3829 if (!text || (text_size == 0)) {
3830 LOGD("There is no subtitle to be displayed.");
3834 msg.data = (void *)text;
3836 duration = GST_BUFFER_DURATION(buffer);
3838 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3839 if (player->duration > GST_BUFFER_PTS(buffer))
3840 duration = player->duration - GST_BUFFER_PTS(buffer);
3843 LOGI("subtitle duration is invalid, subtitle duration change "
3844 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3846 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3848 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3850 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3851 gst_buffer_unmap(buffer, &mapinfo);
3858 static GstPadProbeReturn
3859 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3861 mm_player_t *player = (mm_player_t *)u_data;
3862 GstClockTime cur_timestamp = 0;
3863 gint64 adjusted_timestamp = 0;
3864 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3866 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3868 if (player->set_mode.subtitle_off) {
3869 LOGD("subtitle is OFF.");
3873 if (player->adjust_subtitle_pos == 0) {
3874 LOGD("nothing to do");
3878 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3879 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3881 if (adjusted_timestamp < 0) {
3882 LOGD("adjusted_timestamp under zero");
3887 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3888 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3889 GST_TIME_ARGS(cur_timestamp),
3890 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3892 return GST_PAD_PROBE_OK;
3896 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3900 /* check player and subtitlebin are created */
3901 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3902 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3904 if (position == 0) {
3905 LOGD("nothing to do");
3907 return MM_ERROR_NONE;
3911 case MM_PLAYER_POS_FORMAT_TIME:
3913 /* check current postion */
3914 player->adjust_subtitle_pos = position;
3916 LOGD("save adjust_subtitle_pos in player") ;
3922 LOGW("invalid format.");
3924 return MM_ERROR_INVALID_ARGUMENT;
3930 return MM_ERROR_NONE;
3934 * This function is to create audio or video pipeline for playing.
3936 * @param player [in] handle of player
3938 * @return This function returns zero on success.
3943 __mmplayer_gst_create_pipeline(mm_player_t *player)
3945 int ret = MM_ERROR_NONE;
3946 MMPlayerGstElement *mainbin = NULL;
3947 MMHandleType attrs = 0;
3950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3952 /* get profile attribute */
3953 attrs = MMPLAYER_GET_ATTRS(player);
3955 LOGE("failed to get content attribute");
3959 /* create pipeline handles */
3960 if (player->pipeline) {
3961 LOGE("pipeline should be released before create new one");
3965 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3966 if (player->pipeline == NULL)
3969 /* create mainbin */
3970 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3971 if (mainbin == NULL)
3974 /* create pipeline */
3975 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3976 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3977 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3978 LOGE("failed to create pipeline");
3983 player->pipeline->mainbin = mainbin;
3985 /* create the source and decoder elements */
3986 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3987 ret = __mmplayer_gst_build_es_pipeline(player);
3989 ret = __mmplayer_gst_build_pipeline(player);
3991 if (ret != MM_ERROR_NONE) {
3992 LOGE("failed to create some elements");
3996 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3997 if (__mmplayer_check_subtitle(player)
3998 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3999 LOGE("failed to create text pipeline");
4002 ret = __mmplayer_gst_add_bus_watch(player);
4003 if (ret != MM_ERROR_NONE) {
4004 LOGE("failed to add bus watch");
4009 return MM_ERROR_NONE;
4012 __mmplayer_gst_destroy_pipeline(player);
4013 return MM_ERROR_PLAYER_INTERNAL;
4017 __mmplayer_reset_gapless_state(mm_player_t *player)
4020 MMPLAYER_RETURN_IF_FAIL(player
4022 && player->pipeline->audiobin
4023 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4025 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4032 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4035 int ret = MM_ERROR_NONE;
4039 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4041 /* cleanup stuffs */
4042 MMPLAYER_FREEIF(player->type);
4043 player->no_more_pad = FALSE;
4044 player->num_dynamic_pad = 0;
4045 player->demux_pad_index = 0;
4047 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4048 player->subtitle_language_list = NULL;
4049 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4051 __mmplayer_reset_gapless_state(player);
4053 if (player->streamer) {
4054 __mm_player_streaming_initialize(player->streamer, FALSE);
4055 __mm_player_streaming_destroy(player->streamer);
4056 player->streamer = NULL;
4059 /* cleanup unlinked mime type */
4060 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4061 MMPLAYER_FREEIF(player->unlinked_video_mime);
4062 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4064 /* cleanup running stuffs */
4065 __mmplayer_cancel_eos_timer(player);
4067 /* cleanup gst stuffs */
4068 if (player->pipeline) {
4069 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4070 GstTagList *tag_list = player->pipeline->tag_list;
4072 /* first we need to disconnect all signal hander */
4073 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4076 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4077 MMPlayerGstElement *videobin = player->pipeline->videobin;
4078 MMPlayerGstElement *textbin = player->pipeline->textbin;
4079 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4080 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4081 gst_object_unref(bus);
4083 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4084 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4085 if (ret != MM_ERROR_NONE) {
4086 LOGE("fail to change state to NULL");
4087 return MM_ERROR_PLAYER_INTERNAL;
4090 LOGW("succeeded in changing state to NULL");
4092 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4095 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4096 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4098 /* free avsysaudiosink
4099 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4100 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4102 MMPLAYER_FREEIF(audiobin);
4103 MMPLAYER_FREEIF(videobin);
4104 MMPLAYER_FREEIF(textbin);
4105 MMPLAYER_FREEIF(mainbin);
4109 gst_tag_list_unref(tag_list);
4111 MMPLAYER_FREEIF(player->pipeline);
4113 MMPLAYER_FREEIF(player->album_art);
4115 if (player->v_stream_caps) {
4116 gst_caps_unref(player->v_stream_caps);
4117 player->v_stream_caps = NULL;
4120 if (player->a_stream_caps) {
4121 gst_caps_unref(player->a_stream_caps);
4122 player->a_stream_caps = NULL;
4125 if (player->s_stream_caps) {
4126 gst_caps_unref(player->s_stream_caps);
4127 player->s_stream_caps = NULL;
4129 __mmplayer_track_destroy(player);
4131 if (player->sink_elements)
4132 g_list_free(player->sink_elements);
4133 player->sink_elements = NULL;
4135 if (player->bufmgr) {
4136 tbm_bufmgr_deinit(player->bufmgr);
4137 player->bufmgr = NULL;
4140 LOGW("finished destroy pipeline");
4148 __mmplayer_gst_realize(mm_player_t *player)
4151 int ret = MM_ERROR_NONE;
4155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4157 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4159 ret = __mmplayer_gst_create_pipeline(player);
4161 LOGE("failed to create pipeline");
4165 /* set pipeline state to READY */
4166 /* NOTE : state change to READY must be performed sync. */
4167 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4168 ret = __mmplayer_gst_set_state(player,
4169 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4171 if (ret != MM_ERROR_NONE) {
4172 /* return error if failed to set state */
4173 LOGE("failed to set READY state");
4177 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4179 /* create dot before error-return. for debugging */
4180 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4188 __mmplayer_gst_unrealize(mm_player_t *player)
4190 int ret = MM_ERROR_NONE;
4194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4196 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4197 MMPLAYER_PRINT_STATE(player);
4199 /* release miscellaneous information */
4200 __mmplayer_release_misc(player);
4202 /* destroy pipeline */
4203 ret = __mmplayer_gst_destroy_pipeline(player);
4204 if (ret != MM_ERROR_NONE) {
4205 LOGE("failed to destory pipeline");
4209 /* release miscellaneous information.
4210 these info needs to be released after pipeline is destroyed. */
4211 __mmplayer_release_misc_post(player);
4213 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4221 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4226 LOGW("set_message_callback is called with invalid player handle");
4227 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4230 player->msg_cb = callback;
4231 player->msg_cb_param = user_param;
4233 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4237 return MM_ERROR_NONE;
4241 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4243 int ret = MM_ERROR_NONE;
4248 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4249 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4250 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4252 memset(data, 0, sizeof(MMPlayerParseProfile));
4254 if (strstr(uri, "es_buff://")) {
4255 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4256 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4257 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4258 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4260 tmp = g_ascii_strdown(uri, strlen(uri));
4261 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4262 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4264 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4266 } else if (strstr(uri, "mms://")) {
4267 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4268 } else if ((path = strstr(uri, "mem://"))) {
4269 ret = __mmplayer_set_mem_uri(data, path, param);
4271 ret = __mmplayer_set_file_uri(data, uri);
4274 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4275 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4276 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4277 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4279 /* dump parse result */
4280 SECURE_LOGW("incoming uri : %s", uri);
4281 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4282 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4290 __mmplayer_can_do_interrupt(mm_player_t *player)
4292 if (!player || !player->pipeline || !player->attrs) {
4293 LOGW("not initialized");
4297 if (player->audio_stream_render_cb) {
4298 LOGW("not support in pcm extraction mode");
4302 /* check if seeking */
4303 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4304 MMMessageParamType msg_param;
4305 memset(&msg_param, 0, sizeof(MMMessageParamType));
4306 msg_param.code = MM_ERROR_PLAYER_SEEK;
4307 player->seek_state = MMPLAYER_SEEK_NONE;
4308 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4312 /* check other thread */
4313 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4314 LOGW("locked already, cmd state : %d", player->cmd);
4316 /* check application command */
4317 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4318 LOGW("playing.. should wait cmd lock then, will be interrupted");
4320 /* lock will be released at mrp_resource_release_cb() */
4321 MMPLAYER_CMD_LOCK(player);
4324 LOGW("nothing to do");
4327 LOGW("can interrupt immediately");
4331 FAILED: /* with CMD UNLOCKED */
4334 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4339 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4342 mm_player_t *player = NULL;
4346 if (user_data == NULL) {
4347 LOGE("- user_data is null");
4350 player = (mm_player_t *)user_data;
4352 /* do something to release resource here.
4353 * player stop and interrupt forwarding */
4354 if (!__mmplayer_can_do_interrupt(player)) {
4355 LOGW("no need to interrupt, so leave");
4357 MMMessageParamType msg = {0, };
4360 player->interrupted_by_resource = TRUE;
4362 /* get last play position */
4363 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4364 LOGW("failed to get play position.");
4366 msg.union_type = MM_MSG_UNION_TIME;
4367 msg.time.elapsed = pos;
4368 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4370 LOGD("video resource conflict so, resource will be freed by unrealizing");
4371 if (_mmplayer_unrealize((MMHandleType)player))
4372 LOGW("failed to unrealize");
4374 /* lock is called in __mmplayer_can_do_interrupt() */
4375 MMPLAYER_CMD_UNLOCK(player);
4378 if (res == player->video_overlay_resource)
4379 player->video_overlay_resource = FALSE;
4381 player->video_decoder_resource = FALSE;
4389 __mmplayer_initialize_video_roi(mm_player_t *player)
4391 player->video_roi.scale_x = 0.0;
4392 player->video_roi.scale_y = 0.0;
4393 player->video_roi.scale_width = 1.0;
4394 player->video_roi.scale_height = 1.0;
4398 _mmplayer_create_player(MMHandleType handle)
4400 int ret = MM_ERROR_PLAYER_INTERNAL;
4401 bool enabled = false;
4403 mm_player_t *player = MM_PLAYER_CAST(handle);
4407 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4409 /* initialize player state */
4410 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4411 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4412 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4413 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4415 /* check current state */
4416 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4418 /* construct attributes */
4419 player->attrs = _mmplayer_construct_attribute(handle);
4421 if (!player->attrs) {
4422 LOGE("Failed to construct attributes");
4426 /* initialize gstreamer with configured parameter */
4427 if (!__mmplayer_init_gstreamer(player)) {
4428 LOGE("Initializing gstreamer failed");
4429 _mmplayer_deconstruct_attribute(handle);
4433 /* create lock. note that g_tread_init() has already called in gst_init() */
4434 g_mutex_init(&player->fsink_lock);
4436 /* create update tag lock */
4437 g_mutex_init(&player->update_tag_lock);
4439 /* create gapless play mutex */
4440 g_mutex_init(&player->gapless_play_thread_mutex);
4442 /* create gapless play cond */
4443 g_cond_init(&player->gapless_play_thread_cond);
4445 /* create gapless play thread */
4446 player->gapless_play_thread =
4447 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4448 if (!player->gapless_play_thread) {
4449 LOGE("failed to create gapless play thread");
4450 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4451 g_mutex_clear(&player->gapless_play_thread_mutex);
4452 g_cond_clear(&player->gapless_play_thread_cond);
4456 player->bus_msg_q = g_queue_new();
4457 if (!player->bus_msg_q) {
4458 LOGE("failed to create queue for bus_msg");
4459 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4463 ret = _mmplayer_initialize_video_capture(player);
4464 if (ret != MM_ERROR_NONE) {
4465 LOGE("failed to initialize video capture");
4469 /* initialize resource manager */
4470 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4471 __resource_release_cb, player, &player->resource_manager)
4472 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4473 LOGE("failed to initialize resource manager");
4474 ret = MM_ERROR_PLAYER_INTERNAL;
4478 /* create video bo lock and cond */
4479 g_mutex_init(&player->video_bo_mutex);
4480 g_cond_init(&player->video_bo_cond);
4482 /* create media stream callback mutex */
4483 g_mutex_init(&player->media_stream_cb_lock);
4485 /* create subtitle info lock and cond */
4486 g_mutex_init(&player->subtitle_info_mutex);
4487 g_cond_init(&player->subtitle_info_cond);
4489 player->streaming_type = STREAMING_SERVICE_NONE;
4491 /* give default value of audio effect setting */
4492 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4493 player->sound.rg_enable = false;
4494 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4496 player->play_subtitle = FALSE;
4497 player->has_closed_caption = FALSE;
4498 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4499 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4500 player->pending_resume = FALSE;
4501 if (player->ini.dump_element_keyword[0][0] == '\0')
4502 player->ini.set_dump_element_flag = FALSE;
4504 player->ini.set_dump_element_flag = TRUE;
4506 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4507 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4508 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4510 /* Set video360 settings to their defaults for just-created player.
4513 player->is_360_feature_enabled = FALSE;
4514 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4515 LOGI("spherical feature info: %d", enabled);
4517 player->is_360_feature_enabled = TRUE;
4519 LOGE("failed to get spherical feature info");
4522 player->is_content_spherical = FALSE;
4523 player->is_video360_enabled = TRUE;
4524 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4525 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4526 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4527 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4528 player->video360_zoom = 1.0f;
4529 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4530 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4532 __mmplayer_initialize_video_roi(player);
4534 /* set player state to null */
4535 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4536 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4540 return MM_ERROR_NONE;
4544 g_mutex_clear(&player->fsink_lock);
4545 /* free update tag lock */
4546 g_mutex_clear(&player->update_tag_lock);
4547 g_queue_free(player->bus_msg_q);
4548 /* free gapless play thread */
4549 if (player->gapless_play_thread) {
4550 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4551 player->gapless_play_thread_exit = TRUE;
4552 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4553 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4555 g_thread_join(player->gapless_play_thread);
4556 player->gapless_play_thread = NULL;
4558 g_mutex_clear(&player->gapless_play_thread_mutex);
4559 g_cond_clear(&player->gapless_play_thread_cond);
4562 /* release attributes */
4563 _mmplayer_deconstruct_attribute(handle);
4571 __mmplayer_init_gstreamer(mm_player_t *player)
4573 static gboolean initialized = FALSE;
4574 static const int max_argc = 50;
4576 gchar **argv = NULL;
4577 gchar **argv2 = NULL;
4583 LOGD("gstreamer already initialized.");
4588 argc = malloc(sizeof(int));
4589 argv = malloc(sizeof(gchar *) * max_argc);
4590 argv2 = malloc(sizeof(gchar *) * max_argc);
4592 if (!argc || !argv || !argv2)
4595 memset(argv, 0, sizeof(gchar *) * max_argc);
4596 memset(argv2, 0, sizeof(gchar *) * max_argc);
4600 argv[0] = g_strdup("mmplayer");
4603 for (i = 0; i < 5; i++) {
4604 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4605 if (strlen(player->ini.gst_param[i]) > 0) {
4606 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4611 /* we would not do fork for scanning plugins */
4612 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4615 /* check disable registry scan */
4616 if (player->ini.skip_rescan) {
4617 argv[*argc] = g_strdup("--gst-disable-registry-update");
4621 /* check disable segtrap */
4622 if (player->ini.disable_segtrap) {
4623 argv[*argc] = g_strdup("--gst-disable-segtrap");
4627 LOGD("initializing gstreamer with following parameter");
4628 LOGD("argc : %d", *argc);
4631 for (i = 0; i < arg_count; i++) {
4633 LOGD("argv[%d] : %s", i, argv2[i]);
4636 /* initializing gstreamer */
4637 if (!gst_init_check(argc, &argv, &err)) {
4638 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4645 for (i = 0; i < arg_count; i++) {
4646 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4647 MMPLAYER_FREEIF(argv2[i]);
4650 MMPLAYER_FREEIF(argv);
4651 MMPLAYER_FREEIF(argv2);
4652 MMPLAYER_FREEIF(argc);
4662 for (i = 0; i < arg_count; i++) {
4663 LOGD("free[%d] : %s", i, argv2[i]);
4664 MMPLAYER_FREEIF(argv2[i]);
4667 MMPLAYER_FREEIF(argv);
4668 MMPLAYER_FREEIF(argv2);
4669 MMPLAYER_FREEIF(argc);
4675 __mmplayer_check_async_state_transition(mm_player_t *player)
4677 GstState element_state = GST_STATE_VOID_PENDING;
4678 GstState element_pending_state = GST_STATE_VOID_PENDING;
4679 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4680 GstElement *element = NULL;
4681 gboolean async = FALSE;
4683 /* check player handle */
4684 MMPLAYER_RETURN_IF_FAIL(player &&
4686 player->pipeline->mainbin &&
4687 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4690 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4692 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4693 LOGD("don't need to check the pipeline state");
4697 MMPLAYER_PRINT_STATE(player);
4699 /* wait for state transition */
4700 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4701 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4703 if (ret == GST_STATE_CHANGE_FAILURE) {
4704 LOGE(" [%s] state : %s pending : %s",
4705 GST_ELEMENT_NAME(element),
4706 gst_element_state_get_name(element_state),
4707 gst_element_state_get_name(element_pending_state));
4709 /* dump state of all element */
4710 __mmplayer_dump_pipeline_state(player);
4715 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4720 _mmplayer_destroy(MMHandleType handle)
4722 mm_player_t *player = MM_PLAYER_CAST(handle);
4726 /* check player handle */
4727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4729 /* destroy can called at anytime */
4730 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4732 /* check async state transition */
4733 __mmplayer_check_async_state_transition(player);
4735 /* release gapless play thread */
4736 if (player->gapless_play_thread) {
4737 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4738 player->gapless_play_thread_exit = TRUE;
4739 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4740 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4742 LOGD("waitting for gapless play thread exit");
4743 g_thread_join(player->gapless_play_thread);
4744 g_mutex_clear(&player->gapless_play_thread_mutex);
4745 g_cond_clear(&player->gapless_play_thread_cond);
4746 LOGD("gapless play thread released");
4749 _mmplayer_release_video_capture(player);
4751 /* de-initialize resource manager */
4752 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4753 player->resource_manager))
4754 LOGE("failed to deinitialize resource manager");
4756 /* release pipeline */
4757 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4758 LOGE("failed to destory pipeline");
4759 return MM_ERROR_PLAYER_INTERNAL;
4762 g_queue_free(player->bus_msg_q);
4764 /* release subtitle info lock and cond */
4765 g_mutex_clear(&player->subtitle_info_mutex);
4766 g_cond_clear(&player->subtitle_info_cond);
4768 __mmplayer_release_dump_list(player->dump_list);
4770 /* release miscellaneous information */
4771 __mmplayer_release_misc(player);
4773 /* release miscellaneous information.
4774 these info needs to be released after pipeline is destroyed. */
4775 __mmplayer_release_misc_post(player);
4777 /* release attributes */
4778 _mmplayer_deconstruct_attribute(handle);
4781 g_mutex_clear(&player->fsink_lock);
4784 g_mutex_clear(&player->update_tag_lock);
4786 /* release video bo lock and cond */
4787 g_mutex_clear(&player->video_bo_mutex);
4788 g_cond_clear(&player->video_bo_cond);
4790 /* release media stream callback lock */
4791 g_mutex_clear(&player->media_stream_cb_lock);
4795 return MM_ERROR_NONE;
4799 _mmplayer_realize(MMHandleType hplayer)
4801 mm_player_t *player = (mm_player_t *)hplayer;
4804 MMHandleType attrs = 0;
4805 int ret = MM_ERROR_NONE;
4809 /* check player handle */
4810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4812 /* check current state */
4813 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4815 attrs = MMPLAYER_GET_ATTRS(player);
4817 LOGE("fail to get attributes.");
4818 return MM_ERROR_PLAYER_INTERNAL;
4820 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4821 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4823 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4824 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4826 if (ret != MM_ERROR_NONE) {
4827 LOGE("failed to parse profile");
4832 if (uri && (strstr(uri, "es_buff://"))) {
4833 if (strstr(uri, "es_buff://push_mode"))
4834 player->es_player_push_mode = TRUE;
4836 player->es_player_push_mode = FALSE;
4839 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4840 LOGW("mms protocol is not supported format.");
4841 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4844 if (MMPLAYER_IS_STREAMING(player))
4845 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4847 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4849 player->smooth_streaming = FALSE;
4850 player->videodec_linked = 0;
4851 player->audiodec_linked = 0;
4852 player->textsink_linked = 0;
4853 player->is_external_subtitle_present = FALSE;
4854 player->is_external_subtitle_added_now = FALSE;
4855 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4856 player->video360_metadata.is_spherical = -1;
4857 player->is_openal_plugin_used = FALSE;
4858 player->demux_pad_index = 0;
4859 player->subtitle_language_list = NULL;
4860 player->is_subtitle_force_drop = FALSE;
4861 player->last_multiwin_status = FALSE;
4863 __mmplayer_track_initialize(player);
4864 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4866 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4867 gint prebuffer_ms = 0, rebuffer_ms = 0;
4869 player->streamer = __mm_player_streaming_create();
4870 __mm_player_streaming_initialize(player->streamer, TRUE);
4872 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4873 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4875 if (prebuffer_ms > 0) {
4876 prebuffer_ms = MAX(prebuffer_ms, 1000);
4877 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4880 if (rebuffer_ms > 0) {
4881 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4882 rebuffer_ms = MAX(rebuffer_ms, 1000);
4883 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4886 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4887 player->streamer->buffering_req.rebuffer_time);
4890 /* realize pipeline */
4891 ret = __mmplayer_gst_realize(player);
4892 if (ret != MM_ERROR_NONE)
4893 LOGE("fail to realize the player.");
4895 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4903 _mmplayer_unrealize(MMHandleType hplayer)
4905 mm_player_t *player = (mm_player_t *)hplayer;
4906 int ret = MM_ERROR_NONE;
4910 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4912 MMPLAYER_CMD_UNLOCK(player);
4913 /* destroy the gst bus msg thread which is created during realize.
4914 this funct have to be called before getting cmd lock. */
4915 __mmplayer_bus_msg_thread_destroy(player);
4916 MMPLAYER_CMD_LOCK(player);
4918 /* check current state */
4919 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4921 /* check async state transition */
4922 __mmplayer_check_async_state_transition(player);
4924 /* unrealize pipeline */
4925 ret = __mmplayer_gst_unrealize(player);
4927 /* set asm stop if success */
4928 if (MM_ERROR_NONE == ret) {
4929 if (!player->interrupted_by_resource) {
4930 if (player->video_decoder_resource != NULL) {
4931 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4932 player->video_decoder_resource);
4933 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4934 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4936 player->video_decoder_resource = NULL;
4939 if (player->video_overlay_resource != NULL) {
4940 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4941 player->video_overlay_resource);
4942 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4943 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4945 player->video_overlay_resource = NULL;
4948 ret = mm_resource_manager_commit(player->resource_manager);
4949 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4950 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4953 LOGE("failed and don't change asm state to stop");
4961 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4963 mm_player_t *player = (mm_player_t *)hplayer;
4965 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4967 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4971 _mmplayer_get_state(MMHandleType hplayer, int *state)
4973 mm_player_t *player = (mm_player_t *)hplayer;
4975 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4977 *state = MMPLAYER_CURRENT_STATE(player);
4979 return MM_ERROR_NONE;
4984 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4986 mm_player_t *player = (mm_player_t *)hplayer;
4987 GstElement *vol_element = NULL;
4992 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4994 LOGD("volume [L]=%f:[R]=%f",
4995 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4997 /* invalid factor range or not */
4998 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4999 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5000 LOGE("Invalid factor!(valid factor:0~1.0)");
5001 return MM_ERROR_INVALID_ARGUMENT;
5005 /* not support to set other value into each channel */
5006 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5007 return MM_ERROR_INVALID_ARGUMENT;
5009 /* Save volume to handle. Currently the first array element will be saved. */
5010 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5012 /* check pipeline handle */
5013 if (!player->pipeline || !player->pipeline->audiobin) {
5014 LOGD("audiobin is not created yet");
5015 LOGD("but, current stored volume will be set when it's created.");
5017 /* NOTE : stored volume will be used in create_audiobin
5018 * returning MM_ERROR_NONE here makes application to able to
5019 * set volume at anytime.
5021 return MM_ERROR_NONE;
5024 /* setting volume to volume element */
5025 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5028 LOGD("volume is set [%f]", player->sound.volume);
5029 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5034 return MM_ERROR_NONE;
5038 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5040 mm_player_t *player = (mm_player_t *)hplayer;
5045 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5046 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5048 /* returning stored volume */
5049 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5050 volume->level[i] = player->sound.volume;
5054 return MM_ERROR_NONE;
5058 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5060 mm_player_t *player = (mm_player_t *)hplayer;
5061 GstElement *vol_element = NULL;
5065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5067 /* mute value shoud 0 or 1 */
5068 if (mute != 0 && mute != 1) {
5069 LOGE("bad mute value");
5071 /* FIXIT : definitly, we need _BAD_PARAM error code */
5072 return MM_ERROR_INVALID_ARGUMENT;
5075 player->sound.mute = mute;
5077 /* just hold mute value if pipeline is not ready */
5078 if (!player->pipeline || !player->pipeline->audiobin) {
5079 LOGD("pipeline is not ready. holding mute value");
5080 return MM_ERROR_NONE;
5083 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5085 /* NOTE : volume will only created when the bt is enabled */
5087 LOGD("mute : %d", mute);
5088 g_object_set(vol_element, "mute", mute, NULL);
5090 LOGD("volume elemnet is not created. using volume in audiosink");
5094 return MM_ERROR_NONE;
5098 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5100 mm_player_t *player = (mm_player_t *)hplayer;
5104 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5105 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5107 /* just hold mute value if pipeline is not ready */
5108 if (!player->pipeline || !player->pipeline->audiobin) {
5109 LOGD("pipeline is not ready. returning stored value");
5110 *pmute = player->sound.mute;
5111 return MM_ERROR_NONE;
5114 *pmute = player->sound.mute;
5118 return MM_ERROR_NONE;
5122 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_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->video_stream_changed_cb = callback;
5131 player->video_stream_changed_cb_user_param = user_param;
5132 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5136 return MM_ERROR_NONE;
5140 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5142 mm_player_t *player = (mm_player_t *)hplayer;
5146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5148 player->audio_stream_changed_cb = callback;
5149 player->audio_stream_changed_cb_user_param = user_param;
5150 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5154 return MM_ERROR_NONE;
5158 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5160 mm_player_t *player = (mm_player_t *)hplayer;
5164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5166 player->audio_stream_render_cb = callback;
5167 player->audio_stream_cb_user_param = user_param;
5168 player->audio_stream_sink_sync = sync;
5169 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5173 return MM_ERROR_NONE;
5177 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5179 mm_player_t *player = (mm_player_t *)hplayer;
5183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5185 if (callback && !player->bufmgr)
5186 player->bufmgr = tbm_bufmgr_init(-1);
5188 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5189 player->video_stream_cb = callback;
5190 player->video_stream_cb_user_param = user_param;
5192 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5196 return MM_ERROR_NONE;
5200 _mmplayer_start(MMHandleType hplayer)
5202 mm_player_t *player = (mm_player_t *)hplayer;
5203 gint ret = MM_ERROR_NONE;
5207 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209 /* check current state */
5210 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5212 /* start pipeline */
5213 ret = __mmplayer_gst_start(player);
5214 if (ret != MM_ERROR_NONE)
5215 LOGE("failed to start player.");
5217 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5218 LOGD("force playing start even during buffering");
5219 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5227 /* NOTE: post "not supported codec message" to application
5228 * when one codec is not found during AUTOPLUGGING in MSL.
5229 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5230 * And, if any codec is not found, don't send message here.
5231 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5234 __mmplayer_handle_missed_plugin(mm_player_t *player)
5236 MMMessageParamType msg_param;
5237 memset(&msg_param, 0, sizeof(MMMessageParamType));
5238 gboolean post_msg_direct = FALSE;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5245 player->not_supported_codec, player->can_support_codec);
5247 if (player->not_found_demuxer) {
5248 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5249 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5251 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5252 MMPLAYER_FREEIF(msg_param.data);
5254 return MM_ERROR_NONE;
5257 if (player->not_supported_codec) {
5258 if (player->can_support_codec) {
5259 // There is one codec to play
5260 post_msg_direct = TRUE;
5262 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5263 post_msg_direct = TRUE;
5266 if (post_msg_direct) {
5267 MMMessageParamType msg_param;
5268 memset(&msg_param, 0, sizeof(MMMessageParamType));
5270 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5271 LOGW("not found AUDIO codec, posting error code to application.");
5273 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5274 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5275 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5276 LOGW("not found VIDEO codec, posting error code to application.");
5278 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5279 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5282 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5284 MMPLAYER_FREEIF(msg_param.data);
5286 return MM_ERROR_NONE;
5288 // no any supported codec case
5289 LOGW("not found any codec, posting error code to application.");
5291 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5292 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5293 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5295 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5296 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5299 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5301 MMPLAYER_FREEIF(msg_param.data);
5307 return MM_ERROR_NONE;
5311 __mmplayer_check_pipeline(mm_player_t *player)
5313 GstState element_state = GST_STATE_VOID_PENDING;
5314 GstState element_pending_state = GST_STATE_VOID_PENDING;
5316 int ret = MM_ERROR_NONE;
5318 if (!player->gapless.reconfigure)
5321 LOGW("pipeline is under construction.");
5323 MMPLAYER_PLAYBACK_LOCK(player);
5324 MMPLAYER_PLAYBACK_UNLOCK(player);
5326 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5328 /* wait for state transition */
5329 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5330 if (ret == GST_STATE_CHANGE_FAILURE)
5331 LOGE("failed to change pipeline state within %d sec", timeout);
5334 /* NOTE : it should be able to call 'stop' anytime*/
5336 _mmplayer_stop(MMHandleType hplayer)
5338 mm_player_t *player = (mm_player_t *)hplayer;
5339 int 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_STOP);
5348 /* check pipline building state */
5349 __mmplayer_check_pipeline(player);
5350 __mmplayer_reset_gapless_state(player);
5352 /* NOTE : application should not wait for EOS after calling STOP */
5353 __mmplayer_cancel_eos_timer(player);
5356 player->seek_state = MMPLAYER_SEEK_NONE;
5359 ret = __mmplayer_gst_stop(player);
5361 if (ret != MM_ERROR_NONE)
5362 LOGE("failed to stop player.");
5370 _mmplayer_pause(MMHandleType hplayer)
5372 mm_player_t *player = (mm_player_t *)hplayer;
5373 gint64 pos_nsec = 0;
5374 gboolean async = FALSE;
5375 gint ret = MM_ERROR_NONE;
5379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5381 /* check current state */
5382 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5384 /* check pipline building state */
5385 __mmplayer_check_pipeline(player);
5387 switch (MMPLAYER_CURRENT_STATE(player)) {
5388 case MM_PLAYER_STATE_READY:
5390 /* check prepare async or not.
5391 * In the case of streaming playback, it's recommned to avoid blocking wait.
5393 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5394 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5396 /* Changing back sync of rtspsrc to async */
5397 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5398 LOGD("async prepare working mode for rtsp");
5404 case MM_PLAYER_STATE_PLAYING:
5406 /* NOTE : store current point to overcome some bad operation
5407 *(returning zero when getting current position in paused state) of some
5410 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5411 LOGW("getting current position failed in paused");
5413 player->last_position = pos_nsec;
5415 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5416 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5417 This causes problem is position calculation during normal pause resume scenarios also.
5418 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5419 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5420 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5421 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5427 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5428 LOGD("doing async pause in case of ms buff src");
5432 /* pause pipeline */
5433 ret = __mmplayer_gst_pause(player, async);
5435 if (ret != MM_ERROR_NONE)
5436 LOGE("failed to pause player. ret : 0x%x", ret);
5438 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5439 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5440 LOGE("failed to update display_rotation");
5448 /* in case of streaming, pause could take long time.*/
5450 _mmplayer_abort_pause(MMHandleType hplayer)
5452 mm_player_t *player = (mm_player_t *)hplayer;
5453 int ret = MM_ERROR_NONE;
5457 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5459 player->pipeline->mainbin,
5460 MM_ERROR_PLAYER_NOT_INITIALIZED);
5462 LOGD("set the pipeline state to READY");
5464 /* set state to READY */
5465 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5466 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5467 if (ret != MM_ERROR_NONE) {
5468 LOGE("fail to change state to READY");
5469 return MM_ERROR_PLAYER_INTERNAL;
5472 LOGD("succeeded in changing state to READY");
5477 _mmplayer_resume(MMHandleType hplayer)
5479 mm_player_t *player = (mm_player_t *)hplayer;
5480 int ret = MM_ERROR_NONE;
5481 gboolean async = FALSE;
5485 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5487 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5488 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5489 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5493 /* Changing back sync mode rtspsrc to async */
5494 LOGD("async resume for rtsp case");
5498 /* check current state */
5499 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5501 ret = __mmplayer_gst_resume(player, async);
5502 if (ret != MM_ERROR_NONE)
5503 LOGE("failed to resume player.");
5505 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5506 LOGD("force resume even during buffering");
5507 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5516 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5518 mm_player_t *player = (mm_player_t *)hplayer;
5519 gint64 pos_nsec = 0;
5520 int ret = MM_ERROR_NONE;
5522 signed long long start = 0, stop = 0;
5523 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5526 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5527 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5529 /* The sound of video is not supported under 0.0 and over 2.0. */
5530 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5531 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5534 _mmplayer_set_mute(hplayer, mute);
5536 if (player->playback_rate == rate)
5537 return MM_ERROR_NONE;
5539 /* If the position is reached at start potion during fast backward, EOS is posted.
5540 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5542 player->playback_rate = rate;
5544 current_state = MMPLAYER_CURRENT_STATE(player);
5546 if (current_state != MM_PLAYER_STATE_PAUSED)
5547 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5549 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5551 if ((current_state == MM_PLAYER_STATE_PAUSED)
5552 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5553 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5554 pos_nsec = player->last_position;
5559 stop = GST_CLOCK_TIME_NONE;
5561 start = GST_CLOCK_TIME_NONE;
5565 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5566 player->playback_rate,
5568 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5569 GST_SEEK_TYPE_SET, start,
5570 GST_SEEK_TYPE_SET, stop)) {
5571 LOGE("failed to set speed playback");
5572 return MM_ERROR_PLAYER_SEEK;
5575 LOGD("succeeded to set speed playback as %0.1f", rate);
5579 return MM_ERROR_NONE;;
5583 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5585 mm_player_t *player = (mm_player_t *)hplayer;
5586 int ret = MM_ERROR_NONE;
5590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5592 /* check pipline building state */
5593 __mmplayer_check_pipeline(player);
5595 ret = __mmplayer_gst_set_position(player, position, FALSE);
5603 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5605 mm_player_t *player = (mm_player_t *)hplayer;
5606 int ret = MM_ERROR_NONE;
5608 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5610 ret = __mmplayer_gst_get_position(player, position);
5616 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5618 mm_player_t *player = (mm_player_t *)hplayer;
5619 int ret = MM_ERROR_NONE;
5621 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5622 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5624 if (g_strrstr(player->type, "video/mpegts"))
5625 __mmplayer_update_duration_value(player);
5627 *duration = player->duration;
5632 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5634 mm_player_t *player = (mm_player_t *)hplayer;
5635 int ret = MM_ERROR_NONE;
5637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5639 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5645 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5647 mm_player_t *player = (mm_player_t *)hplayer;
5648 int ret = MM_ERROR_NONE;
5652 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5654 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5662 __mmplayer_is_midi_type(gchar *str_caps)
5664 if ((g_strrstr(str_caps, "audio/midi")) ||
5665 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5666 (g_strrstr(str_caps, "application/x-smaf")) ||
5667 (g_strrstr(str_caps, "audio/x-imelody")) ||
5668 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5669 (g_strrstr(str_caps, "audio/xmf")) ||
5670 (g_strrstr(str_caps, "audio/mxmf"))) {
5679 __mmplayer_is_only_mp3_type(gchar *str_caps)
5681 if (g_strrstr(str_caps, "application/x-id3") ||
5682 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5688 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5690 GstStructure *caps_structure = NULL;
5691 gint samplerate = 0;
5695 MMPLAYER_RETURN_IF_FAIL(player && caps);
5697 caps_structure = gst_caps_get_structure(caps, 0);
5699 /* set stream information */
5700 gst_structure_get_int(caps_structure, "rate", &samplerate);
5701 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5703 gst_structure_get_int(caps_structure, "channels", &channels);
5704 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5706 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5710 __mmplayer_update_content_type_info(mm_player_t *player)
5713 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5715 if (__mmplayer_is_midi_type(player->type)) {
5716 player->bypass_audio_effect = TRUE;
5720 if (!player->streamer) {
5721 LOGD("no need to check streaming type");
5725 if (g_strrstr(player->type, "application/x-hls")) {
5726 /* If it can't know exact type when it parses uri because of redirection case,
5727 * it will be fixed by typefinder or when doing autoplugging.
5729 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5730 player->streamer->is_adaptive_streaming = TRUE;
5731 } else if (g_strrstr(player->type, "application/dash+xml")) {
5732 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5733 player->streamer->is_adaptive_streaming = TRUE;
5736 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5737 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5738 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5740 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5741 if (player->streamer->is_adaptive_streaming)
5742 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5744 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5748 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5753 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5754 GstCaps *caps, gpointer data)
5756 mm_player_t *player = (mm_player_t *)data;
5761 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5763 /* store type string */
5764 MMPLAYER_FREEIF(player->type);
5765 player->type = gst_caps_to_string(caps);
5767 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5768 player, player->type, probability, gst_caps_get_size(caps));
5770 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5771 (g_strrstr(player->type, "audio/x-raw-int"))) {
5772 LOGE("not support media format");
5774 if (player->msg_posted == FALSE) {
5775 MMMessageParamType msg_param;
5776 memset(&msg_param, 0, sizeof(MMMessageParamType));
5778 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5779 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5781 /* don't post more if one was sent already */
5782 player->msg_posted = TRUE;
5787 __mmplayer_update_content_type_info(player);
5789 pad = gst_element_get_static_pad(tf, "src");
5791 LOGE("fail to get typefind src pad.");
5795 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5796 gboolean async = FALSE;
5797 LOGE("failed to autoplug %s", player->type);
5799 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5801 if (async && player->msg_posted == FALSE)
5802 __mmplayer_handle_missed_plugin(player);
5806 gst_object_unref(GST_OBJECT(pad));
5814 __mmplayer_gst_make_decodebin(mm_player_t *player)
5816 GstElement *decodebin = NULL;
5820 /* create decodebin */
5821 decodebin = gst_element_factory_make("decodebin", NULL);
5824 LOGE("fail to create decodebin");
5828 /* raw pad handling signal */
5829 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5830 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5832 /* no-more-pad pad handling signal */
5833 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5834 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5836 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5837 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5839 /* This signal is emitted when a pad for which there is no further possible
5840 decoding is added to the decodebin.*/
5841 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5842 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5844 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5845 before looking for any elements that can handle that stream.*/
5846 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5847 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5849 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5850 before looking for any elements that can handle that stream.*/
5851 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5852 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5854 /* This signal is emitted once decodebin has finished decoding all the data.*/
5855 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5856 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5858 /* This signal is emitted when a element is added to the bin.*/
5859 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5860 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5867 __mmplayer_gst_make_queue2(mm_player_t *player)
5869 GstElement *queue2 = NULL;
5870 gint64 dur_bytes = 0L;
5871 MMPlayerGstElement *mainbin = NULL;
5872 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5875 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5877 mainbin = player->pipeline->mainbin;
5879 queue2 = gst_element_factory_make("queue2", "queue2");
5881 LOGE("failed to create buffering queue element");
5885 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5886 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5888 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5890 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5891 * skip the pull mode(file or ring buffering) setting. */
5892 if (dur_bytes > 0) {
5893 if (!g_strrstr(player->type, "video/mpegts")) {
5894 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5895 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5901 __mm_player_streaming_set_queue2(player->streamer,
5905 (guint64)dur_bytes); /* no meaning at the moment */
5911 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5913 MMPlayerGstElement *mainbin = NULL;
5914 GstElement *decodebin = NULL;
5915 GstElement *queue2 = NULL;
5916 GstPad *sinkpad = NULL;
5917 GstPad *qsrcpad = NULL;
5920 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5922 mainbin = player->pipeline->mainbin;
5924 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5926 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5927 LOGW("need to check: muxed buffer is not null");
5930 queue2 = __mmplayer_gst_make_queue2(player);
5932 LOGE("failed to make queue2");
5936 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5937 LOGE("failed to add buffering queue");
5941 sinkpad = gst_element_get_static_pad(queue2, "sink");
5942 qsrcpad = gst_element_get_static_pad(queue2, "src");
5944 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5945 LOGE("failed to link [%s:%s]-[%s:%s]",
5946 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5950 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5951 LOGE("failed to sync queue2 state with parent");
5955 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5956 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5960 gst_object_unref(GST_OBJECT(sinkpad));
5964 /* create decodebin */
5965 decodebin = __mmplayer_gst_make_decodebin(player);
5967 LOGE("failed to make decodebin");
5971 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5972 LOGE("failed to add decodebin");
5976 /* to force caps on the decodebin element and avoid reparsing stuff by
5977 * typefind. It also avoids a deadlock in the way typefind activates pads in
5978 * the state change */
5979 g_object_set(decodebin, "sink-caps", caps, NULL);
5981 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5983 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5984 LOGE("failed to link [%s:%s]-[%s:%s]",
5985 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5989 gst_object_unref(GST_OBJECT(sinkpad));
5991 gst_object_unref(GST_OBJECT(qsrcpad));
5994 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5995 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5997 /* set decodebin property about buffer in streaming playback. *
5998 * in case of HLS/DASH, it does not need to have big buffer *
5999 * because it is kind of adaptive streaming. */
6000 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6001 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6002 gint high_percent = 0;
6004 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6005 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6007 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6009 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6011 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6012 "high-percent", high_percent,
6013 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6014 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6015 "max-size-buffers", 0, NULL); // disable or automatic
6018 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6019 LOGE("failed to sync decodebin state with parent");
6030 gst_object_unref(GST_OBJECT(sinkpad));
6033 gst_object_unref(GST_OBJECT(qsrcpad));
6036 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6037 * You need to explicitly set elements to the NULL state before
6038 * dropping the final reference, to allow them to clean up.
6040 gst_element_set_state(queue2, GST_STATE_NULL);
6042 /* And, it still has a parent "player".
6043 * You need to let the parent manage the object instead of unreffing the object directly.
6045 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6046 gst_object_unref(queue2);
6051 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6052 * You need to explicitly set elements to the NULL state before
6053 * dropping the final reference, to allow them to clean up.
6055 gst_element_set_state(decodebin, GST_STATE_NULL);
6057 /* And, it still has a parent "player".
6058 * You need to let the parent manage the object instead of unreffing the object directly.
6061 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6062 gst_object_unref(decodebin);
6070 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6075 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6077 LOGD("class : %s, mime : %s", factory_class, mime);
6079 /* add missing plugin */
6080 /* NOTE : msl should check missing plugin for image mime type.
6081 * Some motion jpeg clips can have playable audio track.
6082 * So, msl have to play audio after displaying popup written video format not supported.
6084 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6085 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6086 LOGD("not found demuxer");
6087 player->not_found_demuxer = TRUE;
6088 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6094 if (!g_strrstr(factory_class, "Demuxer")) {
6095 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6096 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6097 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6099 /* check that clip have multi tracks or not */
6100 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6101 LOGD("video plugin is already linked");
6103 LOGW("add VIDEO to missing plugin");
6104 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6105 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6107 } else if (g_str_has_prefix(mime, "audio")) {
6108 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6109 LOGD("audio plugin is already linked");
6111 LOGW("add AUDIO to missing plugin");
6112 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6113 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6121 return MM_ERROR_NONE;
6125 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6127 mm_player_t *player = (mm_player_t *)data;
6131 MMPLAYER_RETURN_IF_FAIL(player);
6133 /* remove fakesink. */
6134 if (!__mmplayer_gst_remove_fakesink(player,
6135 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6136 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6137 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6138 * source element are not same. To overcome this situation, this function will called
6139 * several places and several times. Therefore, this is not an error case.
6144 LOGD("[handle: %p] pipeline has completely constructed", player);
6146 if ((player->ini.async_start) &&
6147 (player->msg_posted == FALSE) &&
6148 (player->cmd >= MMPLAYER_COMMAND_START))
6149 __mmplayer_handle_missed_plugin(player);
6151 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6155 __mmplayer_check_profile(void)
6158 static int profile_tv = -1;
6160 if (__builtin_expect(profile_tv != -1, 1))
6163 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6164 switch (*profileName) {
6179 __mmplayer_get_next_uri(mm_player_t *player)
6181 MMPlayerParseProfile profile;
6183 guint num_of_list = 0;
6186 num_of_list = g_list_length(player->uri_info.uri_list);
6187 uri_idx = player->uri_info.uri_idx;
6189 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6190 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6191 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6193 LOGW("next uri does not exist");
6197 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6198 LOGE("failed to parse profile");
6202 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6203 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6204 LOGW("uri type is not supported(%d)", profile.uri_type);
6208 LOGD("success to find next uri %d", uri_idx);
6212 if (uri_idx == num_of_list) {
6213 LOGE("failed to find next uri");
6217 player->uri_info.uri_idx = uri_idx;
6218 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6220 if (mm_attrs_commit_all(player->attrs)) {
6221 LOGE("failed to commit");
6225 SECURE_LOGD("next playback uri: %s", uri);
6230 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6232 #define REPEAT_COUNT_INFINITELY -1
6233 #define REPEAT_COUNT_MIN 2
6235 MMHandleType attrs = 0;
6239 guint num_of_list = 0;
6240 int profile_tv = -1;
6244 LOGD("checking for gapless play option");
6246 if (player->pipeline->textbin) {
6247 LOGE("subtitle path is enabled. gapless play is not supported.");
6251 attrs = MMPLAYER_GET_ATTRS(player);
6253 LOGE("fail to get attributes.");
6257 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6259 /* gapless playback is not supported in case of video at TV profile. */
6260 profile_tv = __mmplayer_check_profile();
6261 if (profile_tv && video) {
6262 LOGW("not support video gapless playback");
6266 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6267 LOGE("failed to get play count");
6269 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6270 LOGE("failed to get gapless mode");
6272 /* check repeat count in case of audio */
6274 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6275 LOGW("gapless is disabled");
6279 num_of_list = g_list_length(player->uri_info.uri_list);
6281 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6283 if (num_of_list == 0) {
6284 /* audio looping path */
6285 if (count >= REPEAT_COUNT_MIN) {
6286 /* decrease play count */
6287 /* we succeeded to rewind. update play count and then wait for next EOS */
6289 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6290 /* commit attribute */
6291 if (mm_attrs_commit_all(attrs))
6292 LOGE("failed to commit attribute");
6294 } else if (count != REPEAT_COUNT_INFINITELY) {
6295 LOGD("there is no next uri and no repeat");
6298 LOGD("looping cnt %d", count);
6300 /* gapless playback path */
6301 if (!__mmplayer_get_next_uri(player)) {
6302 LOGE("failed to get next uri");
6309 LOGE("unable to play gapless path. EOS will be posted soon");
6314 __mmplayer_initialize_gapless_play(mm_player_t *player)
6320 player->smooth_streaming = FALSE;
6321 player->videodec_linked = 0;
6322 player->audiodec_linked = 0;
6323 player->textsink_linked = 0;
6324 player->is_external_subtitle_present = FALSE;
6325 player->is_external_subtitle_added_now = FALSE;
6326 player->not_supported_codec = MISSING_PLUGIN_NONE;
6327 player->can_support_codec = FOUND_PLUGIN_NONE;
6328 player->pending_seek.is_pending = false;
6329 player->pending_seek.pos = 0;
6330 player->msg_posted = FALSE;
6331 player->has_many_types = FALSE;
6332 player->no_more_pad = FALSE;
6333 player->not_found_demuxer = 0;
6334 player->seek_state = MMPLAYER_SEEK_NONE;
6335 player->is_subtitle_force_drop = FALSE;
6336 player->play_subtitle = FALSE;
6337 player->adjust_subtitle_pos = 0;
6339 player->total_bitrate = 0;
6340 player->total_maximum_bitrate = 0;
6342 __mmplayer_track_initialize(player);
6343 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6345 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6346 player->bitrate[i] = 0;
6347 player->maximum_bitrate[i] = 0;
6350 if (player->v_stream_caps) {
6351 gst_caps_unref(player->v_stream_caps);
6352 player->v_stream_caps = NULL;
6355 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6357 /* clean found parsers */
6358 if (player->parsers) {
6359 GList *parsers = player->parsers;
6360 for (; parsers; parsers = g_list_next(parsers)) {
6361 gchar *name = parsers->data;
6362 MMPLAYER_FREEIF(name);
6364 g_list_free(player->parsers);
6365 player->parsers = NULL;
6368 /* clean found audio decoders */
6369 if (player->audio_decoders) {
6370 GList *a_dec = player->audio_decoders;
6371 for (; a_dec; a_dec = g_list_next(a_dec)) {
6372 gchar *name = a_dec->data;
6373 MMPLAYER_FREEIF(name);
6375 g_list_free(player->audio_decoders);
6376 player->audio_decoders = NULL;
6383 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6385 MMPlayerGstElement *mainbin = NULL;
6386 MMMessageParamType msg_param = {0,};
6387 GstElement *element = NULL;
6388 MMHandleType attrs = 0;
6390 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6394 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6395 LOGE("player is not initialized");
6399 mainbin = player->pipeline->mainbin;
6400 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6402 attrs = MMPLAYER_GET_ATTRS(player);
6404 LOGE("fail to get attributes");
6408 /* Initialize Player values */
6409 __mmplayer_initialize_gapless_play(player);
6411 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6413 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6414 LOGE("failed to parse profile");
6415 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6419 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6420 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6421 LOGE("dash or hls is not supportable");
6422 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6426 element = __mmplayer_gst_create_source(player);
6428 LOGE("no source element was created");
6432 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6433 LOGE("failed to add source element to pipeline");
6434 gst_object_unref(GST_OBJECT(element));
6439 /* take source element */
6440 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6441 mainbin[MMPLAYER_M_SRC].gst = element;
6445 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6446 if (player->streamer == NULL) {
6447 player->streamer = __mm_player_streaming_create();
6448 __mm_player_streaming_initialize(player->streamer, TRUE);
6451 elem_idx = MMPLAYER_M_TYPEFIND;
6452 element = gst_element_factory_make("typefind", "typefinder");
6453 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6454 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6456 elem_idx = MMPLAYER_M_AUTOPLUG;
6457 element = __mmplayer_gst_make_decodebin(player);
6460 /* check autoplug element is OK */
6462 LOGE("can not create element(%d)", elem_idx);
6466 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6467 LOGE("failed to add sinkbin to pipeline");
6468 gst_object_unref(GST_OBJECT(element));
6473 mainbin[elem_idx].id = elem_idx;
6474 mainbin[elem_idx].gst = element;
6476 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6477 LOGE("Failed to link src - autoplug(or typefind)");
6481 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6482 LOGE("Failed to change state of src element");
6486 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6487 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6488 LOGE("Failed to change state of decodebin");
6492 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6493 LOGE("Failed to change state of src element");
6498 player->gapless.stream_changed = TRUE;
6499 player->gapless.running = TRUE;
6505 MMPLAYER_PLAYBACK_UNLOCK(player);
6507 if (!player->msg_posted) {
6508 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6509 player->msg_posted = TRUE;
6516 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6518 mm_player_selector_t *selector = &player->selector[type];
6519 MMPlayerGstElement *sinkbin = NULL;
6520 enum MainElementID selectorId = MMPLAYER_M_NUM;
6521 enum MainElementID sinkId = MMPLAYER_M_NUM;
6522 GstPad *srcpad = NULL;
6523 GstPad *sinkpad = NULL;
6524 gboolean send_notice = FALSE;
6527 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6529 LOGD("type %d", type);
6532 case MM_PLAYER_TRACK_TYPE_AUDIO:
6533 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6534 sinkId = MMPLAYER_A_BIN;
6535 sinkbin = player->pipeline->audiobin;
6537 case MM_PLAYER_TRACK_TYPE_VIDEO:
6538 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6539 sinkId = MMPLAYER_V_BIN;
6540 sinkbin = player->pipeline->videobin;
6543 case MM_PLAYER_TRACK_TYPE_TEXT:
6544 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6545 sinkId = MMPLAYER_T_BIN;
6546 sinkbin = player->pipeline->textbin;
6549 LOGE("requested type is not supportable");
6554 if (player->pipeline->mainbin[selectorId].gst) {
6557 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6559 if (selector->event_probe_id != 0)
6560 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6561 selector->event_probe_id = 0;
6563 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6564 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6566 if (srcpad && sinkpad) {
6567 /* after getting drained signal there is no data flows, so no need to do pad_block */
6568 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6569 gst_pad_unlink(srcpad, sinkpad);
6571 /* send custom event to sink pad to handle it at video sink */
6573 LOGD("send custom event to sinkpad");
6574 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6575 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6576 gst_pad_send_event(sinkpad, event);
6580 gst_object_unref(sinkpad);
6583 gst_object_unref(srcpad);
6586 LOGD("selector release");
6588 /* release and unref requests pad from the selector */
6589 for (n = 0; n < selector->channels->len; n++) {
6590 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6591 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6593 g_ptr_array_set_size(selector->channels, 0);
6595 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6596 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6598 player->pipeline->mainbin[selectorId].gst = NULL;
6606 __mmplayer_deactivate_old_path(mm_player_t *player)
6609 MMPLAYER_RETURN_IF_FAIL(player);
6611 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6612 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6613 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6614 LOGE("deactivate selector error");
6618 __mmplayer_track_destroy(player);
6619 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6621 if (player->streamer) {
6622 __mm_player_streaming_initialize(player->streamer, FALSE);
6623 __mm_player_streaming_destroy(player->streamer);
6624 player->streamer = NULL;
6627 MMPLAYER_PLAYBACK_LOCK(player);
6628 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6635 if (!player->msg_posted) {
6636 MMMessageParamType msg = {0,};
6639 msg.code = MM_ERROR_PLAYER_INTERNAL;
6640 LOGE("gapless_uri_play> deactivate error");
6642 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6643 player->msg_posted = TRUE;
6649 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6651 int result = MM_ERROR_NONE;
6652 mm_player_t *player = (mm_player_t *)hplayer;
6655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6657 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6658 if (mm_attrs_commit_all(player->attrs)) {
6659 LOGE("failed to commit the original uri.");
6660 result = MM_ERROR_PLAYER_INTERNAL;
6662 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6663 LOGE("failed to add the original uri in the uri list.");
6671 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6673 mm_player_t *player = (mm_player_t *)hplayer;
6674 guint num_of_list = 0;
6678 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6679 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6681 if (player->pipeline && player->pipeline->textbin) {
6682 LOGE("subtitle path is enabled.");
6683 return MM_ERROR_PLAYER_INVALID_STATE;
6686 num_of_list = g_list_length(player->uri_info.uri_list);
6688 if (is_first_path) {
6689 if (num_of_list == 0) {
6690 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6691 LOGD("add original path : %s", uri);
6693 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6694 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6696 LOGD("change original path : %s", uri);
6699 MMHandleType attrs = 0;
6700 attrs = MMPLAYER_GET_ATTRS(player);
6702 if (num_of_list == 0) {
6703 char *original_uri = NULL;
6706 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6708 if (!original_uri) {
6709 LOGE("there is no original uri.");
6710 return MM_ERROR_PLAYER_INVALID_STATE;
6713 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6714 player->uri_info.uri_idx = 0;
6716 LOGD("add original path at first : %s", original_uri);
6720 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6721 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6725 return MM_ERROR_NONE;
6729 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6731 mm_player_t *player = (mm_player_t *)hplayer;
6732 char *next_uri = NULL;
6733 guint num_of_list = 0;
6736 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6738 num_of_list = g_list_length(player->uri_info.uri_list);
6740 if (num_of_list > 0) {
6741 gint uri_idx = player->uri_info.uri_idx;
6743 if (uri_idx < num_of_list-1)
6748 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6749 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6751 *uri = g_strdup(next_uri);
6755 return MM_ERROR_NONE;
6759 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6760 GstCaps *caps, gpointer data)
6762 mm_player_t *player = (mm_player_t *)data;
6763 const gchar *klass = NULL;
6764 const gchar *mime = NULL;
6765 gchar *caps_str = NULL;
6767 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6768 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6769 caps_str = gst_caps_to_string(caps);
6771 LOGW("unknown type of caps : %s from %s",
6772 caps_str, GST_ELEMENT_NAME(elem));
6774 MMPLAYER_FREEIF(caps_str);
6776 /* There is no available codec. */
6777 __mmplayer_check_not_supported_codec(player, klass, mime);
6781 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6782 GstCaps *caps, gpointer data)
6784 mm_player_t *player = (mm_player_t *)data;
6785 const char *mime = NULL;
6786 gboolean ret = TRUE;
6788 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6789 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6791 if (g_str_has_prefix(mime, "audio")) {
6792 GstStructure *caps_structure = NULL;
6793 gint samplerate = 0;
6795 gchar *caps_str = NULL;
6797 caps_structure = gst_caps_get_structure(caps, 0);
6798 gst_structure_get_int(caps_structure, "rate", &samplerate);
6799 gst_structure_get_int(caps_structure, "channels", &channels);
6801 if ((channels > 0 && samplerate == 0)) {
6802 LOGD("exclude audio...");
6806 caps_str = gst_caps_to_string(caps);
6807 /* set it directly because not sent by TAG */
6808 if (g_strrstr(caps_str, "mobile-xmf"))
6809 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6810 MMPLAYER_FREEIF(caps_str);
6811 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6812 MMMessageParamType msg_param;
6813 memset(&msg_param, 0, sizeof(MMMessageParamType));
6814 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6815 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6816 LOGD("video file is not supported on this device");
6818 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6819 LOGD("already video linked");
6822 LOGD("found new stream");
6829 __mmplayer_check_offload_path(mm_player_t *player)
6831 gboolean ret = FALSE;
6832 GstElementFactory *factory = NULL;
6835 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6837 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6838 /* FIXME : 1. need to consider the current audio output path and
6839 player have to know whether it support offload or not.
6840 2. could be added new condition about content length */
6841 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6842 if (!__mmplayer_is_only_mp3_type(player->type))
6845 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6849 LOGD("can setup the audio offload path");
6850 gst_object_unref(factory);
6859 static GstAutoplugSelectResult
6860 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6862 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6864 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6865 int audio_offload = 0;
6867 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6868 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6870 if (audio_offload && __mmplayer_check_offload_path(player)) {
6871 LOGD("expose audio path to build offload path");
6872 player->build_audio_offload = TRUE;
6873 /* update codec info */
6874 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6875 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6876 player->audiodec_linked = 1;
6878 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6882 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6884 LOGD("audio codec type: %d", codec_type);
6885 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6886 /* sw codec will be skipped */
6887 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6888 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6889 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6890 ret = GST_AUTOPLUG_SELECT_SKIP;
6894 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6895 /* hw codec will be skipped */
6896 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6897 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6898 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6899 ret = GST_AUTOPLUG_SELECT_SKIP;
6904 /* set stream information */
6905 if (!player->audiodec_linked)
6906 __mmplayer_set_audio_attrs(player, caps);
6908 /* update codec info */
6909 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6910 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6911 player->audiodec_linked = 1;
6913 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6915 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6917 LOGD("video codec type: %d", codec_type);
6918 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6919 /* sw codec is skipped */
6920 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6921 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6922 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6923 ret = GST_AUTOPLUG_SELECT_SKIP;
6927 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6928 /* hw codec is skipped */
6929 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6930 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6931 ret = GST_AUTOPLUG_SELECT_SKIP;
6936 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6937 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6939 /* mark video decoder for acquire */
6940 if (player->video_decoder_resource == NULL) {
6941 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6942 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6943 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6944 &player->video_decoder_resource)
6945 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6946 LOGE("could not mark video_decoder resource for acquire");
6947 ret = GST_AUTOPLUG_SELECT_SKIP;
6951 LOGW("video decoder resource is already acquired, skip it.");
6952 ret = GST_AUTOPLUG_SELECT_SKIP;
6956 player->interrupted_by_resource = FALSE;
6957 /* acquire resources for video playing */
6958 if (mm_resource_manager_commit(player->resource_manager)
6959 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6960 LOGE("could not acquire resources for video decoding");
6961 ret = GST_AUTOPLUG_SELECT_SKIP;
6966 /* update codec info */
6967 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6968 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6969 player->videodec_linked = 1;
6977 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6978 GstCaps *caps, GstElementFactory *factory, gpointer data)
6980 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6981 mm_player_t *player = (mm_player_t *)data;
6983 gchar *factory_name = NULL;
6984 gchar *caps_str = NULL;
6985 const gchar *klass = NULL;
6988 factory_name = GST_OBJECT_NAME(factory);
6989 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6990 caps_str = gst_caps_to_string(caps);
6992 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6994 /* store type string */
6995 if (player->type == NULL) {
6996 player->type = gst_caps_to_string(caps);
6997 __mmplayer_update_content_type_info(player);
7000 /* filtering exclude keyword */
7001 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7002 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7003 LOGW("skipping [%s] by exculde keyword [%s]",
7004 factory_name, player->ini.exclude_element_keyword[idx]);
7006 result = GST_AUTOPLUG_SELECT_SKIP;
7011 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7012 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7013 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7014 factory_name, player->ini.unsupported_codec_keyword[idx]);
7015 result = GST_AUTOPLUG_SELECT_SKIP;
7020 /* exclude webm format */
7021 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7022 * because webm format is not supportable.
7023 * If webm is disabled in "autoplug-continue", there is no state change
7024 * failure or error because the decodebin will expose the pad directly.
7025 * It make MSL invoke _prepare_async_callback.
7026 * So, we need to disable webm format in "autoplug-select" */
7027 if (caps_str && strstr(caps_str, "webm")) {
7028 LOGW("webm is not supported");
7029 result = GST_AUTOPLUG_SELECT_SKIP;
7033 /* check factory class for filtering */
7034 /* NOTE : msl don't need to use image plugins.
7035 * So, those plugins should be skipped for error handling.
7037 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7038 LOGD("skipping [%s] by not required", factory_name);
7039 result = GST_AUTOPLUG_SELECT_SKIP;
7043 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7044 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7045 // TO CHECK : subtitle if needed, add subparse exception.
7046 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7047 result = GST_AUTOPLUG_SELECT_SKIP;
7051 if (g_strrstr(factory_name, "mpegpsdemux")) {
7052 LOGD("skipping PS container - not support");
7053 result = GST_AUTOPLUG_SELECT_SKIP;
7057 if (g_strrstr(factory_name, "mssdemux"))
7058 player->smooth_streaming = TRUE;
7060 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7061 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7064 GstStructure *str = NULL;
7065 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7067 /* don't make video because of not required */
7068 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7069 (!player->set_mode.media_packet_video_stream)) {
7070 LOGD("no need video decoding, expose pad");
7071 result = GST_AUTOPLUG_SELECT_EXPOSE;
7075 /* get w/h for omx state-tune */
7076 /* FIXME: deprecated? */
7077 str = gst_caps_get_structure(caps, 0);
7078 gst_structure_get_int(str, "width", &width);
7081 if (player->v_stream_caps) {
7082 gst_caps_unref(player->v_stream_caps);
7083 player->v_stream_caps = NULL;
7086 player->v_stream_caps = gst_caps_copy(caps);
7087 LOGD("take caps for video state tune");
7088 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7092 if (g_strrstr(klass, "Codec/Decoder")) {
7093 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7094 if (result != GST_AUTOPLUG_SELECT_TRY) {
7095 LOGW("skip add decoder");
7101 MMPLAYER_FREEIF(caps_str);
7107 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7110 //mm_player_t *player = (mm_player_t *)data;
7111 GstCaps *caps = NULL;
7113 LOGD("[Decodebin2] pad-removed signal");
7115 caps = gst_pad_query_caps(new_pad, NULL);
7117 LOGW("query caps is NULL");
7121 gchar *caps_str = NULL;
7122 caps_str = gst_caps_to_string(caps);
7124 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7126 MMPLAYER_FREEIF(caps_str);
7127 gst_caps_unref(caps);
7131 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7133 mm_player_t *player = (mm_player_t *)data;
7134 GstIterator *iter = NULL;
7135 GValue item = { 0, };
7137 gboolean done = FALSE;
7138 gboolean is_all_drained = TRUE;
7141 MMPLAYER_RETURN_IF_FAIL(player);
7143 LOGD("__mmplayer_gst_decode_drained");
7145 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7146 LOGW("Fail to get cmd lock");
7150 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7151 !__mmplayer_verify_gapless_play_path(player)) {
7152 LOGD("decoding is finished.");
7153 __mmplayer_reset_gapless_state(player);
7154 MMPLAYER_CMD_UNLOCK(player);
7158 player->gapless.reconfigure = TRUE;
7160 /* check decodebin src pads whether they received EOS or not */
7161 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7164 switch (gst_iterator_next(iter, &item)) {
7165 case GST_ITERATOR_OK:
7166 pad = g_value_get_object(&item);
7167 if (pad && !GST_PAD_IS_EOS(pad)) {
7168 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7169 is_all_drained = FALSE;
7172 g_value_reset(&item);
7174 case GST_ITERATOR_RESYNC:
7175 gst_iterator_resync(iter);
7177 case GST_ITERATOR_ERROR:
7178 case GST_ITERATOR_DONE:
7183 g_value_unset(&item);
7184 gst_iterator_free(iter);
7186 if (!is_all_drained) {
7187 LOGD("Wait util the all pads get EOS.");
7188 MMPLAYER_CMD_UNLOCK(player);
7193 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7194 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7196 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7197 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7198 __mmplayer_deactivate_old_path(player);
7199 MMPLAYER_CMD_UNLOCK(player);
7205 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7207 mm_player_t *player = (mm_player_t *)data;
7208 const gchar *klass = NULL;
7209 gchar *factory_name = NULL;
7211 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7212 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7214 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7216 if (__mmplayer_add_dump_buffer_probe(player, element))
7217 LOGD("add buffer probe");
7220 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7221 gchar *selected = NULL;
7222 selected = g_strdup(GST_ELEMENT_NAME(element));
7223 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7227 if (g_strrstr(klass, "Parser")) {
7228 gchar *selected = NULL;
7230 selected = g_strdup(factory_name);
7231 player->parsers = g_list_append(player->parsers, selected);
7234 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7235 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7236 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7238 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7239 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7241 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7242 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7243 "max-video-width", player->adaptive_info.limit.width,
7244 "max-video-height", player->adaptive_info.limit.height, NULL);
7246 } else if (g_strrstr(klass, "Demuxer")) {
7247 //LOGD("plugged element is demuxer. take it");
7248 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7249 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7252 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7253 int surface_type = 0;
7255 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7258 // to support trust-zone only
7259 if (g_strrstr(factory_name, "asfdemux")) {
7260 LOGD("set file-location %s", player->profile.uri);
7261 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7262 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7263 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7264 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7265 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7266 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7267 (__mmplayer_is_only_mp3_type(player->type))) {
7268 LOGD("[mpegaudioparse] set streaming pull mode.");
7269 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7271 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7272 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7275 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7276 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7277 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7279 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7280 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7282 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7283 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7284 (MMPLAYER_IS_DASH_STREAMING(player))) {
7285 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7286 __mm_player_streaming_set_multiqueue(player->streamer, element);
7287 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7296 __mmplayer_release_misc(mm_player_t *player)
7299 bool cur_mode = player->set_mode.rich_audio;
7302 MMPLAYER_RETURN_IF_FAIL(player);
7304 player->video_stream_cb = NULL;
7305 player->video_stream_cb_user_param = NULL;
7306 player->video_stream_prerolled = false;
7308 player->audio_stream_render_cb = NULL;
7309 player->audio_stream_cb_user_param = NULL;
7310 player->audio_stream_sink_sync = false;
7312 player->video_stream_changed_cb = NULL;
7313 player->video_stream_changed_cb_user_param = NULL;
7315 player->audio_stream_changed_cb = NULL;
7316 player->audio_stream_changed_cb_user_param = NULL;
7318 player->sent_bos = FALSE;
7319 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7321 player->seek_state = MMPLAYER_SEEK_NONE;
7323 player->total_bitrate = 0;
7324 player->total_maximum_bitrate = 0;
7326 player->not_found_demuxer = 0;
7328 player->last_position = 0;
7329 player->duration = 0;
7330 player->http_content_size = 0;
7331 player->not_supported_codec = MISSING_PLUGIN_NONE;
7332 player->can_support_codec = FOUND_PLUGIN_NONE;
7333 player->pending_seek.is_pending = false;
7334 player->pending_seek.pos = 0;
7335 player->msg_posted = FALSE;
7336 player->has_many_types = FALSE;
7337 player->is_subtitle_force_drop = FALSE;
7338 player->play_subtitle = FALSE;
7339 player->adjust_subtitle_pos = 0;
7340 player->last_multiwin_status = FALSE;
7341 player->has_closed_caption = FALSE;
7342 player->set_mode.media_packet_video_stream = false;
7343 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7344 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7346 player->set_mode.rich_audio = cur_mode;
7348 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7349 player->bitrate[i] = 0;
7350 player->maximum_bitrate[i] = 0;
7353 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7355 /* remove media stream cb(appsrc cb) */
7356 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7357 player->media_stream_buffer_status_cb[i] = NULL;
7358 player->media_stream_seek_data_cb[i] = NULL;
7359 player->buffer_cb_user_param[i] = NULL;
7360 player->seek_cb_user_param[i] = NULL;
7362 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7364 /* free memory related to audio effect */
7365 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7367 if (player->adaptive_info.var_list) {
7368 g_list_free_full(player->adaptive_info.var_list, g_free);
7369 player->adaptive_info.var_list = NULL;
7372 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7373 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7374 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7376 /* Reset video360 settings to their defaults in case if the pipeline is to be
7379 player->video360_metadata.is_spherical = -1;
7380 player->is_openal_plugin_used = FALSE;
7382 player->is_content_spherical = FALSE;
7383 player->is_video360_enabled = TRUE;
7384 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7385 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7386 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7387 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7388 player->video360_zoom = 1.0f;
7389 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7390 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7392 player->sound.rg_enable = false;
7394 __mmplayer_initialize_video_roi(player);
7399 __mmplayer_release_misc_post(mm_player_t *player)
7401 char *original_uri = NULL;
7404 /* player->pipeline is already released before. */
7406 MMPLAYER_RETURN_IF_FAIL(player);
7408 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7410 /* clean found parsers */
7411 if (player->parsers) {
7412 GList *parsers = player->parsers;
7413 for (; parsers; parsers = g_list_next(parsers)) {
7414 gchar *name = parsers->data;
7415 MMPLAYER_FREEIF(name);
7417 g_list_free(player->parsers);
7418 player->parsers = NULL;
7421 /* clean found audio decoders */
7422 if (player->audio_decoders) {
7423 GList *a_dec = player->audio_decoders;
7424 for (; a_dec; a_dec = g_list_next(a_dec)) {
7425 gchar *name = a_dec->data;
7426 MMPLAYER_FREEIF(name);
7428 g_list_free(player->audio_decoders);
7429 player->audio_decoders = NULL;
7432 /* clean the uri list except original uri */
7433 if (player->uri_info.uri_list) {
7434 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7436 if (player->attrs) {
7437 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7438 LOGD("restore original uri = %s", original_uri);
7440 if (mm_attrs_commit_all(player->attrs))
7441 LOGE("failed to commit the original uri.");
7444 GList *uri_list = player->uri_info.uri_list;
7445 for (; uri_list; uri_list = g_list_next(uri_list)) {
7446 gchar *uri = uri_list->data;
7447 MMPLAYER_FREEIF(uri);
7449 g_list_free(player->uri_info.uri_list);
7450 player->uri_info.uri_list = NULL;
7453 /* clear the audio stream buffer list */
7454 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7456 /* clear the video stream bo list */
7457 __mmplayer_video_stream_destroy_bo_list(player);
7458 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7460 if (player->profile.input_mem.buf) {
7461 free(player->profile.input_mem.buf);
7462 player->profile.input_mem.buf = NULL;
7464 player->profile.input_mem.len = 0;
7465 player->profile.input_mem.offset = 0;
7467 player->uri_info.uri_idx = 0;
7472 __mmplayer_check_subtitle(mm_player_t *player)
7474 MMHandleType attrs = 0;
7475 char *subtitle_uri = NULL;
7479 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7481 /* get subtitle attribute */
7482 attrs = MMPLAYER_GET_ATTRS(player);
7486 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7487 if (!subtitle_uri || !strlen(subtitle_uri))
7490 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7491 player->is_external_subtitle_present = TRUE;
7499 __mmplayer_cancel_eos_timer(mm_player_t *player)
7501 MMPLAYER_RETURN_IF_FAIL(player);
7503 if (player->eos_timer) {
7504 LOGD("cancel eos timer");
7505 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7506 player->eos_timer = 0;
7513 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7517 MMPLAYER_RETURN_IF_FAIL(player);
7518 MMPLAYER_RETURN_IF_FAIL(sink);
7520 player->sink_elements = g_list_append(player->sink_elements, sink);
7526 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7530 MMPLAYER_RETURN_IF_FAIL(player);
7531 MMPLAYER_RETURN_IF_FAIL(sink);
7533 player->sink_elements = g_list_remove(player->sink_elements, sink);
7539 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7540 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7542 MMPlayerSignalItem *item = NULL;
7545 MMPLAYER_RETURN_IF_FAIL(player);
7547 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7548 LOGE("invalid signal type [%d]", type);
7552 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7554 LOGE("cannot connect signal [%s]", signal);
7559 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7560 player->signals[type] = g_list_append(player->signals[type], item);
7566 /* NOTE : be careful with calling this api. please refer to below glib comment
7567 * glib comment : Note that there is a bug in GObject that makes this function much
7568 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7569 * will no longer be called, but, the signal handler is not currently disconnected.
7570 * If the instance is itself being freed at the same time than this doesn't matter,
7571 * since the signal will automatically be removed, but if instance persists,
7572 * then the signal handler will leak. You should not remove the signal yourself
7573 * because in a future versions of GObject, the handler will automatically be
7576 * It's possible to work around this problem in a way that will continue to work
7577 * with future versions of GObject by checking that the signal handler is still
7578 * connected before disconnected it:
7580 * if (g_signal_handler_is_connected(instance, id))
7581 * g_signal_handler_disconnect(instance, id);
7584 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7586 GList *sig_list = NULL;
7587 MMPlayerSignalItem *item = NULL;
7591 MMPLAYER_RETURN_IF_FAIL(player);
7593 LOGD("release signals type : %d", type);
7595 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7596 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7598 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7599 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7600 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7604 sig_list = player->signals[type];
7606 for (; sig_list; sig_list = sig_list->next) {
7607 item = sig_list->data;
7609 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7610 if (g_signal_handler_is_connected(item->obj, item->sig))
7611 g_signal_handler_disconnect(item->obj, item->sig);
7614 MMPLAYER_FREEIF(item);
7617 g_list_free(player->signals[type]);
7618 player->signals[type] = NULL;
7626 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7628 mm_player_t *player = 0;
7629 int prev_display_surface_type = 0;
7630 void *prev_display_overlay = NULL;
7634 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7635 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7637 player = MM_PLAYER_CAST(handle);
7639 /* check video sinkbin is created */
7640 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7641 LOGE("Videosink is already created");
7642 return MM_ERROR_NONE;
7645 LOGD("videosink element is not yet ready");
7647 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7648 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7650 return MM_ERROR_INVALID_ARGUMENT;
7653 /* load previous attributes */
7654 if (player->attrs) {
7655 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7656 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7657 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7658 if (prev_display_surface_type == surface_type) {
7659 LOGD("incoming display surface type is same as previous one, do nothing..");
7661 return MM_ERROR_NONE;
7664 LOGE("failed to load attributes");
7666 return MM_ERROR_PLAYER_INTERNAL;
7669 /* videobin is not created yet, so we just set attributes related to display surface */
7670 LOGD("store display attribute for given surface type(%d)", surface_type);
7671 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7672 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7673 if (mm_attrs_commit_all(player->attrs)) {
7674 LOGE("failed to commit attribute");
7676 return MM_ERROR_PLAYER_INTERNAL;
7680 return MM_ERROR_NONE;
7683 /* Note : if silent is true, then subtitle would not be displayed. :*/
7685 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7687 mm_player_t *player = (mm_player_t *)hplayer;
7691 /* check player handle */
7692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7694 player->set_mode.subtitle_off = silent;
7696 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7700 return MM_ERROR_NONE;
7704 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7706 MMPlayerGstElement *mainbin = NULL;
7707 MMPlayerGstElement *textbin = NULL;
7708 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7709 GstState current_state = GST_STATE_VOID_PENDING;
7710 GstState element_state = GST_STATE_VOID_PENDING;
7711 GstState element_pending_state = GST_STATE_VOID_PENDING;
7713 GstEvent *event = NULL;
7714 int result = MM_ERROR_NONE;
7716 GstClock *curr_clock = NULL;
7717 GstClockTime base_time, start_time, curr_time;
7722 /* check player handle */
7723 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7725 player->pipeline->mainbin &&
7726 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7728 mainbin = player->pipeline->mainbin;
7729 textbin = player->pipeline->textbin;
7731 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7733 // sync clock with current pipeline
7734 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7735 curr_time = gst_clock_get_time(curr_clock);
7737 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7738 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7740 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7741 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7743 if (current_state > GST_STATE_READY) {
7744 // sync state with current pipeline
7745 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7746 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7747 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7749 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7750 if (GST_STATE_CHANGE_FAILURE == ret) {
7751 LOGE("fail to state change.");
7752 result = MM_ERROR_PLAYER_INTERNAL;
7756 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7757 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7760 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7761 gst_object_unref(curr_clock);
7764 // seek to current position
7765 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7766 result = MM_ERROR_PLAYER_INVALID_STATE;
7767 LOGE("gst_element_query_position failed, invalid state");
7771 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7772 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);
7774 __mmplayer_gst_send_event_to_sink(player, event);
7776 result = MM_ERROR_PLAYER_INTERNAL;
7777 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7781 /* sync state with current pipeline */
7782 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7783 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7784 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7786 return MM_ERROR_NONE;
7789 /* release text pipeline resource */
7790 player->textsink_linked = 0;
7792 /* release signal */
7793 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7795 /* release textbin with it's childs */
7796 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7797 MMPLAYER_FREEIF(player->pipeline->textbin);
7798 player->pipeline->textbin = NULL;
7800 /* release subtitle elem */
7801 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7802 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7808 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7810 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7811 GstState current_state = GST_STATE_VOID_PENDING;
7813 MMHandleType attrs = 0;
7814 MMPlayerGstElement *mainbin = NULL;
7815 MMPlayerGstElement *textbin = NULL;
7817 gchar *subtitle_uri = NULL;
7818 int result = MM_ERROR_NONE;
7819 const gchar *charset = NULL;
7823 /* check player handle */
7824 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7826 player->pipeline->mainbin &&
7827 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7828 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7830 mainbin = player->pipeline->mainbin;
7831 textbin = player->pipeline->textbin;
7833 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7834 if (current_state < GST_STATE_READY) {
7835 result = MM_ERROR_PLAYER_INVALID_STATE;
7836 LOGE("Pipeline is not in proper state");
7840 attrs = MMPLAYER_GET_ATTRS(player);
7842 LOGE("cannot get content attribute");
7843 result = MM_ERROR_PLAYER_INTERNAL;
7847 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7848 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7849 LOGE("subtitle uri is not proper filepath");
7850 result = MM_ERROR_PLAYER_INVALID_URI;
7854 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7855 LOGE("failed to get storage info of subtitle path");
7856 result = MM_ERROR_PLAYER_INVALID_URI;
7860 LOGD("old subtitle file path is [%s]", subtitle_uri);
7861 LOGD("new subtitle file path is [%s]", filepath);
7863 if (!strcmp(filepath, subtitle_uri)) {
7864 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7867 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7868 if (mm_attrs_commit_all(player->attrs)) {
7869 LOGE("failed to commit.");
7874 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7875 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7876 player->subtitle_language_list = NULL;
7877 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7879 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7880 if (ret != GST_STATE_CHANGE_SUCCESS) {
7881 LOGE("failed to change state of textbin to READY");
7882 result = MM_ERROR_PLAYER_INTERNAL;
7886 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7887 if (ret != GST_STATE_CHANGE_SUCCESS) {
7888 LOGE("failed to change state of subparse to READY");
7889 result = MM_ERROR_PLAYER_INTERNAL;
7893 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7894 if (ret != GST_STATE_CHANGE_SUCCESS) {
7895 LOGE("failed to change state of filesrc to READY");
7896 result = MM_ERROR_PLAYER_INTERNAL;
7900 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7902 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7904 charset = util_get_charset(filepath);
7906 LOGD("detected charset is %s", charset);
7907 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7910 result = _mmplayer_sync_subtitle_pipeline(player);
7917 /* API to switch between external subtitles */
7919 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7921 int result = MM_ERROR_NONE;
7922 mm_player_t *player = (mm_player_t *)hplayer;
7927 /* check player handle */
7928 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7930 /* filepath can be null in idle state */
7932 /* check file path */
7933 if ((path = strstr(filepath, "file://")))
7934 result = util_exist_file_path(path + 7);
7936 result = util_exist_file_path(filepath);
7938 if (result != MM_ERROR_NONE) {
7939 LOGE("invalid subtitle path 0x%X", result);
7940 return result; /* file not found or permission denied */
7944 if (!player->pipeline) {
7946 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7947 if (mm_attrs_commit_all(player->attrs)) {
7948 LOGE("failed to commit"); /* subtitle path will not be created */
7949 return MM_ERROR_PLAYER_INTERNAL;
7952 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7953 /* check filepath */
7954 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7956 if (!__mmplayer_check_subtitle(player)) {
7957 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7958 if (mm_attrs_commit_all(player->attrs)) {
7959 LOGE("failed to commit");
7960 return MM_ERROR_PLAYER_INTERNAL;
7963 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7964 LOGE("fail to create text pipeline");
7965 return MM_ERROR_PLAYER_INTERNAL;
7968 result = _mmplayer_sync_subtitle_pipeline(player);
7970 result = __mmplayer_change_external_subtitle_language(player, filepath);
7973 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7974 player->is_external_subtitle_added_now = TRUE;
7976 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7977 if (!player->subtitle_language_list) {
7978 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7979 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7980 LOGW("subtitle language list is not updated yet");
7982 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7990 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7992 int result = MM_ERROR_NONE;
7993 gchar *change_pad_name = NULL;
7994 GstPad *sinkpad = NULL;
7995 MMPlayerGstElement *mainbin = NULL;
7996 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7997 GstCaps *caps = NULL;
7998 gint total_track_num = 0;
8002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8003 MM_ERROR_PLAYER_NOT_INITIALIZED);
8005 LOGD("Change Track(%d) to %d", type, index);
8007 mainbin = player->pipeline->mainbin;
8009 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8010 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8011 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8012 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8014 /* Changing Video Track is not supported. */
8015 LOGE("Track Type Error");
8019 if (mainbin[elem_idx].gst == NULL) {
8020 result = MM_ERROR_PLAYER_NO_OP;
8021 LOGD("Req track doesn't exist");
8025 total_track_num = player->selector[type].total_track_num;
8026 if (total_track_num <= 0) {
8027 result = MM_ERROR_PLAYER_NO_OP;
8028 LOGD("Language list is not available");
8032 if ((index < 0) || (index >= total_track_num)) {
8033 result = MM_ERROR_INVALID_ARGUMENT;
8034 LOGD("Not a proper index : %d", index);
8038 /*To get the new pad from the selector*/
8039 change_pad_name = g_strdup_printf("sink_%u", index);
8040 if (change_pad_name == NULL) {
8041 result = MM_ERROR_PLAYER_INTERNAL;
8042 LOGD("Pad does not exists");
8046 LOGD("new active pad name: %s", change_pad_name);
8048 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8049 if (sinkpad == NULL) {
8050 LOGD("sinkpad is NULL");
8051 result = MM_ERROR_PLAYER_INTERNAL;
8055 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8056 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8058 caps = gst_pad_get_current_caps(sinkpad);
8059 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8062 gst_object_unref(sinkpad);
8064 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8065 __mmplayer_set_audio_attrs(player, caps);
8068 MMPLAYER_FREEIF(change_pad_name);
8073 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8075 int result = MM_ERROR_NONE;
8076 mm_player_t *player = NULL;
8077 MMPlayerGstElement *mainbin = NULL;
8079 gint current_active_index = 0;
8081 GstState current_state = GST_STATE_VOID_PENDING;
8082 GstEvent *event = NULL;
8087 player = (mm_player_t *)hplayer;
8088 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8090 if (!player->pipeline) {
8091 LOGE("Track %d pre setting -> %d", type, index);
8093 player->selector[type].active_pad_index = index;
8097 mainbin = player->pipeline->mainbin;
8099 current_active_index = player->selector[type].active_pad_index;
8101 /*If index is same as running index no need to change the pad*/
8102 if (current_active_index == index)
8105 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8106 result = MM_ERROR_PLAYER_INVALID_STATE;
8110 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8111 if (current_state < GST_STATE_PAUSED) {
8112 result = MM_ERROR_PLAYER_INVALID_STATE;
8113 LOGW("Pipeline not in porper state");
8117 result = __mmplayer_change_selector_pad(player, type, index);
8118 if (result != MM_ERROR_NONE) {
8119 LOGE("change selector pad error");
8123 player->selector[type].active_pad_index = index;
8125 if (current_state == GST_STATE_PLAYING) {
8126 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8127 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8128 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8130 __mmplayer_gst_send_event_to_sink(player, event);
8132 result = MM_ERROR_PLAYER_INTERNAL;
8142 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8144 mm_player_t *player = (mm_player_t *)hplayer;
8148 /* check player handle */
8149 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8151 *silent = player->set_mode.subtitle_off;
8153 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8157 return MM_ERROR_NONE;
8161 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8163 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8164 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8166 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8167 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8171 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8172 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8173 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8174 mm_player_dump_t *dump_s;
8175 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8176 if (dump_s == NULL) {
8177 LOGE("malloc fail");
8181 dump_s->dump_element_file = NULL;
8182 dump_s->dump_pad = NULL;
8183 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8185 if (dump_s->dump_pad) {
8186 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8187 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]);
8188 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8189 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);
8190 /* add list for removed buffer probe and close FILE */
8191 player->dump_list = g_list_append(player->dump_list, dump_s);
8192 LOGD("%s sink pad added buffer probe for dump", factory_name);
8195 MMPLAYER_FREEIF(dump_s);
8196 LOGE("failed to get %s sink pad added", factory_name);
8203 static GstPadProbeReturn
8204 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8206 FILE *dump_data = (FILE *)u_data;
8208 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8209 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8211 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8213 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8215 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8217 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8219 return GST_PAD_PROBE_OK;
8223 __mmplayer_release_dump_list(GList *dump_list)
8225 GList *d_list = dump_list;
8230 for (; d_list; d_list = g_list_next(d_list)) {
8231 mm_player_dump_t *dump_s = d_list->data;
8232 if (dump_s->dump_pad) {
8233 if (dump_s->probe_handle_id)
8234 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8235 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8237 if (dump_s->dump_element_file) {
8238 fclose(dump_s->dump_element_file);
8239 dump_s->dump_element_file = NULL;
8241 MMPLAYER_FREEIF(dump_s);
8243 g_list_free(dump_list);
8248 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8250 mm_player_t *player = (mm_player_t *)hplayer;
8254 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8255 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8257 *exist = (bool)player->has_closed_caption;
8261 return MM_ERROR_NONE;
8265 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8269 // LOGD("unref internal gst buffer %p", buffer);
8270 gst_buffer_unref((GstBuffer *)buffer);
8277 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8279 mm_player_t *player = (mm_player_t *)hplayer;
8283 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8284 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8286 if (MMPLAYER_IS_STREAMING(player))
8287 *timeout = (int)player->ini.live_state_change_timeout;
8289 *timeout = (int)player->ini.localplayback_state_change_timeout;
8291 LOGD("timeout = %d", *timeout);
8294 return MM_ERROR_NONE;
8298 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8300 mm_player_t *player = (mm_player_t *)hplayer;
8304 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8305 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8307 *num = player->video_num_buffers;
8308 *extra_num = player->video_extra_num_buffers;
8310 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8313 return MM_ERROR_NONE;
8317 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8321 MMPLAYER_RETURN_IF_FAIL(player);
8323 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8325 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8326 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8327 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8328 player->storage_info[i].id = -1;
8329 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8331 if (path_type != MMPLAYER_PATH_MAX)
8340 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8342 int ret = MM_ERROR_NONE;
8343 mm_player_t *player = (mm_player_t *)hplayer;
8344 MMMessageParamType msg_param = {0, };
8347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8349 LOGW("state changed storage %d:%d", id, state);
8351 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8352 return MM_ERROR_NONE;
8354 /* FIXME: text path should be handled seperately. */
8355 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8356 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8357 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8358 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8359 LOGW("external storage is removed");
8361 if (player->msg_posted == FALSE) {
8362 memset(&msg_param, 0, sizeof(MMMessageParamType));
8363 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8364 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8365 player->msg_posted = TRUE;
8368 /* unrealize the player */
8369 ret = _mmplayer_unrealize(hplayer);
8370 if (ret != MM_ERROR_NONE)
8371 LOGE("failed to unrealize");
8379 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8381 int ret = MM_ERROR_NONE;
8382 mm_player_t *player = (mm_player_t *)hplayer;
8383 int idx = 0, total = 0;
8384 gchar *result = NULL, *tmp = NULL;
8387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8388 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8390 total = *num = g_list_length(player->adaptive_info.var_list);
8392 LOGW("There is no stream variant info.");
8396 result = g_strdup("");
8397 for (idx = 0 ; idx < total ; idx++) {
8398 VariantData *v_data = NULL;
8399 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8402 gchar data[64] = {0};
8403 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8405 tmp = g_strconcat(result, data, NULL);
8409 LOGW("There is no variant data in %d", idx);
8414 *var_info = (char *)result;
8416 LOGD("variant info %d:%s", *num, *var_info);
8422 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8424 int ret = MM_ERROR_NONE;
8425 mm_player_t *player = (mm_player_t *)hplayer;
8428 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8430 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8432 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8433 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8434 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8436 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8437 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8438 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8439 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8441 /* FIXME: seek to current position for applying new variant limitation */
8450 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8452 int ret = MM_ERROR_NONE;
8453 mm_player_t *player = (mm_player_t *)hplayer;
8456 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8457 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8459 *bandwidth = player->adaptive_info.limit.bandwidth;
8460 *width = player->adaptive_info.limit.width;
8461 *height = player->adaptive_info.limit.height;
8463 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8470 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8472 int ret = MM_ERROR_NONE;
8473 mm_player_t *player = (mm_player_t *)hplayer;
8476 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8477 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8478 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8480 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8482 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8483 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8484 else /* live case */
8485 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8487 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8494 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8496 #define IDX_FIRST_SW_CODEC 0
8497 mm_player_t *player = (mm_player_t *)hplayer;
8498 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8499 MMHandleType attrs = 0;
8502 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8504 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8505 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8506 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8508 switch (stream_type) {
8509 case MM_PLAYER_STREAM_TYPE_AUDIO:
8510 /* to support audio codec selection, codec info have to be added in ini file as below.
8511 audio codec element hw = xxxx
8512 audio codec element sw = avdec */
8513 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8514 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8515 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8516 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8517 LOGE("There is no audio codec info for codec_type %d", codec_type);
8518 return MM_ERROR_PLAYER_NO_OP;
8521 case MM_PLAYER_STREAM_TYPE_VIDEO:
8522 /* to support video codec selection, codec info have to be added in ini file as below.
8523 video codec element hw = omx
8524 video codec element sw = avdec */
8525 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8526 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8527 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8528 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8529 LOGE("There is no video codec info for codec_type %d", codec_type);
8530 return MM_ERROR_PLAYER_NO_OP;
8534 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8535 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8539 LOGD("update %s codec_type to %d", attr_name, codec_type);
8541 attrs = MMPLAYER_GET_ATTRS(player);
8542 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8544 if (mm_attrs_commit_all(player->attrs)) {
8545 LOGE("failed to commit codec_type attributes");
8546 return MM_ERROR_PLAYER_INTERNAL;
8550 return MM_ERROR_NONE;
8554 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8556 mm_player_t *player = (mm_player_t *)hplayer;
8557 GstElement *rg_vol_element = NULL;
8561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8563 player->sound.rg_enable = enabled;
8565 /* just hold rgvolume enable value if pipeline is not ready */
8566 if (!player->pipeline || !player->pipeline->audiobin) {
8567 LOGD("pipeline is not ready. holding rgvolume enable value");
8568 return MM_ERROR_NONE;
8571 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8573 if (!rg_vol_element) {
8574 LOGD("rgvolume element is not created");
8575 return MM_ERROR_PLAYER_INTERNAL;
8579 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8581 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8585 return MM_ERROR_NONE;
8589 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8591 mm_player_t *player = (mm_player_t *)hplayer;
8592 GstElement *rg_vol_element = NULL;
8593 gboolean enable = FALSE;
8597 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8598 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8600 /* just hold enable_rg value if pipeline is not ready */
8601 if (!player->pipeline || !player->pipeline->audiobin) {
8602 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8603 *enabled = player->sound.rg_enable;
8604 return MM_ERROR_NONE;
8607 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8609 if (!rg_vol_element) {
8610 LOGD("rgvolume element is not created");
8611 return MM_ERROR_PLAYER_INTERNAL;
8614 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8615 *enabled = (bool)enable;
8619 return MM_ERROR_NONE;
8623 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8625 mm_player_t *player = (mm_player_t *)hplayer;
8626 MMHandleType attrs = 0;
8627 void *handle = NULL;
8628 int ret = MM_ERROR_NONE;
8632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8634 attrs = MMPLAYER_GET_ATTRS(player);
8635 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8637 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8639 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8640 return MM_ERROR_PLAYER_INTERNAL;
8643 player->video_roi.scale_x = scale_x;
8644 player->video_roi.scale_y = scale_y;
8645 player->video_roi.scale_width = scale_width;
8646 player->video_roi.scale_height = scale_height;
8648 /* check video sinkbin is created */
8649 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8650 return MM_ERROR_NONE;
8652 if (!gst_video_overlay_set_video_roi_area(
8653 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8654 scale_x, scale_y, scale_width, scale_height))
8655 ret = MM_ERROR_PLAYER_INTERNAL;
8657 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8658 scale_x, scale_y, scale_width, scale_height);
8666 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8668 mm_player_t *player = (mm_player_t *)hplayer;
8669 int ret = MM_ERROR_NONE;
8673 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8674 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8676 *scale_x = player->video_roi.scale_x;
8677 *scale_y = player->video_roi.scale_y;
8678 *scale_width = player->video_roi.scale_width;
8679 *scale_height = player->video_roi.scale_height;
8681 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8682 *scale_x, *scale_y, *scale_width, *scale_height);
8688 __mmplayer_update_duration_value(mm_player_t *player)
8690 gboolean ret = FALSE;
8691 gint64 dur_nsec = 0;
8692 LOGD("try to update duration");
8694 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8695 player->duration = dur_nsec;
8696 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8700 if (player->duration < 0) {
8701 LOGW("duration is Non-Initialized !!!");
8702 player->duration = 0;
8705 /* update streaming service type */
8706 player->streaming_type = __mmplayer_get_stream_service_type(player);
8708 /* check duration is OK */
8709 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8710 /* FIXIT : find another way to get duration here. */
8711 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8717 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8719 /* update audio params
8720 NOTE : We need original audio params and it can be only obtained from src pad of audio
8721 decoder. Below code only valid when we are not using 'resampler' just before
8722 'audioconverter'. */
8723 GstCaps *caps_a = NULL;
8725 gint samplerate = 0, channels = 0;
8726 GstStructure *p = NULL;
8728 LOGD("try to update audio attrs");
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8731 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8733 pad = gst_element_get_static_pad(
8734 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8737 LOGW("failed to get pad from audiosink");
8741 caps_a = gst_pad_get_current_caps(pad);
8743 LOGW("not ready to get audio caps");
8744 gst_object_unref(pad);
8748 p = gst_caps_get_structure(caps_a, 0);
8750 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8752 gst_structure_get_int(p, "rate", &samplerate);
8753 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8755 gst_structure_get_int(p, "channels", &channels);
8756 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8758 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8760 gst_caps_unref(caps_a);
8761 gst_object_unref(pad);
8767 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8769 LOGD("try to update video attrs");
8771 GstCaps *caps_v = NULL;
8775 GstStructure *p = NULL;
8777 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8778 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8780 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8782 LOGD("no videosink sink pad");
8786 caps_v = gst_pad_get_current_caps(pad);
8787 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8788 if (!caps_v && player->v_stream_caps) {
8789 caps_v = player->v_stream_caps;
8790 gst_caps_ref(caps_v);
8794 LOGD("no negitiated caps from videosink");
8795 gst_object_unref(pad);
8799 p = gst_caps_get_structure(caps_v, 0);
8800 gst_structure_get_int(p, "width", &width);
8801 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8803 gst_structure_get_int(p, "height", &height);
8804 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8806 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8808 SECURE_LOGD("width : %d height : %d", width, height);
8810 gst_caps_unref(caps_v);
8811 gst_object_unref(pad);
8814 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8815 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8822 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8824 gboolean ret = FALSE;
8825 guint64 data_size = 0;
8829 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8830 if (!player->duration)
8833 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8834 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8835 if (stat(path, &sb) == 0)
8836 data_size = (guint64)sb.st_size;
8838 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8839 data_size = player->http_content_size;
8842 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8845 guint64 bitrate = 0;
8846 guint64 msec_dur = 0;
8848 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8850 bitrate = data_size * 8 * 1000 / msec_dur;
8851 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8852 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8856 LOGD("player duration is less than 0");
8860 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8861 if (player->total_bitrate) {
8862 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8871 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8873 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8874 data->uri_type = uri_type;
8878 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8880 int ret = MM_ERROR_PLAYER_INVALID_URI;
8882 char *buffer = NULL;
8883 char *seperator = strchr(path, ',');
8884 char ext[100] = {0,}, size[100] = {0,};
8887 if ((buffer = strstr(path, "ext="))) {
8888 buffer += strlen("ext=");
8890 if (strlen(buffer)) {
8891 strncpy(ext, buffer, 99);
8893 if ((seperator = strchr(ext, ','))
8894 || (seperator = strchr(ext, ' '))
8895 || (seperator = strchr(ext, '\0'))) {
8896 seperator[0] = '\0';
8901 if ((buffer = strstr(path, "size="))) {
8902 buffer += strlen("size=");
8904 if (strlen(buffer) > 0) {
8905 strncpy(size, buffer, 99);
8907 if ((seperator = strchr(size, ','))
8908 || (seperator = strchr(size, ' '))
8909 || (seperator = strchr(size, '\0'))) {
8910 seperator[0] = '\0';
8913 mem_size = atoi(size);
8918 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8920 if (mem_size && param) {
8921 if (data->input_mem.buf)
8922 free(data->input_mem.buf);
8923 data->input_mem.buf = malloc(mem_size);
8925 if (data->input_mem.buf) {
8926 memcpy(data->input_mem.buf, param, mem_size);
8927 data->input_mem.len = mem_size;
8928 ret = MM_ERROR_NONE;
8930 LOGE("failed to alloc mem %d", mem_size);
8931 ret = MM_ERROR_PLAYER_INTERNAL;
8934 data->input_mem.offset = 0;
8935 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8942 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8944 gchar *location = NULL;
8947 int ret = MM_ERROR_NONE;
8949 if ((path = strstr(uri, "file://"))) {
8950 location = g_filename_from_uri(uri, NULL, &err);
8951 if (!location || (err != NULL)) {
8952 LOGE("Invalid URI '%s' for filesrc: %s", path,
8953 (err != NULL) ? err->message : "unknown error");
8957 MMPLAYER_FREEIF(location);
8959 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8960 return MM_ERROR_PLAYER_INVALID_URI;
8962 LOGD("path from uri: %s", location);
8965 path = (location != NULL) ? (location) : ((char *)uri);
8968 ret = util_exist_file_path(path);
8970 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8971 if (ret == MM_ERROR_NONE) {
8972 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8973 if (util_is_sdp_file(path)) {
8974 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8975 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8977 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8979 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8980 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8982 LOGE("invalid uri, could not play..");
8983 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8986 MMPLAYER_FREEIF(location);
8991 static MMPlayerVideoStreamDataType *
8992 __mmplayer_create_stream_from_pad(GstPad *pad)
8994 GstCaps *caps = NULL;
8995 GstStructure *structure = NULL;
8996 unsigned int fourcc = 0;
8997 const gchar *string_format = NULL;
8998 MMPlayerVideoStreamDataType *stream = NULL;
9000 MMPixelFormatType format;
9002 caps = gst_pad_get_current_caps(pad);
9004 LOGE("Caps is NULL.");
9008 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9009 structure = gst_caps_get_structure(caps, 0);
9010 gst_structure_get_int(structure, "width", &width);
9011 gst_structure_get_int(structure, "height", &height);
9012 string_format = gst_structure_get_string(structure, "format");
9014 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9015 format = util_get_pixtype(fourcc);
9016 gst_caps_unref(caps);
9019 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9020 LOGE("Wrong condition!!");
9024 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9026 LOGE("failed to alloc mem for video data");
9030 stream->width = width;
9031 stream->height = height;
9032 stream->format = format;
9038 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9040 unsigned int pitch = 0;
9042 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9044 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9045 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9046 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9047 stream->stride[index] = pitch;
9048 stream->elevation[index] = stream->height;
9053 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9055 if (stream->format == MM_PIXEL_FORMAT_I420) {
9056 int ret = TBM_SURFACE_ERROR_NONE;
9057 tbm_surface_h surface;
9058 tbm_surface_info_s info;
9060 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9062 ret = tbm_surface_get_info(surface, &info);
9063 if (ret != TBM_SURFACE_ERROR_NONE) {
9064 tbm_surface_destroy(surface);
9068 tbm_surface_destroy(surface);
9069 stream->stride[0] = info.planes[0].stride;
9070 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9071 stream->stride[1] = info.planes[1].stride;
9072 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9073 stream->stride[2] = info.planes[2].stride;
9074 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9075 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9076 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9077 stream->stride[0] = stream->width * 4;
9078 stream->elevation[0] = stream->height;
9079 stream->bo_size = stream->stride[0] * stream->height;
9081 LOGE("Not support format %d", stream->format);
9089 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9091 tbm_bo_handle thandle;
9093 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9094 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9095 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9099 unsigned char *src = NULL;
9100 unsigned char *dest = NULL;
9101 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9103 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9105 LOGE("fail to gst_memory_map");
9109 if (!mapinfo.data) {
9110 LOGE("data pointer is wrong");
9114 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9115 if (!stream->bo[0]) {
9116 LOGE("Fail to tbm_bo_alloc!!");
9120 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9122 LOGE("thandle pointer is wrong");
9126 if (stream->format == MM_PIXEL_FORMAT_I420) {
9127 src_stride[0] = GST_ROUND_UP_4(stream->width);
9128 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9129 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9130 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9133 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9134 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9136 for (i = 0; i < 3; i++) {
9137 src = mapinfo.data + src_offset[i];
9138 dest = thandle.ptr + dest_offset[i];
9143 for (j = 0; j < stream->height >> k; j++) {
9144 memcpy(dest, src, stream->width>>k);
9145 src += src_stride[i];
9146 dest += stream->stride[i];
9149 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9150 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9152 LOGE("Not support format %d", stream->format);
9156 tbm_bo_unmap(stream->bo[0]);
9157 gst_memory_unmap(mem, &mapinfo);
9163 tbm_bo_unmap(stream->bo[0]);
9166 gst_memory_unmap(mem, &mapinfo);
9172 __mmplayer_set_pause_state(mm_player_t *player)
9174 if (player->sent_bos)
9177 /* rtsp case, get content attrs by GstMessage */
9178 if (MMPLAYER_IS_RTSP_STREAMING(player))
9181 /* it's first time to update all content attrs. */
9182 __mmplayer_update_content_attrs(player, ATTR_ALL);
9186 __mmplayer_set_playing_state(mm_player_t *player)
9188 gchar *audio_codec = NULL;
9190 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9191 /* initialize because auto resume is done well. */
9192 player->resumed_by_rewind = FALSE;
9193 player->playback_rate = 1.0;
9196 if (player->sent_bos)
9199 /* try to get content metadata */
9201 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9202 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9203 * legacy mmfw-player api
9205 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9207 if ((player->cmd == MMPLAYER_COMMAND_START)
9208 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9209 __mmplayer_handle_missed_plugin(player);
9212 /* check audio codec field is set or not
9213 * we can get it from typefinder or codec's caps.
9215 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9217 /* The codec format can't be sent for audio only case like amr, mid etc.
9218 * Because, parser don't make related TAG.
9219 * So, if it's not set yet, fill it with found data.
9222 if (g_strrstr(player->type, "audio/midi"))
9223 audio_codec = "MIDI";
9224 else if (g_strrstr(player->type, "audio/x-amr"))
9225 audio_codec = "AMR";
9226 else if (g_strrstr(player->type, "audio/mpeg")
9227 && !g_strrstr(player->type, "mpegversion= (int)1"))
9228 audio_codec = "AAC";
9230 audio_codec = "unknown";
9232 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9234 if (mm_attrs_commit_all(player->attrs))
9235 LOGE("failed to update attributes");
9237 LOGD("set audio codec type with caps");