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);
3228 /* set video rotator */
3229 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3232 *bucket = element_bucket;
3234 return MM_ERROR_NONE;
3236 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3237 g_list_free(element_bucket);
3241 return MM_ERROR_PLAYER_INTERNAL;
3245 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3247 gchar *factory_name = NULL;
3249 switch (surface_type) {
3250 case MM_DISPLAY_SURFACE_OVERLAY:
3251 if (strlen(player->ini.videosink_element_overlay) > 0)
3252 factory_name = player->ini.videosink_element_overlay;
3254 case MM_DISPLAY_SURFACE_REMOTE:
3255 case MM_DISPLAY_SURFACE_NULL:
3256 if (strlen(player->ini.videosink_element_fake) > 0)
3257 factory_name = player->ini.videosink_element_fake;
3260 LOGE("unidentified surface type");
3264 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3265 return factory_name;
3269 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3271 gchar *factory_name = NULL;
3272 MMPlayerGstElement *videobin = NULL;
3277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3279 videobin = player->pipeline->videobin;
3280 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3282 attrs = MMPLAYER_GET_ATTRS(player);
3284 LOGE("cannot get content attribute");
3285 return MM_ERROR_PLAYER_INTERNAL;
3288 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3289 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3290 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3292 /* support shard memory with S/W codec on HawkP */
3293 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3294 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3295 "use-tbm", use_tbm, NULL);
3299 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3300 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3303 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3305 LOGD("disable last-sample");
3306 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3309 if (player->set_mode.media_packet_video_stream) {
3311 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3312 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3313 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3315 __mmplayer_add_signal_connection(player,
3316 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3317 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3319 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3322 __mmplayer_add_signal_connection(player,
3323 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3324 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3326 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3330 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3331 return MM_ERROR_PLAYER_INTERNAL;
3333 if (videobin[MMPLAYER_V_SINK].gst) {
3334 GstPad *sink_pad = NULL;
3335 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3337 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3338 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3339 gst_object_unref(GST_OBJECT(sink_pad));
3341 LOGE("failed to get sink pad from videosink");
3345 return MM_ERROR_NONE;
3350 * - video overlay surface(arm/x86) : tizenwlsink
3353 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3356 GList *element_bucket = NULL;
3357 MMPlayerGstElement *first_element = NULL;
3358 MMPlayerGstElement *videobin = NULL;
3359 gchar *videosink_factory_name = NULL;
3362 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3365 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3367 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3369 player->pipeline->videobin = videobin;
3372 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3373 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3374 if (!videobin[MMPLAYER_V_BIN].gst) {
3375 LOGE("failed to create videobin");
3379 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3382 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3383 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3385 /* additional setting for sink plug-in */
3386 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3387 LOGE("failed to set video property");
3391 /* store it as it's sink element */
3392 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3394 /* adding created elements to bin */
3395 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3396 LOGE("failed to add elements");
3400 /* Linking elements in the bucket by added order */
3401 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3402 LOGE("failed to link elements");
3406 /* get first element's sinkpad for creating ghostpad */
3407 first_element = (MMPlayerGstElement *)element_bucket->data;
3408 if (!first_element) {
3409 LOGE("failed to get first element from bucket");
3413 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3415 LOGE("failed to get pad from first element");
3419 /* create ghostpad */
3420 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3421 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3422 LOGE("failed to add ghostpad to videobin");
3425 gst_object_unref(pad);
3427 /* done. free allocated variables */
3428 g_list_free(element_bucket);
3432 return MM_ERROR_NONE;
3435 LOGE("ERROR : releasing videobin");
3436 g_list_free(element_bucket);
3439 gst_object_unref(GST_OBJECT(pad));
3441 /* release videobin with it's childs */
3442 if (videobin[MMPLAYER_V_BIN].gst)
3443 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3445 MMPLAYER_FREEIF(videobin);
3446 player->pipeline->videobin = NULL;
3448 return MM_ERROR_PLAYER_INTERNAL;
3452 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3454 GList *element_bucket = NULL;
3455 MMPlayerGstElement *textbin = player->pipeline->textbin;
3457 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3458 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3459 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3460 "signal-handoffs", FALSE,
3463 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3464 __mmplayer_add_signal_connection(player,
3465 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3466 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3468 G_CALLBACK(__mmplayer_update_subtitle),
3471 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3472 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3474 if (!player->play_subtitle) {
3475 LOGD("add textbin sink as sink element of whole pipeline.");
3476 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3479 /* adding created elements to bin */
3480 LOGD("adding created elements to bin");
3481 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3482 LOGE("failed to add elements");
3486 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3487 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3488 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3490 /* linking elements in the bucket by added order. */
3491 LOGD("Linking elements in the bucket by added order.");
3492 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3493 LOGE("failed to link elements");
3497 /* done. free allocated variables */
3498 g_list_free(element_bucket);
3500 if (textbin[MMPLAYER_T_QUEUE].gst) {
3502 GstPad *ghostpad = NULL;
3504 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3506 LOGE("failed to get sink pad of text queue");
3510 ghostpad = gst_ghost_pad_new("text_sink", pad);
3511 gst_object_unref(pad);
3514 LOGE("failed to create ghostpad of textbin");
3518 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3519 LOGE("failed to add ghostpad to textbin");
3520 gst_object_unref(ghostpad);
3525 return MM_ERROR_NONE;
3528 g_list_free(element_bucket);
3530 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3531 LOGE("remove textbin sink from sink list");
3532 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3535 /* release element at __mmplayer_gst_create_text_sink_bin */
3536 return MM_ERROR_PLAYER_INTERNAL;
3540 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3542 MMPlayerGstElement *textbin = NULL;
3543 GList *element_bucket = NULL;
3544 int surface_type = 0;
3549 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3552 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3554 LOGE("failed to allocate memory for textbin");
3555 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3559 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3560 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3561 if (!textbin[MMPLAYER_T_BIN].gst) {
3562 LOGE("failed to create textbin");
3567 player->pipeline->textbin = textbin;
3570 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3571 LOGD("surface type for subtitle : %d", surface_type);
3572 switch (surface_type) {
3573 case MM_DISPLAY_SURFACE_OVERLAY:
3574 case MM_DISPLAY_SURFACE_NULL:
3575 case MM_DISPLAY_SURFACE_REMOTE:
3576 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3577 LOGE("failed to make plain text elements");
3588 return MM_ERROR_NONE;
3592 LOGD("ERROR : releasing textbin");
3594 g_list_free(element_bucket);
3596 /* release signal */
3597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3599 /* release element which are not added to bin */
3600 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3601 /* NOTE : skip bin */
3602 if (textbin[i].gst) {
3603 GstObject *parent = NULL;
3604 parent = gst_element_get_parent(textbin[i].gst);
3607 gst_object_unref(GST_OBJECT(textbin[i].gst));
3608 textbin[i].gst = NULL;
3610 gst_object_unref(GST_OBJECT(parent));
3615 /* release textbin with it's childs */
3616 if (textbin[MMPLAYER_T_BIN].gst)
3617 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3619 MMPLAYER_FREEIF(player->pipeline->textbin);
3620 player->pipeline->textbin = NULL;
3623 return MM_ERROR_PLAYER_INTERNAL;
3627 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3629 MMPlayerGstElement *mainbin = NULL;
3630 MMPlayerGstElement *textbin = NULL;
3631 MMHandleType attrs = 0;
3632 GstElement *subsrc = NULL;
3633 GstElement *subparse = NULL;
3634 gchar *subtitle_uri = NULL;
3635 const gchar *charset = NULL;
3641 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3643 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3645 mainbin = player->pipeline->mainbin;
3647 attrs = MMPLAYER_GET_ATTRS(player);
3649 LOGE("cannot get content attribute");
3650 return MM_ERROR_PLAYER_INTERNAL;
3653 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3654 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3655 LOGE("subtitle uri is not proper filepath.");
3656 return MM_ERROR_PLAYER_INVALID_URI;
3659 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3660 LOGE("failed to get storage info of subtitle path");
3661 return MM_ERROR_PLAYER_INVALID_URI;
3664 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3666 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3667 player->subtitle_language_list = NULL;
3668 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3670 /* create the subtitle source */
3671 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3673 LOGE("failed to create filesrc element");
3676 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3678 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3679 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3681 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3682 LOGW("failed to add queue");
3683 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3684 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3685 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3690 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3692 LOGE("failed to create subparse element");
3696 charset = util_get_charset(subtitle_uri);
3698 LOGD("detected charset is %s", charset);
3699 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3702 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3703 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3705 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3706 LOGW("failed to add subparse");
3707 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3708 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3709 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3713 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3714 LOGW("failed to link subsrc and subparse");
3718 player->play_subtitle = TRUE;
3719 player->adjust_subtitle_pos = 0;
3721 LOGD("play subtitle using subtitle file");
3723 if (player->pipeline->textbin == NULL) {
3724 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3725 LOGE("failed to create text sink bin. continuing without text");
3729 textbin = player->pipeline->textbin;
3731 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3732 LOGW("failed to add textbin");
3734 /* release signal */
3735 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3737 /* release textbin with it's childs */
3738 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3739 MMPLAYER_FREEIF(player->pipeline->textbin);
3740 player->pipeline->textbin = textbin = NULL;
3744 LOGD("link text input selector and textbin ghost pad");
3746 player->textsink_linked = 1;
3747 player->external_text_idx = 0;
3748 LOGI("textsink is linked");
3750 textbin = player->pipeline->textbin;
3751 LOGD("text bin has been created. reuse it.");
3752 player->external_text_idx = 1;
3755 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3756 LOGW("failed to link subparse and textbin");
3760 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3762 LOGE("failed to get sink pad from textsink to probe data");
3766 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3767 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3769 gst_object_unref(pad);
3772 /* create dot. for debugging */
3773 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3776 return MM_ERROR_NONE;
3779 /* release text pipeline resource */
3780 player->textsink_linked = 0;
3782 /* release signal */
3783 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3785 if (player->pipeline->textbin) {
3786 LOGE("remove textbin");
3788 /* release textbin with it's childs */
3789 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3790 MMPLAYER_FREEIF(player->pipeline->textbin);
3791 player->pipeline->textbin = NULL;
3795 /* release subtitle elem */
3796 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3797 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3799 return MM_ERROR_PLAYER_INTERNAL;
3803 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3805 mm_player_t *player = (mm_player_t *)data;
3806 MMMessageParamType msg = {0, };
3807 GstClockTime duration = 0;
3808 gpointer text = NULL;
3809 guint text_size = 0;
3810 gboolean ret = TRUE;
3811 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3815 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3816 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3818 if (player->is_subtitle_force_drop) {
3819 LOGW("subtitle is dropped forcedly.");
3823 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3824 text = mapinfo.data;
3825 text_size = mapinfo.size;
3827 if (player->set_mode.subtitle_off) {
3828 LOGD("subtitle is OFF.");
3832 if (!text || (text_size == 0)) {
3833 LOGD("There is no subtitle to be displayed.");
3837 msg.data = (void *)text;
3839 duration = GST_BUFFER_DURATION(buffer);
3841 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3842 if (player->duration > GST_BUFFER_PTS(buffer))
3843 duration = player->duration - GST_BUFFER_PTS(buffer);
3846 LOGI("subtitle duration is invalid, subtitle duration change "
3847 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3849 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3851 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3853 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3854 gst_buffer_unmap(buffer, &mapinfo);
3861 static GstPadProbeReturn
3862 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3864 mm_player_t *player = (mm_player_t *)u_data;
3865 GstClockTime cur_timestamp = 0;
3866 gint64 adjusted_timestamp = 0;
3867 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3869 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3871 if (player->set_mode.subtitle_off) {
3872 LOGD("subtitle is OFF.");
3876 if (player->adjust_subtitle_pos == 0) {
3877 LOGD("nothing to do");
3881 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3882 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3884 if (adjusted_timestamp < 0) {
3885 LOGD("adjusted_timestamp under zero");
3890 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3891 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3892 GST_TIME_ARGS(cur_timestamp),
3893 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3895 return GST_PAD_PROBE_OK;
3899 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3903 /* check player and subtitlebin are created */
3904 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3905 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3907 if (position == 0) {
3908 LOGD("nothing to do");
3910 return MM_ERROR_NONE;
3914 case MM_PLAYER_POS_FORMAT_TIME:
3916 /* check current postion */
3917 player->adjust_subtitle_pos = position;
3919 LOGD("save adjust_subtitle_pos in player") ;
3925 LOGW("invalid format.");
3927 return MM_ERROR_INVALID_ARGUMENT;
3933 return MM_ERROR_NONE;
3937 * This function is to create audio or video pipeline for playing.
3939 * @param player [in] handle of player
3941 * @return This function returns zero on success.
3946 __mmplayer_gst_create_pipeline(mm_player_t *player)
3948 int ret = MM_ERROR_NONE;
3949 MMPlayerGstElement *mainbin = NULL;
3950 MMHandleType attrs = 0;
3953 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3955 /* get profile attribute */
3956 attrs = MMPLAYER_GET_ATTRS(player);
3958 LOGE("failed to get content attribute");
3962 /* create pipeline handles */
3963 if (player->pipeline) {
3964 LOGE("pipeline should be released before create new one");
3968 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3969 if (player->pipeline == NULL)
3972 /* create mainbin */
3973 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3974 if (mainbin == NULL)
3977 /* create pipeline */
3978 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3979 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3980 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3981 LOGE("failed to create pipeline");
3986 player->pipeline->mainbin = mainbin;
3988 /* create the source and decoder elements */
3989 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3990 ret = __mmplayer_gst_build_es_pipeline(player);
3992 ret = __mmplayer_gst_build_pipeline(player);
3994 if (ret != MM_ERROR_NONE) {
3995 LOGE("failed to create some elements");
3999 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4000 if (__mmplayer_check_subtitle(player)
4001 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4002 LOGE("failed to create text pipeline");
4005 ret = __mmplayer_gst_add_bus_watch(player);
4006 if (ret != MM_ERROR_NONE) {
4007 LOGE("failed to add bus watch");
4012 return MM_ERROR_NONE;
4015 __mmplayer_gst_destroy_pipeline(player);
4016 return MM_ERROR_PLAYER_INTERNAL;
4020 __mmplayer_reset_gapless_state(mm_player_t *player)
4023 MMPLAYER_RETURN_IF_FAIL(player
4025 && player->pipeline->audiobin
4026 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4028 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4035 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4038 int ret = MM_ERROR_NONE;
4042 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4044 /* cleanup stuffs */
4045 MMPLAYER_FREEIF(player->type);
4046 player->no_more_pad = FALSE;
4047 player->num_dynamic_pad = 0;
4048 player->demux_pad_index = 0;
4050 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4051 player->subtitle_language_list = NULL;
4052 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4054 __mmplayer_reset_gapless_state(player);
4056 if (player->streamer) {
4057 __mm_player_streaming_initialize(player->streamer, FALSE);
4058 __mm_player_streaming_destroy(player->streamer);
4059 player->streamer = NULL;
4062 /* cleanup unlinked mime type */
4063 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4064 MMPLAYER_FREEIF(player->unlinked_video_mime);
4065 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4067 /* cleanup running stuffs */
4068 __mmplayer_cancel_eos_timer(player);
4070 /* cleanup gst stuffs */
4071 if (player->pipeline) {
4072 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4073 GstTagList *tag_list = player->pipeline->tag_list;
4075 /* first we need to disconnect all signal hander */
4076 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4079 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4080 MMPlayerGstElement *videobin = player->pipeline->videobin;
4081 MMPlayerGstElement *textbin = player->pipeline->textbin;
4082 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4083 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4084 gst_object_unref(bus);
4086 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4087 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4088 if (ret != MM_ERROR_NONE) {
4089 LOGE("fail to change state to NULL");
4090 return MM_ERROR_PLAYER_INTERNAL;
4093 LOGW("succeeded in changing state to NULL");
4095 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4098 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4099 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4101 /* free avsysaudiosink
4102 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4103 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4105 MMPLAYER_FREEIF(audiobin);
4106 MMPLAYER_FREEIF(videobin);
4107 MMPLAYER_FREEIF(textbin);
4108 MMPLAYER_FREEIF(mainbin);
4112 gst_tag_list_unref(tag_list);
4114 MMPLAYER_FREEIF(player->pipeline);
4116 MMPLAYER_FREEIF(player->album_art);
4118 if (player->v_stream_caps) {
4119 gst_caps_unref(player->v_stream_caps);
4120 player->v_stream_caps = NULL;
4123 if (player->a_stream_caps) {
4124 gst_caps_unref(player->a_stream_caps);
4125 player->a_stream_caps = NULL;
4128 if (player->s_stream_caps) {
4129 gst_caps_unref(player->s_stream_caps);
4130 player->s_stream_caps = NULL;
4132 __mmplayer_track_destroy(player);
4134 if (player->sink_elements)
4135 g_list_free(player->sink_elements);
4136 player->sink_elements = NULL;
4138 if (player->bufmgr) {
4139 tbm_bufmgr_deinit(player->bufmgr);
4140 player->bufmgr = NULL;
4143 LOGW("finished destroy pipeline");
4151 __mmplayer_gst_realize(mm_player_t *player)
4154 int ret = MM_ERROR_NONE;
4158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4160 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4162 ret = __mmplayer_gst_create_pipeline(player);
4164 LOGE("failed to create pipeline");
4168 /* set pipeline state to READY */
4169 /* NOTE : state change to READY must be performed sync. */
4170 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4171 ret = __mmplayer_gst_set_state(player,
4172 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4174 if (ret != MM_ERROR_NONE) {
4175 /* return error if failed to set state */
4176 LOGE("failed to set READY state");
4180 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4182 /* create dot before error-return. for debugging */
4183 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4191 __mmplayer_gst_unrealize(mm_player_t *player)
4193 int ret = MM_ERROR_NONE;
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4199 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4200 MMPLAYER_PRINT_STATE(player);
4202 /* release miscellaneous information */
4203 __mmplayer_release_misc(player);
4205 /* destroy pipeline */
4206 ret = __mmplayer_gst_destroy_pipeline(player);
4207 if (ret != MM_ERROR_NONE) {
4208 LOGE("failed to destory pipeline");
4212 /* release miscellaneous information.
4213 these info needs to be released after pipeline is destroyed. */
4214 __mmplayer_release_misc_post(player);
4216 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4224 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4229 LOGW("set_message_callback is called with invalid player handle");
4230 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4233 player->msg_cb = callback;
4234 player->msg_cb_param = user_param;
4236 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4240 return MM_ERROR_NONE;
4244 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4246 int ret = MM_ERROR_NONE;
4251 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4252 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4253 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4255 memset(data, 0, sizeof(MMPlayerParseProfile));
4257 if (strstr(uri, "es_buff://")) {
4258 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4259 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4260 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4261 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4263 tmp = g_ascii_strdown(uri, strlen(uri));
4264 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4265 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4267 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4269 } else if (strstr(uri, "mms://")) {
4270 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4271 } else if ((path = strstr(uri, "mem://"))) {
4272 ret = __mmplayer_set_mem_uri(data, path, param);
4274 ret = __mmplayer_set_file_uri(data, uri);
4277 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4278 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4279 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4280 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4282 /* dump parse result */
4283 SECURE_LOGW("incoming uri : %s", uri);
4284 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4285 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4293 __mmplayer_can_do_interrupt(mm_player_t *player)
4295 if (!player || !player->pipeline || !player->attrs) {
4296 LOGW("not initialized");
4300 if (player->audio_stream_render_cb) {
4301 LOGW("not support in pcm extraction mode");
4305 /* check if seeking */
4306 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4307 MMMessageParamType msg_param;
4308 memset(&msg_param, 0, sizeof(MMMessageParamType));
4309 msg_param.code = MM_ERROR_PLAYER_SEEK;
4310 player->seek_state = MMPLAYER_SEEK_NONE;
4311 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4315 /* check other thread */
4316 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4317 LOGW("locked already, cmd state : %d", player->cmd);
4319 /* check application command */
4320 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4321 LOGW("playing.. should wait cmd lock then, will be interrupted");
4323 /* lock will be released at mrp_resource_release_cb() */
4324 MMPLAYER_CMD_LOCK(player);
4327 LOGW("nothing to do");
4330 LOGW("can interrupt immediately");
4334 FAILED: /* with CMD UNLOCKED */
4337 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4342 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4345 mm_player_t *player = NULL;
4349 if (user_data == NULL) {
4350 LOGE("- user_data is null");
4353 player = (mm_player_t *)user_data;
4355 /* do something to release resource here.
4356 * player stop and interrupt forwarding */
4357 if (!__mmplayer_can_do_interrupt(player)) {
4358 LOGW("no need to interrupt, so leave");
4360 MMMessageParamType msg = {0, };
4363 player->interrupted_by_resource = TRUE;
4365 /* get last play position */
4366 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4367 LOGW("failed to get play position.");
4369 msg.union_type = MM_MSG_UNION_TIME;
4370 msg.time.elapsed = pos;
4371 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4373 LOGD("video resource conflict so, resource will be freed by unrealizing");
4374 if (_mmplayer_unrealize((MMHandleType)player))
4375 LOGW("failed to unrealize");
4377 /* lock is called in __mmplayer_can_do_interrupt() */
4378 MMPLAYER_CMD_UNLOCK(player);
4381 if (res == player->video_overlay_resource)
4382 player->video_overlay_resource = FALSE;
4384 player->video_decoder_resource = FALSE;
4392 __mmplayer_initialize_video_roi(mm_player_t *player)
4394 player->video_roi.scale_x = 0.0;
4395 player->video_roi.scale_y = 0.0;
4396 player->video_roi.scale_width = 1.0;
4397 player->video_roi.scale_height = 1.0;
4401 _mmplayer_create_player(MMHandleType handle)
4403 int ret = MM_ERROR_PLAYER_INTERNAL;
4404 bool enabled = false;
4406 mm_player_t *player = MM_PLAYER_CAST(handle);
4410 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4412 /* initialize player state */
4413 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4414 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4415 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4416 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4418 /* check current state */
4419 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4421 /* construct attributes */
4422 player->attrs = _mmplayer_construct_attribute(handle);
4424 if (!player->attrs) {
4425 LOGE("Failed to construct attributes");
4429 /* initialize gstreamer with configured parameter */
4430 if (!__mmplayer_init_gstreamer(player)) {
4431 LOGE("Initializing gstreamer failed");
4432 _mmplayer_deconstruct_attribute(handle);
4436 /* create lock. note that g_tread_init() has already called in gst_init() */
4437 g_mutex_init(&player->fsink_lock);
4439 /* create update tag lock */
4440 g_mutex_init(&player->update_tag_lock);
4442 /* create gapless play mutex */
4443 g_mutex_init(&player->gapless_play_thread_mutex);
4445 /* create gapless play cond */
4446 g_cond_init(&player->gapless_play_thread_cond);
4448 /* create gapless play thread */
4449 player->gapless_play_thread =
4450 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4451 if (!player->gapless_play_thread) {
4452 LOGE("failed to create gapless play thread");
4453 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4454 g_mutex_clear(&player->gapless_play_thread_mutex);
4455 g_cond_clear(&player->gapless_play_thread_cond);
4459 player->bus_msg_q = g_queue_new();
4460 if (!player->bus_msg_q) {
4461 LOGE("failed to create queue for bus_msg");
4462 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4466 ret = _mmplayer_initialize_video_capture(player);
4467 if (ret != MM_ERROR_NONE) {
4468 LOGE("failed to initialize video capture");
4472 /* initialize resource manager */
4473 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4474 __resource_release_cb, player, &player->resource_manager)
4475 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4476 LOGE("failed to initialize resource manager");
4477 ret = MM_ERROR_PLAYER_INTERNAL;
4481 /* create video bo lock and cond */
4482 g_mutex_init(&player->video_bo_mutex);
4483 g_cond_init(&player->video_bo_cond);
4485 /* create media stream callback mutex */
4486 g_mutex_init(&player->media_stream_cb_lock);
4488 /* create subtitle info lock and cond */
4489 g_mutex_init(&player->subtitle_info_mutex);
4490 g_cond_init(&player->subtitle_info_cond);
4492 player->streaming_type = STREAMING_SERVICE_NONE;
4494 /* give default value of audio effect setting */
4495 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4496 player->sound.rg_enable = false;
4497 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4499 player->play_subtitle = FALSE;
4500 player->has_closed_caption = FALSE;
4501 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4502 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4503 player->pending_resume = FALSE;
4504 if (player->ini.dump_element_keyword[0][0] == '\0')
4505 player->ini.set_dump_element_flag = FALSE;
4507 player->ini.set_dump_element_flag = TRUE;
4509 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4510 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4511 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4513 /* Set video360 settings to their defaults for just-created player.
4516 player->is_360_feature_enabled = FALSE;
4517 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4518 LOGI("spherical feature info: %d", enabled);
4520 player->is_360_feature_enabled = TRUE;
4522 LOGE("failed to get spherical feature info");
4525 player->is_content_spherical = FALSE;
4526 player->is_video360_enabled = TRUE;
4527 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4528 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4529 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4530 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4531 player->video360_zoom = 1.0f;
4532 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4533 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4535 __mmplayer_initialize_video_roi(player);
4537 /* set player state to null */
4538 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4539 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4543 return MM_ERROR_NONE;
4547 g_mutex_clear(&player->fsink_lock);
4548 /* free update tag lock */
4549 g_mutex_clear(&player->update_tag_lock);
4550 g_queue_free(player->bus_msg_q);
4551 /* free gapless play thread */
4552 if (player->gapless_play_thread) {
4553 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4554 player->gapless_play_thread_exit = TRUE;
4555 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4556 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4558 g_thread_join(player->gapless_play_thread);
4559 player->gapless_play_thread = NULL;
4561 g_mutex_clear(&player->gapless_play_thread_mutex);
4562 g_cond_clear(&player->gapless_play_thread_cond);
4565 /* release attributes */
4566 _mmplayer_deconstruct_attribute(handle);
4574 __mmplayer_init_gstreamer(mm_player_t *player)
4576 static gboolean initialized = FALSE;
4577 static const int max_argc = 50;
4579 gchar **argv = NULL;
4580 gchar **argv2 = NULL;
4586 LOGD("gstreamer already initialized.");
4591 argc = malloc(sizeof(int));
4592 argv = malloc(sizeof(gchar *) * max_argc);
4593 argv2 = malloc(sizeof(gchar *) * max_argc);
4595 if (!argc || !argv || !argv2)
4598 memset(argv, 0, sizeof(gchar *) * max_argc);
4599 memset(argv2, 0, sizeof(gchar *) * max_argc);
4603 argv[0] = g_strdup("mmplayer");
4606 for (i = 0; i < 5; i++) {
4607 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4608 if (strlen(player->ini.gst_param[i]) > 0) {
4609 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4614 /* we would not do fork for scanning plugins */
4615 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4618 /* check disable registry scan */
4619 if (player->ini.skip_rescan) {
4620 argv[*argc] = g_strdup("--gst-disable-registry-update");
4624 /* check disable segtrap */
4625 if (player->ini.disable_segtrap) {
4626 argv[*argc] = g_strdup("--gst-disable-segtrap");
4630 LOGD("initializing gstreamer with following parameter");
4631 LOGD("argc : %d", *argc);
4634 for (i = 0; i < arg_count; i++) {
4636 LOGD("argv[%d] : %s", i, argv2[i]);
4639 /* initializing gstreamer */
4640 if (!gst_init_check(argc, &argv, &err)) {
4641 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4648 for (i = 0; i < arg_count; i++) {
4649 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4650 MMPLAYER_FREEIF(argv2[i]);
4653 MMPLAYER_FREEIF(argv);
4654 MMPLAYER_FREEIF(argv2);
4655 MMPLAYER_FREEIF(argc);
4665 for (i = 0; i < arg_count; i++) {
4666 LOGD("free[%d] : %s", i, argv2[i]);
4667 MMPLAYER_FREEIF(argv2[i]);
4670 MMPLAYER_FREEIF(argv);
4671 MMPLAYER_FREEIF(argv2);
4672 MMPLAYER_FREEIF(argc);
4678 __mmplayer_check_async_state_transition(mm_player_t *player)
4680 GstState element_state = GST_STATE_VOID_PENDING;
4681 GstState element_pending_state = GST_STATE_VOID_PENDING;
4682 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4683 GstElement *element = NULL;
4684 gboolean async = FALSE;
4686 /* check player handle */
4687 MMPLAYER_RETURN_IF_FAIL(player &&
4689 player->pipeline->mainbin &&
4690 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4693 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4695 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4696 LOGD("don't need to check the pipeline state");
4700 MMPLAYER_PRINT_STATE(player);
4702 /* wait for state transition */
4703 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4704 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4706 if (ret == GST_STATE_CHANGE_FAILURE) {
4707 LOGE(" [%s] state : %s pending : %s",
4708 GST_ELEMENT_NAME(element),
4709 gst_element_state_get_name(element_state),
4710 gst_element_state_get_name(element_pending_state));
4712 /* dump state of all element */
4713 __mmplayer_dump_pipeline_state(player);
4718 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4723 _mmplayer_destroy(MMHandleType handle)
4725 mm_player_t *player = MM_PLAYER_CAST(handle);
4729 /* check player handle */
4730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4732 /* destroy can called at anytime */
4733 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4735 /* check async state transition */
4736 __mmplayer_check_async_state_transition(player);
4738 /* release gapless play thread */
4739 if (player->gapless_play_thread) {
4740 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4741 player->gapless_play_thread_exit = TRUE;
4742 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4743 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4745 LOGD("waitting for gapless play thread exit");
4746 g_thread_join(player->gapless_play_thread);
4747 g_mutex_clear(&player->gapless_play_thread_mutex);
4748 g_cond_clear(&player->gapless_play_thread_cond);
4749 LOGD("gapless play thread released");
4752 _mmplayer_release_video_capture(player);
4754 /* de-initialize resource manager */
4755 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4756 player->resource_manager))
4757 LOGE("failed to deinitialize resource manager");
4759 /* release pipeline */
4760 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4761 LOGE("failed to destory pipeline");
4762 return MM_ERROR_PLAYER_INTERNAL;
4765 g_queue_free(player->bus_msg_q);
4767 /* release subtitle info lock and cond */
4768 g_mutex_clear(&player->subtitle_info_mutex);
4769 g_cond_clear(&player->subtitle_info_cond);
4771 __mmplayer_release_dump_list(player->dump_list);
4773 /* release miscellaneous information */
4774 __mmplayer_release_misc(player);
4776 /* release miscellaneous information.
4777 these info needs to be released after pipeline is destroyed. */
4778 __mmplayer_release_misc_post(player);
4780 /* release attributes */
4781 _mmplayer_deconstruct_attribute(handle);
4784 g_mutex_clear(&player->fsink_lock);
4787 g_mutex_clear(&player->update_tag_lock);
4789 /* release video bo lock and cond */
4790 g_mutex_clear(&player->video_bo_mutex);
4791 g_cond_clear(&player->video_bo_cond);
4793 /* release media stream callback lock */
4794 g_mutex_clear(&player->media_stream_cb_lock);
4798 return MM_ERROR_NONE;
4802 _mmplayer_realize(MMHandleType hplayer)
4804 mm_player_t *player = (mm_player_t *)hplayer;
4807 MMHandleType attrs = 0;
4808 int ret = MM_ERROR_NONE;
4812 /* check player handle */
4813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4815 /* check current state */
4816 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4818 attrs = MMPLAYER_GET_ATTRS(player);
4820 LOGE("fail to get attributes.");
4821 return MM_ERROR_PLAYER_INTERNAL;
4823 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4824 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4826 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4827 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4829 if (ret != MM_ERROR_NONE) {
4830 LOGE("failed to parse profile");
4835 if (uri && (strstr(uri, "es_buff://"))) {
4836 if (strstr(uri, "es_buff://push_mode"))
4837 player->es_player_push_mode = TRUE;
4839 player->es_player_push_mode = FALSE;
4842 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4843 LOGW("mms protocol is not supported format.");
4844 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4847 if (MMPLAYER_IS_STREAMING(player))
4848 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4850 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4852 player->smooth_streaming = FALSE;
4853 player->videodec_linked = 0;
4854 player->audiodec_linked = 0;
4855 player->textsink_linked = 0;
4856 player->is_external_subtitle_present = FALSE;
4857 player->is_external_subtitle_added_now = FALSE;
4858 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4859 player->video360_metadata.is_spherical = -1;
4860 player->is_openal_plugin_used = FALSE;
4861 player->demux_pad_index = 0;
4862 player->subtitle_language_list = NULL;
4863 player->is_subtitle_force_drop = FALSE;
4864 player->last_multiwin_status = FALSE;
4866 __mmplayer_track_initialize(player);
4867 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4869 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4870 gint prebuffer_ms = 0, rebuffer_ms = 0;
4872 player->streamer = __mm_player_streaming_create();
4873 __mm_player_streaming_initialize(player->streamer, TRUE);
4875 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4876 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4878 if (prebuffer_ms > 0) {
4879 prebuffer_ms = MAX(prebuffer_ms, 1000);
4880 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4883 if (rebuffer_ms > 0) {
4884 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4885 rebuffer_ms = MAX(rebuffer_ms, 1000);
4886 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4889 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4890 player->streamer->buffering_req.rebuffer_time);
4893 /* realize pipeline */
4894 ret = __mmplayer_gst_realize(player);
4895 if (ret != MM_ERROR_NONE)
4896 LOGE("fail to realize the player.");
4898 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4906 _mmplayer_unrealize(MMHandleType hplayer)
4908 mm_player_t *player = (mm_player_t *)hplayer;
4909 int ret = MM_ERROR_NONE;
4913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4915 MMPLAYER_CMD_UNLOCK(player);
4916 /* destroy the gst bus msg thread which is created during realize.
4917 this funct have to be called before getting cmd lock. */
4918 __mmplayer_bus_msg_thread_destroy(player);
4919 MMPLAYER_CMD_LOCK(player);
4921 /* check current state */
4922 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4924 /* check async state transition */
4925 __mmplayer_check_async_state_transition(player);
4927 /* unrealize pipeline */
4928 ret = __mmplayer_gst_unrealize(player);
4930 /* set asm stop if success */
4931 if (MM_ERROR_NONE == ret) {
4932 if (!player->interrupted_by_resource) {
4933 if (player->video_decoder_resource != NULL) {
4934 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4935 player->video_decoder_resource);
4936 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4937 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4939 player->video_decoder_resource = NULL;
4942 if (player->video_overlay_resource != NULL) {
4943 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4944 player->video_overlay_resource);
4945 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4946 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4948 player->video_overlay_resource = NULL;
4951 ret = mm_resource_manager_commit(player->resource_manager);
4952 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4953 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4956 LOGE("failed and don't change asm state to stop");
4964 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4966 mm_player_t *player = (mm_player_t *)hplayer;
4968 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4970 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4974 _mmplayer_get_state(MMHandleType hplayer, int *state)
4976 mm_player_t *player = (mm_player_t *)hplayer;
4978 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4980 *state = MMPLAYER_CURRENT_STATE(player);
4982 return MM_ERROR_NONE;
4987 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4989 mm_player_t *player = (mm_player_t *)hplayer;
4990 GstElement *vol_element = NULL;
4995 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4997 LOGD("volume [L]=%f:[R]=%f",
4998 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5000 /* invalid factor range or not */
5001 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5002 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5003 LOGE("Invalid factor!(valid factor:0~1.0)");
5004 return MM_ERROR_INVALID_ARGUMENT;
5008 /* not support to set other value into each channel */
5009 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5010 return MM_ERROR_INVALID_ARGUMENT;
5012 /* Save volume to handle. Currently the first array element will be saved. */
5013 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5015 /* check pipeline handle */
5016 if (!player->pipeline || !player->pipeline->audiobin) {
5017 LOGD("audiobin is not created yet");
5018 LOGD("but, current stored volume will be set when it's created.");
5020 /* NOTE : stored volume will be used in create_audiobin
5021 * returning MM_ERROR_NONE here makes application to able to
5022 * set volume at anytime.
5024 return MM_ERROR_NONE;
5027 /* setting volume to volume element */
5028 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5031 LOGD("volume is set [%f]", player->sound.volume);
5032 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5037 return MM_ERROR_NONE;
5041 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5043 mm_player_t *player = (mm_player_t *)hplayer;
5048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5049 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5051 /* returning stored volume */
5052 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5053 volume->level[i] = player->sound.volume;
5057 return MM_ERROR_NONE;
5061 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5063 mm_player_t *player = (mm_player_t *)hplayer;
5064 GstElement *vol_element = NULL;
5068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5070 /* mute value shoud 0 or 1 */
5071 if (mute != 0 && mute != 1) {
5072 LOGE("bad mute value");
5074 /* FIXIT : definitly, we need _BAD_PARAM error code */
5075 return MM_ERROR_INVALID_ARGUMENT;
5078 player->sound.mute = mute;
5080 /* just hold mute value if pipeline is not ready */
5081 if (!player->pipeline || !player->pipeline->audiobin) {
5082 LOGD("pipeline is not ready. holding mute value");
5083 return MM_ERROR_NONE;
5086 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5088 /* NOTE : volume will only created when the bt is enabled */
5090 LOGD("mute : %d", mute);
5091 g_object_set(vol_element, "mute", mute, NULL);
5093 LOGD("volume elemnet is not created. using volume in audiosink");
5097 return MM_ERROR_NONE;
5101 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5103 mm_player_t *player = (mm_player_t *)hplayer;
5107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5108 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5110 /* just hold mute value if pipeline is not ready */
5111 if (!player->pipeline || !player->pipeline->audiobin) {
5112 LOGD("pipeline is not ready. returning stored value");
5113 *pmute = player->sound.mute;
5114 return MM_ERROR_NONE;
5117 *pmute = player->sound.mute;
5121 return MM_ERROR_NONE;
5125 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5127 mm_player_t *player = (mm_player_t *)hplayer;
5131 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5133 player->video_stream_changed_cb = callback;
5134 player->video_stream_changed_cb_user_param = user_param;
5135 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5139 return MM_ERROR_NONE;
5143 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5145 mm_player_t *player = (mm_player_t *)hplayer;
5149 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5151 player->audio_stream_changed_cb = callback;
5152 player->audio_stream_changed_cb_user_param = user_param;
5153 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5157 return MM_ERROR_NONE;
5161 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5163 mm_player_t *player = (mm_player_t *)hplayer;
5167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 player->audio_stream_render_cb = callback;
5170 player->audio_stream_cb_user_param = user_param;
5171 player->audio_stream_sink_sync = sync;
5172 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5176 return MM_ERROR_NONE;
5180 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5182 mm_player_t *player = (mm_player_t *)hplayer;
5186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5188 if (callback && !player->bufmgr)
5189 player->bufmgr = tbm_bufmgr_init(-1);
5191 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5192 player->video_stream_cb = callback;
5193 player->video_stream_cb_user_param = user_param;
5195 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5199 return MM_ERROR_NONE;
5203 _mmplayer_start(MMHandleType hplayer)
5205 mm_player_t *player = (mm_player_t *)hplayer;
5206 gint ret = MM_ERROR_NONE;
5210 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5212 /* check current state */
5213 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5215 /* start pipeline */
5216 ret = __mmplayer_gst_start(player);
5217 if (ret != MM_ERROR_NONE)
5218 LOGE("failed to start player.");
5220 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5221 LOGD("force playing start even during buffering");
5222 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5230 /* NOTE: post "not supported codec message" to application
5231 * when one codec is not found during AUTOPLUGGING in MSL.
5232 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5233 * And, if any codec is not found, don't send message here.
5234 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5237 __mmplayer_handle_missed_plugin(mm_player_t *player)
5239 MMMessageParamType msg_param;
5240 memset(&msg_param, 0, sizeof(MMMessageParamType));
5241 gboolean post_msg_direct = FALSE;
5245 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5247 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5248 player->not_supported_codec, player->can_support_codec);
5250 if (player->not_found_demuxer) {
5251 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5252 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5254 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5255 MMPLAYER_FREEIF(msg_param.data);
5257 return MM_ERROR_NONE;
5260 if (player->not_supported_codec) {
5261 if (player->can_support_codec) {
5262 // There is one codec to play
5263 post_msg_direct = TRUE;
5265 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5266 post_msg_direct = TRUE;
5269 if (post_msg_direct) {
5270 MMMessageParamType msg_param;
5271 memset(&msg_param, 0, sizeof(MMMessageParamType));
5273 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5274 LOGW("not found AUDIO codec, posting error code to application.");
5276 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5277 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5278 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5279 LOGW("not found VIDEO codec, posting error code to application.");
5281 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5282 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5285 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5287 MMPLAYER_FREEIF(msg_param.data);
5289 return MM_ERROR_NONE;
5291 // no any supported codec case
5292 LOGW("not found any codec, posting error code to application.");
5294 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5295 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5296 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5298 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5299 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5302 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5304 MMPLAYER_FREEIF(msg_param.data);
5310 return MM_ERROR_NONE;
5314 __mmplayer_check_pipeline(mm_player_t *player)
5316 GstState element_state = GST_STATE_VOID_PENDING;
5317 GstState element_pending_state = GST_STATE_VOID_PENDING;
5319 int ret = MM_ERROR_NONE;
5321 if (!player->gapless.reconfigure)
5324 LOGW("pipeline is under construction.");
5326 MMPLAYER_PLAYBACK_LOCK(player);
5327 MMPLAYER_PLAYBACK_UNLOCK(player);
5329 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5331 /* wait for state transition */
5332 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5333 if (ret == GST_STATE_CHANGE_FAILURE)
5334 LOGE("failed to change pipeline state within %d sec", timeout);
5337 /* NOTE : it should be able to call 'stop' anytime*/
5339 _mmplayer_stop(MMHandleType hplayer)
5341 mm_player_t *player = (mm_player_t *)hplayer;
5342 int ret = MM_ERROR_NONE;
5346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5348 /* check current state */
5349 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5351 /* check pipline building state */
5352 __mmplayer_check_pipeline(player);
5353 __mmplayer_reset_gapless_state(player);
5355 /* NOTE : application should not wait for EOS after calling STOP */
5356 __mmplayer_cancel_eos_timer(player);
5359 player->seek_state = MMPLAYER_SEEK_NONE;
5362 ret = __mmplayer_gst_stop(player);
5364 if (ret != MM_ERROR_NONE)
5365 LOGE("failed to stop player.");
5373 _mmplayer_pause(MMHandleType hplayer)
5375 mm_player_t *player = (mm_player_t *)hplayer;
5376 gint64 pos_nsec = 0;
5377 gboolean async = FALSE;
5378 gint ret = MM_ERROR_NONE;
5382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5384 /* check current state */
5385 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5387 /* check pipline building state */
5388 __mmplayer_check_pipeline(player);
5390 switch (MMPLAYER_CURRENT_STATE(player)) {
5391 case MM_PLAYER_STATE_READY:
5393 /* check prepare async or not.
5394 * In the case of streaming playback, it's recommned to avoid blocking wait.
5396 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5397 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5399 /* Changing back sync of rtspsrc to async */
5400 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5401 LOGD("async prepare working mode for rtsp");
5407 case MM_PLAYER_STATE_PLAYING:
5409 /* NOTE : store current point to overcome some bad operation
5410 *(returning zero when getting current position in paused state) of some
5413 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5414 LOGW("getting current position failed in paused");
5416 player->last_position = pos_nsec;
5418 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5419 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5420 This causes problem is position calculation during normal pause resume scenarios also.
5421 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5422 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5423 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5424 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5430 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5431 LOGD("doing async pause in case of ms buff src");
5435 /* pause pipeline */
5436 ret = __mmplayer_gst_pause(player, async);
5438 if (ret != MM_ERROR_NONE)
5439 LOGE("failed to pause player. ret : 0x%x", ret);
5441 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5442 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5443 LOGE("failed to update display_rotation");
5451 /* in case of streaming, pause could take long time.*/
5453 _mmplayer_abort_pause(MMHandleType hplayer)
5455 mm_player_t *player = (mm_player_t *)hplayer;
5456 int ret = MM_ERROR_NONE;
5460 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5462 player->pipeline->mainbin,
5463 MM_ERROR_PLAYER_NOT_INITIALIZED);
5465 LOGD("set the pipeline state to READY");
5467 /* set state to READY */
5468 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5469 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5470 if (ret != MM_ERROR_NONE) {
5471 LOGE("fail to change state to READY");
5472 return MM_ERROR_PLAYER_INTERNAL;
5475 LOGD("succeeded in changing state to READY");
5480 _mmplayer_resume(MMHandleType hplayer)
5482 mm_player_t *player = (mm_player_t *)hplayer;
5483 int ret = MM_ERROR_NONE;
5484 gboolean async = FALSE;
5488 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5490 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5491 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5492 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5496 /* Changing back sync mode rtspsrc to async */
5497 LOGD("async resume for rtsp case");
5501 /* check current state */
5502 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5504 ret = __mmplayer_gst_resume(player, async);
5505 if (ret != MM_ERROR_NONE)
5506 LOGE("failed to resume player.");
5508 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5509 LOGD("force resume even during buffering");
5510 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5519 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5521 mm_player_t *player = (mm_player_t *)hplayer;
5522 gint64 pos_nsec = 0;
5523 int ret = MM_ERROR_NONE;
5525 signed long long start = 0, stop = 0;
5526 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5529 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5530 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5532 /* The sound of video is not supported under 0.0 and over 2.0. */
5533 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5534 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5537 _mmplayer_set_mute(hplayer, mute);
5539 if (player->playback_rate == rate)
5540 return MM_ERROR_NONE;
5542 /* If the position is reached at start potion during fast backward, EOS is posted.
5543 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5545 player->playback_rate = rate;
5547 current_state = MMPLAYER_CURRENT_STATE(player);
5549 if (current_state != MM_PLAYER_STATE_PAUSED)
5550 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5552 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5554 if ((current_state == MM_PLAYER_STATE_PAUSED)
5555 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5556 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5557 pos_nsec = player->last_position;
5562 stop = GST_CLOCK_TIME_NONE;
5564 start = GST_CLOCK_TIME_NONE;
5568 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5569 player->playback_rate,
5571 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5572 GST_SEEK_TYPE_SET, start,
5573 GST_SEEK_TYPE_SET, stop)) {
5574 LOGE("failed to set speed playback");
5575 return MM_ERROR_PLAYER_SEEK;
5578 LOGD("succeeded to set speed playback as %0.1f", rate);
5582 return MM_ERROR_NONE;;
5586 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5588 mm_player_t *player = (mm_player_t *)hplayer;
5589 int ret = MM_ERROR_NONE;
5593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5595 /* check pipline building state */
5596 __mmplayer_check_pipeline(player);
5598 ret = __mmplayer_gst_set_position(player, position, FALSE);
5606 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5608 mm_player_t *player = (mm_player_t *)hplayer;
5609 int ret = MM_ERROR_NONE;
5611 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5613 ret = __mmplayer_gst_get_position(player, position);
5619 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5621 mm_player_t *player = (mm_player_t *)hplayer;
5622 int ret = MM_ERROR_NONE;
5624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5625 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5627 if (g_strrstr(player->type, "video/mpegts"))
5628 __mmplayer_update_duration_value(player);
5630 *duration = player->duration;
5635 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5637 mm_player_t *player = (mm_player_t *)hplayer;
5638 int ret = MM_ERROR_NONE;
5640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5642 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5648 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5650 mm_player_t *player = (mm_player_t *)hplayer;
5651 int ret = MM_ERROR_NONE;
5655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5657 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5665 __mmplayer_is_midi_type(gchar *str_caps)
5667 if ((g_strrstr(str_caps, "audio/midi")) ||
5668 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5669 (g_strrstr(str_caps, "application/x-smaf")) ||
5670 (g_strrstr(str_caps, "audio/x-imelody")) ||
5671 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5672 (g_strrstr(str_caps, "audio/xmf")) ||
5673 (g_strrstr(str_caps, "audio/mxmf"))) {
5682 __mmplayer_is_only_mp3_type(gchar *str_caps)
5684 if (g_strrstr(str_caps, "application/x-id3") ||
5685 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5691 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5693 GstStructure *caps_structure = NULL;
5694 gint samplerate = 0;
5698 MMPLAYER_RETURN_IF_FAIL(player && caps);
5700 caps_structure = gst_caps_get_structure(caps, 0);
5702 /* set stream information */
5703 gst_structure_get_int(caps_structure, "rate", &samplerate);
5704 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5706 gst_structure_get_int(caps_structure, "channels", &channels);
5707 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5709 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5713 __mmplayer_update_content_type_info(mm_player_t *player)
5716 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5718 if (__mmplayer_is_midi_type(player->type)) {
5719 player->bypass_audio_effect = TRUE;
5723 if (!player->streamer) {
5724 LOGD("no need to check streaming type");
5728 if (g_strrstr(player->type, "application/x-hls")) {
5729 /* If it can't know exact type when it parses uri because of redirection case,
5730 * it will be fixed by typefinder or when doing autoplugging.
5732 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5733 player->streamer->is_adaptive_streaming = TRUE;
5734 } else if (g_strrstr(player->type, "application/dash+xml")) {
5735 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5736 player->streamer->is_adaptive_streaming = TRUE;
5739 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5740 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5741 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5743 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5744 if (player->streamer->is_adaptive_streaming)
5745 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5747 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5751 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5756 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5757 GstCaps *caps, gpointer data)
5759 mm_player_t *player = (mm_player_t *)data;
5764 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5766 /* store type string */
5767 MMPLAYER_FREEIF(player->type);
5768 player->type = gst_caps_to_string(caps);
5770 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5771 player, player->type, probability, gst_caps_get_size(caps));
5773 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5774 (g_strrstr(player->type, "audio/x-raw-int"))) {
5775 LOGE("not support media format");
5777 if (player->msg_posted == FALSE) {
5778 MMMessageParamType msg_param;
5779 memset(&msg_param, 0, sizeof(MMMessageParamType));
5781 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5782 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5784 /* don't post more if one was sent already */
5785 player->msg_posted = TRUE;
5790 __mmplayer_update_content_type_info(player);
5792 pad = gst_element_get_static_pad(tf, "src");
5794 LOGE("fail to get typefind src pad.");
5798 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5799 gboolean async = FALSE;
5800 LOGE("failed to autoplug %s", player->type);
5802 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5804 if (async && player->msg_posted == FALSE)
5805 __mmplayer_handle_missed_plugin(player);
5809 gst_object_unref(GST_OBJECT(pad));
5817 __mmplayer_gst_make_decodebin(mm_player_t *player)
5819 GstElement *decodebin = NULL;
5823 /* create decodebin */
5824 decodebin = gst_element_factory_make("decodebin", NULL);
5827 LOGE("fail to create decodebin");
5831 /* raw pad handling signal */
5832 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5833 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5835 /* no-more-pad pad handling signal */
5836 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5837 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5839 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5840 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5842 /* This signal is emitted when a pad for which there is no further possible
5843 decoding is added to the decodebin.*/
5844 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5845 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5847 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5848 before looking for any elements that can handle that stream.*/
5849 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5850 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5852 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5853 before looking for any elements that can handle that stream.*/
5854 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5855 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5857 /* This signal is emitted once decodebin has finished decoding all the data.*/
5858 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5859 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5861 /* This signal is emitted when a element is added to the bin.*/
5862 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5863 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5870 __mmplayer_gst_make_queue2(mm_player_t *player)
5872 GstElement *queue2 = NULL;
5873 gint64 dur_bytes = 0L;
5874 MMPlayerGstElement *mainbin = NULL;
5875 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5878 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5880 mainbin = player->pipeline->mainbin;
5882 queue2 = gst_element_factory_make("queue2", "queue2");
5884 LOGE("failed to create buffering queue element");
5888 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5889 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5891 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5893 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5894 * skip the pull mode(file or ring buffering) setting. */
5895 if (dur_bytes > 0) {
5896 if (!g_strrstr(player->type, "video/mpegts")) {
5897 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5898 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5904 __mm_player_streaming_set_queue2(player->streamer,
5908 (guint64)dur_bytes); /* no meaning at the moment */
5914 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5916 MMPlayerGstElement *mainbin = NULL;
5917 GstElement *decodebin = NULL;
5918 GstElement *queue2 = NULL;
5919 GstPad *sinkpad = NULL;
5920 GstPad *qsrcpad = NULL;
5923 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5925 mainbin = player->pipeline->mainbin;
5927 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5929 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5930 LOGW("need to check: muxed buffer is not null");
5933 queue2 = __mmplayer_gst_make_queue2(player);
5935 LOGE("failed to make queue2");
5939 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5940 LOGE("failed to add buffering queue");
5944 sinkpad = gst_element_get_static_pad(queue2, "sink");
5945 qsrcpad = gst_element_get_static_pad(queue2, "src");
5947 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5948 LOGE("failed to link [%s:%s]-[%s:%s]",
5949 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5953 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5954 LOGE("failed to sync queue2 state with parent");
5958 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5959 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5963 gst_object_unref(GST_OBJECT(sinkpad));
5967 /* create decodebin */
5968 decodebin = __mmplayer_gst_make_decodebin(player);
5970 LOGE("failed to make decodebin");
5974 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5975 LOGE("failed to add decodebin");
5979 /* to force caps on the decodebin element and avoid reparsing stuff by
5980 * typefind. It also avoids a deadlock in the way typefind activates pads in
5981 * the state change */
5982 g_object_set(decodebin, "sink-caps", caps, NULL);
5984 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5986 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5987 LOGE("failed to link [%s:%s]-[%s:%s]",
5988 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5992 gst_object_unref(GST_OBJECT(sinkpad));
5994 gst_object_unref(GST_OBJECT(qsrcpad));
5997 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5998 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6000 /* set decodebin property about buffer in streaming playback. *
6001 * in case of HLS/DASH, it does not need to have big buffer *
6002 * because it is kind of adaptive streaming. */
6003 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6004 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6005 gint high_percent = 0;
6007 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6008 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6010 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6012 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6014 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6015 "high-percent", high_percent,
6016 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6017 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6018 "max-size-buffers", 0, NULL); // disable or automatic
6021 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6022 LOGE("failed to sync decodebin state with parent");
6033 gst_object_unref(GST_OBJECT(sinkpad));
6036 gst_object_unref(GST_OBJECT(qsrcpad));
6039 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6040 * You need to explicitly set elements to the NULL state before
6041 * dropping the final reference, to allow them to clean up.
6043 gst_element_set_state(queue2, GST_STATE_NULL);
6045 /* And, it still has a parent "player".
6046 * You need to let the parent manage the object instead of unreffing the object directly.
6048 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6049 gst_object_unref(queue2);
6054 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6055 * You need to explicitly set elements to the NULL state before
6056 * dropping the final reference, to allow them to clean up.
6058 gst_element_set_state(decodebin, GST_STATE_NULL);
6060 /* And, it still has a parent "player".
6061 * You need to let the parent manage the object instead of unreffing the object directly.
6064 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6065 gst_object_unref(decodebin);
6073 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6077 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6078 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6080 LOGD("class : %s, mime : %s", factory_class, mime);
6082 /* add missing plugin */
6083 /* NOTE : msl should check missing plugin for image mime type.
6084 * Some motion jpeg clips can have playable audio track.
6085 * So, msl have to play audio after displaying popup written video format not supported.
6087 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6088 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6089 LOGD("not found demuxer");
6090 player->not_found_demuxer = TRUE;
6091 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6097 if (!g_strrstr(factory_class, "Demuxer")) {
6098 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6099 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6100 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6102 /* check that clip have multi tracks or not */
6103 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6104 LOGD("video plugin is already linked");
6106 LOGW("add VIDEO to missing plugin");
6107 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6108 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6110 } else if (g_str_has_prefix(mime, "audio")) {
6111 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6112 LOGD("audio plugin is already linked");
6114 LOGW("add AUDIO to missing plugin");
6115 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6116 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6124 return MM_ERROR_NONE;
6128 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6130 mm_player_t *player = (mm_player_t *)data;
6134 MMPLAYER_RETURN_IF_FAIL(player);
6136 /* remove fakesink. */
6137 if (!__mmplayer_gst_remove_fakesink(player,
6138 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6139 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6140 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6141 * source element are not same. To overcome this situation, this function will called
6142 * several places and several times. Therefore, this is not an error case.
6147 LOGD("[handle: %p] pipeline has completely constructed", player);
6149 if ((player->ini.async_start) &&
6150 (player->msg_posted == FALSE) &&
6151 (player->cmd >= MMPLAYER_COMMAND_START))
6152 __mmplayer_handle_missed_plugin(player);
6154 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6158 __mmplayer_check_profile(void)
6161 static int profile_tv = -1;
6163 if (__builtin_expect(profile_tv != -1, 1))
6166 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6167 switch (*profileName) {
6182 __mmplayer_get_next_uri(mm_player_t *player)
6184 MMPlayerParseProfile profile;
6186 guint num_of_list = 0;
6189 num_of_list = g_list_length(player->uri_info.uri_list);
6190 uri_idx = player->uri_info.uri_idx;
6192 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6193 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6194 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6196 LOGW("next uri does not exist");
6200 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6201 LOGE("failed to parse profile");
6205 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6206 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6207 LOGW("uri type is not supported(%d)", profile.uri_type);
6211 LOGD("success to find next uri %d", uri_idx);
6215 if (uri_idx == num_of_list) {
6216 LOGE("failed to find next uri");
6220 player->uri_info.uri_idx = uri_idx;
6221 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6223 if (mm_attrs_commit_all(player->attrs)) {
6224 LOGE("failed to commit");
6228 SECURE_LOGD("next playback uri: %s", uri);
6233 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6235 #define REPEAT_COUNT_INFINITELY -1
6236 #define REPEAT_COUNT_MIN 2
6238 MMHandleType attrs = 0;
6242 guint num_of_list = 0;
6243 int profile_tv = -1;
6247 LOGD("checking for gapless play option");
6249 if (player->pipeline->textbin) {
6250 LOGE("subtitle path is enabled. gapless play is not supported.");
6254 attrs = MMPLAYER_GET_ATTRS(player);
6256 LOGE("fail to get attributes.");
6260 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6262 /* gapless playback is not supported in case of video at TV profile. */
6263 profile_tv = __mmplayer_check_profile();
6264 if (profile_tv && video) {
6265 LOGW("not support video gapless playback");
6269 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6270 LOGE("failed to get play count");
6272 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6273 LOGE("failed to get gapless mode");
6275 /* check repeat count in case of audio */
6277 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6278 LOGW("gapless is disabled");
6282 num_of_list = g_list_length(player->uri_info.uri_list);
6284 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6286 if (num_of_list == 0) {
6287 /* audio looping path */
6288 if (count >= REPEAT_COUNT_MIN) {
6289 /* decrease play count */
6290 /* we succeeded to rewind. update play count and then wait for next EOS */
6292 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6293 /* commit attribute */
6294 if (mm_attrs_commit_all(attrs))
6295 LOGE("failed to commit attribute");
6297 } else if (count != REPEAT_COUNT_INFINITELY) {
6298 LOGD("there is no next uri and no repeat");
6301 LOGD("looping cnt %d", count);
6303 /* gapless playback path */
6304 if (!__mmplayer_get_next_uri(player)) {
6305 LOGE("failed to get next uri");
6312 LOGE("unable to play gapless path. EOS will be posted soon");
6317 __mmplayer_initialize_gapless_play(mm_player_t *player)
6323 player->smooth_streaming = FALSE;
6324 player->videodec_linked = 0;
6325 player->audiodec_linked = 0;
6326 player->textsink_linked = 0;
6327 player->is_external_subtitle_present = FALSE;
6328 player->is_external_subtitle_added_now = FALSE;
6329 player->not_supported_codec = MISSING_PLUGIN_NONE;
6330 player->can_support_codec = FOUND_PLUGIN_NONE;
6331 player->pending_seek.is_pending = false;
6332 player->pending_seek.pos = 0;
6333 player->msg_posted = FALSE;
6334 player->has_many_types = FALSE;
6335 player->no_more_pad = FALSE;
6336 player->not_found_demuxer = 0;
6337 player->seek_state = MMPLAYER_SEEK_NONE;
6338 player->is_subtitle_force_drop = FALSE;
6339 player->play_subtitle = FALSE;
6340 player->adjust_subtitle_pos = 0;
6342 player->total_bitrate = 0;
6343 player->total_maximum_bitrate = 0;
6345 __mmplayer_track_initialize(player);
6346 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6348 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6349 player->bitrate[i] = 0;
6350 player->maximum_bitrate[i] = 0;
6353 if (player->v_stream_caps) {
6354 gst_caps_unref(player->v_stream_caps);
6355 player->v_stream_caps = NULL;
6358 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6360 /* clean found parsers */
6361 if (player->parsers) {
6362 GList *parsers = player->parsers;
6363 for (; parsers; parsers = g_list_next(parsers)) {
6364 gchar *name = parsers->data;
6365 MMPLAYER_FREEIF(name);
6367 g_list_free(player->parsers);
6368 player->parsers = NULL;
6371 /* clean found audio decoders */
6372 if (player->audio_decoders) {
6373 GList *a_dec = player->audio_decoders;
6374 for (; a_dec; a_dec = g_list_next(a_dec)) {
6375 gchar *name = a_dec->data;
6376 MMPLAYER_FREEIF(name);
6378 g_list_free(player->audio_decoders);
6379 player->audio_decoders = NULL;
6386 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6388 MMPlayerGstElement *mainbin = NULL;
6389 MMMessageParamType msg_param = {0,};
6390 GstElement *element = NULL;
6391 MMHandleType attrs = 0;
6393 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6397 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6398 LOGE("player is not initialized");
6402 mainbin = player->pipeline->mainbin;
6403 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6405 attrs = MMPLAYER_GET_ATTRS(player);
6407 LOGE("fail to get attributes");
6411 /* Initialize Player values */
6412 __mmplayer_initialize_gapless_play(player);
6414 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6416 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6417 LOGE("failed to parse profile");
6418 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6422 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6423 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6424 LOGE("dash or hls is not supportable");
6425 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6429 element = __mmplayer_gst_create_source(player);
6431 LOGE("no source element was created");
6435 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6436 LOGE("failed to add source element to pipeline");
6437 gst_object_unref(GST_OBJECT(element));
6442 /* take source element */
6443 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6444 mainbin[MMPLAYER_M_SRC].gst = element;
6448 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6449 if (player->streamer == NULL) {
6450 player->streamer = __mm_player_streaming_create();
6451 __mm_player_streaming_initialize(player->streamer, TRUE);
6454 elem_idx = MMPLAYER_M_TYPEFIND;
6455 element = gst_element_factory_make("typefind", "typefinder");
6456 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6457 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6459 elem_idx = MMPLAYER_M_AUTOPLUG;
6460 element = __mmplayer_gst_make_decodebin(player);
6463 /* check autoplug element is OK */
6465 LOGE("can not create element(%d)", elem_idx);
6469 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6470 LOGE("failed to add sinkbin to pipeline");
6471 gst_object_unref(GST_OBJECT(element));
6476 mainbin[elem_idx].id = elem_idx;
6477 mainbin[elem_idx].gst = element;
6479 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6480 LOGE("Failed to link src - autoplug(or typefind)");
6484 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6485 LOGE("Failed to change state of src element");
6489 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6490 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6491 LOGE("Failed to change state of decodebin");
6495 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6496 LOGE("Failed to change state of src element");
6501 player->gapless.stream_changed = TRUE;
6502 player->gapless.running = TRUE;
6508 MMPLAYER_PLAYBACK_UNLOCK(player);
6510 if (!player->msg_posted) {
6511 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6512 player->msg_posted = TRUE;
6519 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6521 mm_player_selector_t *selector = &player->selector[type];
6522 MMPlayerGstElement *sinkbin = NULL;
6523 enum MainElementID selectorId = MMPLAYER_M_NUM;
6524 enum MainElementID sinkId = MMPLAYER_M_NUM;
6525 GstPad *srcpad = NULL;
6526 GstPad *sinkpad = NULL;
6527 gboolean send_notice = FALSE;
6530 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6532 LOGD("type %d", type);
6535 case MM_PLAYER_TRACK_TYPE_AUDIO:
6536 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6537 sinkId = MMPLAYER_A_BIN;
6538 sinkbin = player->pipeline->audiobin;
6540 case MM_PLAYER_TRACK_TYPE_VIDEO:
6541 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6542 sinkId = MMPLAYER_V_BIN;
6543 sinkbin = player->pipeline->videobin;
6546 case MM_PLAYER_TRACK_TYPE_TEXT:
6547 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6548 sinkId = MMPLAYER_T_BIN;
6549 sinkbin = player->pipeline->textbin;
6552 LOGE("requested type is not supportable");
6557 if (player->pipeline->mainbin[selectorId].gst) {
6560 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6562 if (selector->event_probe_id != 0)
6563 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6564 selector->event_probe_id = 0;
6566 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6567 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6569 if (srcpad && sinkpad) {
6570 /* after getting drained signal there is no data flows, so no need to do pad_block */
6571 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6572 gst_pad_unlink(srcpad, sinkpad);
6574 /* send custom event to sink pad to handle it at video sink */
6576 LOGD("send custom event to sinkpad");
6577 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6578 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6579 gst_pad_send_event(sinkpad, event);
6583 gst_object_unref(sinkpad);
6586 gst_object_unref(srcpad);
6589 LOGD("selector release");
6591 /* release and unref requests pad from the selector */
6592 for (n = 0; n < selector->channels->len; n++) {
6593 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6594 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6596 g_ptr_array_set_size(selector->channels, 0);
6598 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6599 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6601 player->pipeline->mainbin[selectorId].gst = NULL;
6609 __mmplayer_deactivate_old_path(mm_player_t *player)
6612 MMPLAYER_RETURN_IF_FAIL(player);
6614 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6615 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6616 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6617 LOGE("deactivate selector error");
6621 __mmplayer_track_destroy(player);
6622 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6624 if (player->streamer) {
6625 __mm_player_streaming_initialize(player->streamer, FALSE);
6626 __mm_player_streaming_destroy(player->streamer);
6627 player->streamer = NULL;
6630 MMPLAYER_PLAYBACK_LOCK(player);
6631 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6638 if (!player->msg_posted) {
6639 MMMessageParamType msg = {0,};
6642 msg.code = MM_ERROR_PLAYER_INTERNAL;
6643 LOGE("gapless_uri_play> deactivate error");
6645 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6646 player->msg_posted = TRUE;
6652 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6654 int result = MM_ERROR_NONE;
6655 mm_player_t *player = (mm_player_t *)hplayer;
6658 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6660 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6661 if (mm_attrs_commit_all(player->attrs)) {
6662 LOGE("failed to commit the original uri.");
6663 result = MM_ERROR_PLAYER_INTERNAL;
6665 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6666 LOGE("failed to add the original uri in the uri list.");
6674 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6676 mm_player_t *player = (mm_player_t *)hplayer;
6677 guint num_of_list = 0;
6681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6682 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6684 if (player->pipeline && player->pipeline->textbin) {
6685 LOGE("subtitle path is enabled.");
6686 return MM_ERROR_PLAYER_INVALID_STATE;
6689 num_of_list = g_list_length(player->uri_info.uri_list);
6691 if (is_first_path) {
6692 if (num_of_list == 0) {
6693 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6694 LOGD("add original path : %s", uri);
6696 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6697 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6699 LOGD("change original path : %s", uri);
6702 MMHandleType attrs = 0;
6703 attrs = MMPLAYER_GET_ATTRS(player);
6705 if (num_of_list == 0) {
6706 char *original_uri = NULL;
6709 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6711 if (!original_uri) {
6712 LOGE("there is no original uri.");
6713 return MM_ERROR_PLAYER_INVALID_STATE;
6716 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6717 player->uri_info.uri_idx = 0;
6719 LOGD("add original path at first : %s", original_uri);
6723 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6724 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6728 return MM_ERROR_NONE;
6732 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6734 mm_player_t *player = (mm_player_t *)hplayer;
6735 char *next_uri = NULL;
6736 guint num_of_list = 0;
6739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6741 num_of_list = g_list_length(player->uri_info.uri_list);
6743 if (num_of_list > 0) {
6744 gint uri_idx = player->uri_info.uri_idx;
6746 if (uri_idx < num_of_list-1)
6751 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6752 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6754 *uri = g_strdup(next_uri);
6758 return MM_ERROR_NONE;
6762 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6763 GstCaps *caps, gpointer data)
6765 mm_player_t *player = (mm_player_t *)data;
6766 const gchar *klass = NULL;
6767 const gchar *mime = NULL;
6768 gchar *caps_str = NULL;
6770 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6771 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6772 caps_str = gst_caps_to_string(caps);
6774 LOGW("unknown type of caps : %s from %s",
6775 caps_str, GST_ELEMENT_NAME(elem));
6777 MMPLAYER_FREEIF(caps_str);
6779 /* There is no available codec. */
6780 __mmplayer_check_not_supported_codec(player, klass, mime);
6784 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6785 GstCaps *caps, gpointer data)
6787 mm_player_t *player = (mm_player_t *)data;
6788 const char *mime = NULL;
6789 gboolean ret = TRUE;
6791 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6792 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6794 if (g_str_has_prefix(mime, "audio")) {
6795 GstStructure *caps_structure = NULL;
6796 gint samplerate = 0;
6798 gchar *caps_str = NULL;
6800 caps_structure = gst_caps_get_structure(caps, 0);
6801 gst_structure_get_int(caps_structure, "rate", &samplerate);
6802 gst_structure_get_int(caps_structure, "channels", &channels);
6804 if ((channels > 0 && samplerate == 0)) {
6805 LOGD("exclude audio...");
6809 caps_str = gst_caps_to_string(caps);
6810 /* set it directly because not sent by TAG */
6811 if (g_strrstr(caps_str, "mobile-xmf"))
6812 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6813 MMPLAYER_FREEIF(caps_str);
6814 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6815 MMMessageParamType msg_param;
6816 memset(&msg_param, 0, sizeof(MMMessageParamType));
6817 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6818 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6819 LOGD("video file is not supported on this device");
6821 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6822 LOGD("already video linked");
6825 LOGD("found new stream");
6832 __mmplayer_check_offload_path(mm_player_t *player)
6834 gboolean ret = FALSE;
6835 GstElementFactory *factory = NULL;
6838 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6840 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6841 /* FIXME : 1. need to consider the current audio output path and
6842 player have to know whether it support offload or not.
6843 2. could be added new condition about content length */
6844 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6845 if (!__mmplayer_is_only_mp3_type(player->type))
6848 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6852 LOGD("can setup the audio offload path");
6853 gst_object_unref(factory);
6862 static GstAutoplugSelectResult
6863 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6865 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6867 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6868 int audio_offload = 0;
6870 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6871 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6873 if (audio_offload && __mmplayer_check_offload_path(player)) {
6874 LOGD("expose audio path to build offload path");
6875 player->build_audio_offload = TRUE;
6876 /* update codec info */
6877 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6878 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6879 player->audiodec_linked = 1;
6881 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6885 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6887 LOGD("audio codec type: %d", codec_type);
6888 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6889 /* sw codec will be skipped */
6890 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6891 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6892 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6893 ret = GST_AUTOPLUG_SELECT_SKIP;
6897 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6898 /* hw codec will be skipped */
6899 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6900 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6901 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6902 ret = GST_AUTOPLUG_SELECT_SKIP;
6907 /* set stream information */
6908 if (!player->audiodec_linked)
6909 __mmplayer_set_audio_attrs(player, caps);
6911 /* update codec info */
6912 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6913 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6914 player->audiodec_linked = 1;
6916 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6918 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6920 LOGD("video codec type: %d", codec_type);
6921 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6922 /* sw codec is skipped */
6923 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6924 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6925 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6926 ret = GST_AUTOPLUG_SELECT_SKIP;
6930 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6931 /* hw codec is skipped */
6932 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6933 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6934 ret = GST_AUTOPLUG_SELECT_SKIP;
6939 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6940 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6942 /* mark video decoder for acquire */
6943 if (player->video_decoder_resource == NULL) {
6944 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6945 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6946 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6947 &player->video_decoder_resource)
6948 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6949 LOGE("could not mark video_decoder resource for acquire");
6950 ret = GST_AUTOPLUG_SELECT_SKIP;
6954 LOGW("video decoder resource is already acquired, skip it.");
6955 ret = GST_AUTOPLUG_SELECT_SKIP;
6959 player->interrupted_by_resource = FALSE;
6960 /* acquire resources for video playing */
6961 if (mm_resource_manager_commit(player->resource_manager)
6962 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6963 LOGE("could not acquire resources for video decoding");
6964 ret = GST_AUTOPLUG_SELECT_SKIP;
6969 /* update codec info */
6970 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6971 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6972 player->videodec_linked = 1;
6980 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6981 GstCaps *caps, GstElementFactory *factory, gpointer data)
6983 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6984 mm_player_t *player = (mm_player_t *)data;
6986 gchar *factory_name = NULL;
6987 gchar *caps_str = NULL;
6988 const gchar *klass = NULL;
6991 factory_name = GST_OBJECT_NAME(factory);
6992 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6993 caps_str = gst_caps_to_string(caps);
6995 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6997 /* store type string */
6998 if (player->type == NULL) {
6999 player->type = gst_caps_to_string(caps);
7000 __mmplayer_update_content_type_info(player);
7003 /* filtering exclude keyword */
7004 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7005 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7006 LOGW("skipping [%s] by exculde keyword [%s]",
7007 factory_name, player->ini.exclude_element_keyword[idx]);
7009 result = GST_AUTOPLUG_SELECT_SKIP;
7014 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7015 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7016 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7017 factory_name, player->ini.unsupported_codec_keyword[idx]);
7018 result = GST_AUTOPLUG_SELECT_SKIP;
7023 /* exclude webm format */
7024 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7025 * because webm format is not supportable.
7026 * If webm is disabled in "autoplug-continue", there is no state change
7027 * failure or error because the decodebin will expose the pad directly.
7028 * It make MSL invoke _prepare_async_callback.
7029 * So, we need to disable webm format in "autoplug-select" */
7030 if (caps_str && strstr(caps_str, "webm")) {
7031 LOGW("webm is not supported");
7032 result = GST_AUTOPLUG_SELECT_SKIP;
7036 /* check factory class for filtering */
7037 /* NOTE : msl don't need to use image plugins.
7038 * So, those plugins should be skipped for error handling.
7040 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7041 LOGD("skipping [%s] by not required", factory_name);
7042 result = GST_AUTOPLUG_SELECT_SKIP;
7046 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7047 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7048 // TO CHECK : subtitle if needed, add subparse exception.
7049 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7050 result = GST_AUTOPLUG_SELECT_SKIP;
7054 if (g_strrstr(factory_name, "mpegpsdemux")) {
7055 LOGD("skipping PS container - not support");
7056 result = GST_AUTOPLUG_SELECT_SKIP;
7060 if (g_strrstr(factory_name, "mssdemux"))
7061 player->smooth_streaming = TRUE;
7063 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7064 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7067 GstStructure *str = NULL;
7068 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7070 /* don't make video because of not required */
7071 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7072 (!player->set_mode.media_packet_video_stream)) {
7073 LOGD("no need video decoding, expose pad");
7074 result = GST_AUTOPLUG_SELECT_EXPOSE;
7078 /* get w/h for omx state-tune */
7079 /* FIXME: deprecated? */
7080 str = gst_caps_get_structure(caps, 0);
7081 gst_structure_get_int(str, "width", &width);
7084 if (player->v_stream_caps) {
7085 gst_caps_unref(player->v_stream_caps);
7086 player->v_stream_caps = NULL;
7089 player->v_stream_caps = gst_caps_copy(caps);
7090 LOGD("take caps for video state tune");
7091 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7095 if (g_strrstr(klass, "Codec/Decoder")) {
7096 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7097 if (result != GST_AUTOPLUG_SELECT_TRY) {
7098 LOGW("skip add decoder");
7104 MMPLAYER_FREEIF(caps_str);
7110 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7113 //mm_player_t *player = (mm_player_t *)data;
7114 GstCaps *caps = NULL;
7116 LOGD("[Decodebin2] pad-removed signal");
7118 caps = gst_pad_query_caps(new_pad, NULL);
7120 LOGW("query caps is NULL");
7124 gchar *caps_str = NULL;
7125 caps_str = gst_caps_to_string(caps);
7127 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7129 MMPLAYER_FREEIF(caps_str);
7130 gst_caps_unref(caps);
7134 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7136 mm_player_t *player = (mm_player_t *)data;
7137 GstIterator *iter = NULL;
7138 GValue item = { 0, };
7140 gboolean done = FALSE;
7141 gboolean is_all_drained = TRUE;
7144 MMPLAYER_RETURN_IF_FAIL(player);
7146 LOGD("__mmplayer_gst_decode_drained");
7148 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7149 LOGW("Fail to get cmd lock");
7153 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7154 !__mmplayer_verify_gapless_play_path(player)) {
7155 LOGD("decoding is finished.");
7156 __mmplayer_reset_gapless_state(player);
7157 MMPLAYER_CMD_UNLOCK(player);
7161 player->gapless.reconfigure = TRUE;
7163 /* check decodebin src pads whether they received EOS or not */
7164 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7167 switch (gst_iterator_next(iter, &item)) {
7168 case GST_ITERATOR_OK:
7169 pad = g_value_get_object(&item);
7170 if (pad && !GST_PAD_IS_EOS(pad)) {
7171 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7172 is_all_drained = FALSE;
7175 g_value_reset(&item);
7177 case GST_ITERATOR_RESYNC:
7178 gst_iterator_resync(iter);
7180 case GST_ITERATOR_ERROR:
7181 case GST_ITERATOR_DONE:
7186 g_value_unset(&item);
7187 gst_iterator_free(iter);
7189 if (!is_all_drained) {
7190 LOGD("Wait util the all pads get EOS.");
7191 MMPLAYER_CMD_UNLOCK(player);
7196 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7197 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7199 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7200 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7201 __mmplayer_deactivate_old_path(player);
7202 MMPLAYER_CMD_UNLOCK(player);
7208 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7210 mm_player_t *player = (mm_player_t *)data;
7211 const gchar *klass = NULL;
7212 gchar *factory_name = NULL;
7214 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7215 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7217 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7219 if (__mmplayer_add_dump_buffer_probe(player, element))
7220 LOGD("add buffer probe");
7223 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7224 gchar *selected = NULL;
7225 selected = g_strdup(GST_ELEMENT_NAME(element));
7226 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7230 if (g_strrstr(klass, "Parser")) {
7231 gchar *selected = NULL;
7233 selected = g_strdup(factory_name);
7234 player->parsers = g_list_append(player->parsers, selected);
7237 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7238 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7239 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7241 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7242 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7244 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7245 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7246 "max-video-width", player->adaptive_info.limit.width,
7247 "max-video-height", player->adaptive_info.limit.height, NULL);
7249 } else if (g_strrstr(klass, "Demuxer")) {
7250 //LOGD("plugged element is demuxer. take it");
7251 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7252 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7255 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7256 int surface_type = 0;
7258 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7261 // to support trust-zone only
7262 if (g_strrstr(factory_name, "asfdemux")) {
7263 LOGD("set file-location %s", player->profile.uri);
7264 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7265 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7266 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7267 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7268 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7269 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7270 (__mmplayer_is_only_mp3_type(player->type))) {
7271 LOGD("[mpegaudioparse] set streaming pull mode.");
7272 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7274 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7275 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7278 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7279 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7280 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7282 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7283 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7285 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7286 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7287 (MMPLAYER_IS_DASH_STREAMING(player))) {
7288 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7289 __mm_player_streaming_set_multiqueue(player->streamer, element);
7290 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7299 __mmplayer_release_misc(mm_player_t *player)
7302 bool cur_mode = player->set_mode.rich_audio;
7305 MMPLAYER_RETURN_IF_FAIL(player);
7307 player->video_stream_cb = NULL;
7308 player->video_stream_cb_user_param = NULL;
7309 player->video_stream_prerolled = false;
7311 player->audio_stream_render_cb = NULL;
7312 player->audio_stream_cb_user_param = NULL;
7313 player->audio_stream_sink_sync = false;
7315 player->video_stream_changed_cb = NULL;
7316 player->video_stream_changed_cb_user_param = NULL;
7318 player->audio_stream_changed_cb = NULL;
7319 player->audio_stream_changed_cb_user_param = NULL;
7321 player->sent_bos = FALSE;
7322 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7324 player->seek_state = MMPLAYER_SEEK_NONE;
7326 player->total_bitrate = 0;
7327 player->total_maximum_bitrate = 0;
7329 player->not_found_demuxer = 0;
7331 player->last_position = 0;
7332 player->duration = 0;
7333 player->http_content_size = 0;
7334 player->not_supported_codec = MISSING_PLUGIN_NONE;
7335 player->can_support_codec = FOUND_PLUGIN_NONE;
7336 player->pending_seek.is_pending = false;
7337 player->pending_seek.pos = 0;
7338 player->msg_posted = FALSE;
7339 player->has_many_types = FALSE;
7340 player->is_subtitle_force_drop = FALSE;
7341 player->play_subtitle = FALSE;
7342 player->adjust_subtitle_pos = 0;
7343 player->last_multiwin_status = FALSE;
7344 player->has_closed_caption = FALSE;
7345 player->set_mode.media_packet_video_stream = false;
7346 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7347 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7349 player->set_mode.rich_audio = cur_mode;
7351 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7352 player->bitrate[i] = 0;
7353 player->maximum_bitrate[i] = 0;
7356 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7358 /* remove media stream cb(appsrc cb) */
7359 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7360 player->media_stream_buffer_status_cb[i] = NULL;
7361 player->media_stream_seek_data_cb[i] = NULL;
7362 player->buffer_cb_user_param[i] = NULL;
7363 player->seek_cb_user_param[i] = NULL;
7365 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7367 /* free memory related to audio effect */
7368 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7370 if (player->adaptive_info.var_list) {
7371 g_list_free_full(player->adaptive_info.var_list, g_free);
7372 player->adaptive_info.var_list = NULL;
7375 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7376 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7377 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7379 /* Reset video360 settings to their defaults in case if the pipeline is to be
7382 player->video360_metadata.is_spherical = -1;
7383 player->is_openal_plugin_used = FALSE;
7385 player->is_content_spherical = FALSE;
7386 player->is_video360_enabled = TRUE;
7387 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7388 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7389 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7390 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7391 player->video360_zoom = 1.0f;
7392 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7393 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7395 player->sound.rg_enable = false;
7397 __mmplayer_initialize_video_roi(player);
7402 __mmplayer_release_misc_post(mm_player_t *player)
7404 char *original_uri = NULL;
7407 /* player->pipeline is already released before. */
7409 MMPLAYER_RETURN_IF_FAIL(player);
7411 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7413 /* clean found parsers */
7414 if (player->parsers) {
7415 GList *parsers = player->parsers;
7416 for (; parsers; parsers = g_list_next(parsers)) {
7417 gchar *name = parsers->data;
7418 MMPLAYER_FREEIF(name);
7420 g_list_free(player->parsers);
7421 player->parsers = NULL;
7424 /* clean found audio decoders */
7425 if (player->audio_decoders) {
7426 GList *a_dec = player->audio_decoders;
7427 for (; a_dec; a_dec = g_list_next(a_dec)) {
7428 gchar *name = a_dec->data;
7429 MMPLAYER_FREEIF(name);
7431 g_list_free(player->audio_decoders);
7432 player->audio_decoders = NULL;
7435 /* clean the uri list except original uri */
7436 if (player->uri_info.uri_list) {
7437 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7439 if (player->attrs) {
7440 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7441 LOGD("restore original uri = %s", original_uri);
7443 if (mm_attrs_commit_all(player->attrs))
7444 LOGE("failed to commit the original uri.");
7447 GList *uri_list = player->uri_info.uri_list;
7448 for (; uri_list; uri_list = g_list_next(uri_list)) {
7449 gchar *uri = uri_list->data;
7450 MMPLAYER_FREEIF(uri);
7452 g_list_free(player->uri_info.uri_list);
7453 player->uri_info.uri_list = NULL;
7456 /* clear the audio stream buffer list */
7457 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7459 /* clear the video stream bo list */
7460 __mmplayer_video_stream_destroy_bo_list(player);
7461 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7463 if (player->profile.input_mem.buf) {
7464 free(player->profile.input_mem.buf);
7465 player->profile.input_mem.buf = NULL;
7467 player->profile.input_mem.len = 0;
7468 player->profile.input_mem.offset = 0;
7470 player->uri_info.uri_idx = 0;
7475 __mmplayer_check_subtitle(mm_player_t *player)
7477 MMHandleType attrs = 0;
7478 char *subtitle_uri = NULL;
7482 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7484 /* get subtitle attribute */
7485 attrs = MMPLAYER_GET_ATTRS(player);
7489 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7490 if (!subtitle_uri || !strlen(subtitle_uri))
7493 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7494 player->is_external_subtitle_present = TRUE;
7502 __mmplayer_cancel_eos_timer(mm_player_t *player)
7504 MMPLAYER_RETURN_IF_FAIL(player);
7506 if (player->eos_timer) {
7507 LOGD("cancel eos timer");
7508 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7509 player->eos_timer = 0;
7516 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7520 MMPLAYER_RETURN_IF_FAIL(player);
7521 MMPLAYER_RETURN_IF_FAIL(sink);
7523 player->sink_elements = g_list_append(player->sink_elements, sink);
7529 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7533 MMPLAYER_RETURN_IF_FAIL(player);
7534 MMPLAYER_RETURN_IF_FAIL(sink);
7536 player->sink_elements = g_list_remove(player->sink_elements, sink);
7542 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7543 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7545 MMPlayerSignalItem *item = NULL;
7548 MMPLAYER_RETURN_IF_FAIL(player);
7550 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7551 LOGE("invalid signal type [%d]", type);
7555 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7557 LOGE("cannot connect signal [%s]", signal);
7562 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7563 player->signals[type] = g_list_append(player->signals[type], item);
7569 /* NOTE : be careful with calling this api. please refer to below glib comment
7570 * glib comment : Note that there is a bug in GObject that makes this function much
7571 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7572 * will no longer be called, but, the signal handler is not currently disconnected.
7573 * If the instance is itself being freed at the same time than this doesn't matter,
7574 * since the signal will automatically be removed, but if instance persists,
7575 * then the signal handler will leak. You should not remove the signal yourself
7576 * because in a future versions of GObject, the handler will automatically be
7579 * It's possible to work around this problem in a way that will continue to work
7580 * with future versions of GObject by checking that the signal handler is still
7581 * connected before disconnected it:
7583 * if (g_signal_handler_is_connected(instance, id))
7584 * g_signal_handler_disconnect(instance, id);
7587 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7589 GList *sig_list = NULL;
7590 MMPlayerSignalItem *item = NULL;
7594 MMPLAYER_RETURN_IF_FAIL(player);
7596 LOGD("release signals type : %d", type);
7598 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7599 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7600 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7601 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7602 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7603 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7607 sig_list = player->signals[type];
7609 for (; sig_list; sig_list = sig_list->next) {
7610 item = sig_list->data;
7612 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7613 if (g_signal_handler_is_connected(item->obj, item->sig))
7614 g_signal_handler_disconnect(item->obj, item->sig);
7617 MMPLAYER_FREEIF(item);
7620 g_list_free(player->signals[type]);
7621 player->signals[type] = NULL;
7629 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7631 mm_player_t *player = 0;
7632 int prev_display_surface_type = 0;
7633 void *prev_display_overlay = NULL;
7637 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7638 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7640 player = MM_PLAYER_CAST(handle);
7642 /* check video sinkbin is created */
7643 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7644 LOGE("Videosink is already created");
7645 return MM_ERROR_NONE;
7648 LOGD("videosink element is not yet ready");
7650 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7651 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7653 return MM_ERROR_INVALID_ARGUMENT;
7656 /* load previous attributes */
7657 if (player->attrs) {
7658 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7659 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7660 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7661 if (prev_display_surface_type == surface_type) {
7662 LOGD("incoming display surface type is same as previous one, do nothing..");
7664 return MM_ERROR_NONE;
7667 LOGE("failed to load attributes");
7669 return MM_ERROR_PLAYER_INTERNAL;
7672 /* videobin is not created yet, so we just set attributes related to display surface */
7673 LOGD("store display attribute for given surface type(%d)", surface_type);
7674 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7675 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7676 if (mm_attrs_commit_all(player->attrs)) {
7677 LOGE("failed to commit attribute");
7679 return MM_ERROR_PLAYER_INTERNAL;
7683 return MM_ERROR_NONE;
7686 /* Note : if silent is true, then subtitle would not be displayed. :*/
7688 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7690 mm_player_t *player = (mm_player_t *)hplayer;
7694 /* check player handle */
7695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7697 player->set_mode.subtitle_off = silent;
7699 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7703 return MM_ERROR_NONE;
7707 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7709 MMPlayerGstElement *mainbin = NULL;
7710 MMPlayerGstElement *textbin = NULL;
7711 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7712 GstState current_state = GST_STATE_VOID_PENDING;
7713 GstState element_state = GST_STATE_VOID_PENDING;
7714 GstState element_pending_state = GST_STATE_VOID_PENDING;
7716 GstEvent *event = NULL;
7717 int result = MM_ERROR_NONE;
7719 GstClock *curr_clock = NULL;
7720 GstClockTime base_time, start_time, curr_time;
7725 /* check player handle */
7726 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7728 player->pipeline->mainbin &&
7729 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7731 mainbin = player->pipeline->mainbin;
7732 textbin = player->pipeline->textbin;
7734 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7736 // sync clock with current pipeline
7737 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7738 curr_time = gst_clock_get_time(curr_clock);
7740 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7741 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7743 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7744 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7746 if (current_state > GST_STATE_READY) {
7747 // sync state with current pipeline
7748 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7749 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7750 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7752 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7753 if (GST_STATE_CHANGE_FAILURE == ret) {
7754 LOGE("fail to state change.");
7755 result = MM_ERROR_PLAYER_INTERNAL;
7759 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7760 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7763 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7764 gst_object_unref(curr_clock);
7767 // seek to current position
7768 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7769 result = MM_ERROR_PLAYER_INVALID_STATE;
7770 LOGE("gst_element_query_position failed, invalid state");
7774 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7775 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);
7777 __mmplayer_gst_send_event_to_sink(player, event);
7779 result = MM_ERROR_PLAYER_INTERNAL;
7780 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7784 /* sync state with current pipeline */
7785 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7786 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7787 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7789 return MM_ERROR_NONE;
7792 /* release text pipeline resource */
7793 player->textsink_linked = 0;
7795 /* release signal */
7796 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7798 /* release textbin with it's childs */
7799 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7800 MMPLAYER_FREEIF(player->pipeline->textbin);
7801 player->pipeline->textbin = NULL;
7803 /* release subtitle elem */
7804 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7805 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7811 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7813 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7814 GstState current_state = GST_STATE_VOID_PENDING;
7816 MMHandleType attrs = 0;
7817 MMPlayerGstElement *mainbin = NULL;
7818 MMPlayerGstElement *textbin = NULL;
7820 gchar *subtitle_uri = NULL;
7821 int result = MM_ERROR_NONE;
7822 const gchar *charset = NULL;
7826 /* check player handle */
7827 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7829 player->pipeline->mainbin &&
7830 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7831 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7833 mainbin = player->pipeline->mainbin;
7834 textbin = player->pipeline->textbin;
7836 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7837 if (current_state < GST_STATE_READY) {
7838 result = MM_ERROR_PLAYER_INVALID_STATE;
7839 LOGE("Pipeline is not in proper state");
7843 attrs = MMPLAYER_GET_ATTRS(player);
7845 LOGE("cannot get content attribute");
7846 result = MM_ERROR_PLAYER_INTERNAL;
7850 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7851 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7852 LOGE("subtitle uri is not proper filepath");
7853 result = MM_ERROR_PLAYER_INVALID_URI;
7857 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7858 LOGE("failed to get storage info of subtitle path");
7859 result = MM_ERROR_PLAYER_INVALID_URI;
7863 LOGD("old subtitle file path is [%s]", subtitle_uri);
7864 LOGD("new subtitle file path is [%s]", filepath);
7866 if (!strcmp(filepath, subtitle_uri)) {
7867 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7870 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7871 if (mm_attrs_commit_all(player->attrs)) {
7872 LOGE("failed to commit.");
7877 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7878 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7879 player->subtitle_language_list = NULL;
7880 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7882 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7883 if (ret != GST_STATE_CHANGE_SUCCESS) {
7884 LOGE("failed to change state of textbin to READY");
7885 result = MM_ERROR_PLAYER_INTERNAL;
7889 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7890 if (ret != GST_STATE_CHANGE_SUCCESS) {
7891 LOGE("failed to change state of subparse to READY");
7892 result = MM_ERROR_PLAYER_INTERNAL;
7896 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7897 if (ret != GST_STATE_CHANGE_SUCCESS) {
7898 LOGE("failed to change state of filesrc to READY");
7899 result = MM_ERROR_PLAYER_INTERNAL;
7903 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7905 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7907 charset = util_get_charset(filepath);
7909 LOGD("detected charset is %s", charset);
7910 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7913 result = _mmplayer_sync_subtitle_pipeline(player);
7920 /* API to switch between external subtitles */
7922 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7924 int result = MM_ERROR_NONE;
7925 mm_player_t *player = (mm_player_t *)hplayer;
7930 /* check player handle */
7931 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7933 /* filepath can be null in idle state */
7935 /* check file path */
7936 if ((path = strstr(filepath, "file://")))
7937 result = util_exist_file_path(path + 7);
7939 result = util_exist_file_path(filepath);
7941 if (result != MM_ERROR_NONE) {
7942 LOGE("invalid subtitle path 0x%X", result);
7943 return result; /* file not found or permission denied */
7947 if (!player->pipeline) {
7949 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7950 if (mm_attrs_commit_all(player->attrs)) {
7951 LOGE("failed to commit"); /* subtitle path will not be created */
7952 return MM_ERROR_PLAYER_INTERNAL;
7955 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7956 /* check filepath */
7957 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7959 if (!__mmplayer_check_subtitle(player)) {
7960 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7961 if (mm_attrs_commit_all(player->attrs)) {
7962 LOGE("failed to commit");
7963 return MM_ERROR_PLAYER_INTERNAL;
7966 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7967 LOGE("fail to create text pipeline");
7968 return MM_ERROR_PLAYER_INTERNAL;
7971 result = _mmplayer_sync_subtitle_pipeline(player);
7973 result = __mmplayer_change_external_subtitle_language(player, filepath);
7976 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7977 player->is_external_subtitle_added_now = TRUE;
7979 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7980 if (!player->subtitle_language_list) {
7981 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7982 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7983 LOGW("subtitle language list is not updated yet");
7985 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7993 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7995 int result = MM_ERROR_NONE;
7996 gchar *change_pad_name = NULL;
7997 GstPad *sinkpad = NULL;
7998 MMPlayerGstElement *mainbin = NULL;
7999 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8000 GstCaps *caps = NULL;
8001 gint total_track_num = 0;
8005 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8006 MM_ERROR_PLAYER_NOT_INITIALIZED);
8008 LOGD("Change Track(%d) to %d", type, index);
8010 mainbin = player->pipeline->mainbin;
8012 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8013 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8014 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8015 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8017 /* Changing Video Track is not supported. */
8018 LOGE("Track Type Error");
8022 if (mainbin[elem_idx].gst == NULL) {
8023 result = MM_ERROR_PLAYER_NO_OP;
8024 LOGD("Req track doesn't exist");
8028 total_track_num = player->selector[type].total_track_num;
8029 if (total_track_num <= 0) {
8030 result = MM_ERROR_PLAYER_NO_OP;
8031 LOGD("Language list is not available");
8035 if ((index < 0) || (index >= total_track_num)) {
8036 result = MM_ERROR_INVALID_ARGUMENT;
8037 LOGD("Not a proper index : %d", index);
8041 /*To get the new pad from the selector*/
8042 change_pad_name = g_strdup_printf("sink_%u", index);
8043 if (change_pad_name == NULL) {
8044 result = MM_ERROR_PLAYER_INTERNAL;
8045 LOGD("Pad does not exists");
8049 LOGD("new active pad name: %s", change_pad_name);
8051 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8052 if (sinkpad == NULL) {
8053 LOGD("sinkpad is NULL");
8054 result = MM_ERROR_PLAYER_INTERNAL;
8058 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8059 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8061 caps = gst_pad_get_current_caps(sinkpad);
8062 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8065 gst_object_unref(sinkpad);
8067 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8068 __mmplayer_set_audio_attrs(player, caps);
8071 MMPLAYER_FREEIF(change_pad_name);
8076 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8078 int result = MM_ERROR_NONE;
8079 mm_player_t *player = NULL;
8080 MMPlayerGstElement *mainbin = NULL;
8082 gint current_active_index = 0;
8084 GstState current_state = GST_STATE_VOID_PENDING;
8085 GstEvent *event = NULL;
8090 player = (mm_player_t *)hplayer;
8091 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8093 if (!player->pipeline) {
8094 LOGE("Track %d pre setting -> %d", type, index);
8096 player->selector[type].active_pad_index = index;
8100 mainbin = player->pipeline->mainbin;
8102 current_active_index = player->selector[type].active_pad_index;
8104 /*If index is same as running index no need to change the pad*/
8105 if (current_active_index == index)
8108 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8109 result = MM_ERROR_PLAYER_INVALID_STATE;
8113 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8114 if (current_state < GST_STATE_PAUSED) {
8115 result = MM_ERROR_PLAYER_INVALID_STATE;
8116 LOGW("Pipeline not in porper state");
8120 result = __mmplayer_change_selector_pad(player, type, index);
8121 if (result != MM_ERROR_NONE) {
8122 LOGE("change selector pad error");
8126 player->selector[type].active_pad_index = index;
8128 if (current_state == GST_STATE_PLAYING) {
8129 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8130 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8131 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8133 __mmplayer_gst_send_event_to_sink(player, event);
8135 result = MM_ERROR_PLAYER_INTERNAL;
8145 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8147 mm_player_t *player = (mm_player_t *)hplayer;
8151 /* check player handle */
8152 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8154 *silent = player->set_mode.subtitle_off;
8156 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8160 return MM_ERROR_NONE;
8164 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8166 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8167 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8169 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8170 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8174 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8175 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8176 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8177 mm_player_dump_t *dump_s;
8178 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8179 if (dump_s == NULL) {
8180 LOGE("malloc fail");
8184 dump_s->dump_element_file = NULL;
8185 dump_s->dump_pad = NULL;
8186 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8188 if (dump_s->dump_pad) {
8189 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8190 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]);
8191 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8192 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);
8193 /* add list for removed buffer probe and close FILE */
8194 player->dump_list = g_list_append(player->dump_list, dump_s);
8195 LOGD("%s sink pad added buffer probe for dump", factory_name);
8198 MMPLAYER_FREEIF(dump_s);
8199 LOGE("failed to get %s sink pad added", factory_name);
8206 static GstPadProbeReturn
8207 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8209 FILE *dump_data = (FILE *)u_data;
8211 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8212 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8214 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8216 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8218 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8220 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8222 return GST_PAD_PROBE_OK;
8226 __mmplayer_release_dump_list(GList *dump_list)
8228 GList *d_list = dump_list;
8233 for (; d_list; d_list = g_list_next(d_list)) {
8234 mm_player_dump_t *dump_s = d_list->data;
8235 if (dump_s->dump_pad) {
8236 if (dump_s->probe_handle_id)
8237 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8238 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8240 if (dump_s->dump_element_file) {
8241 fclose(dump_s->dump_element_file);
8242 dump_s->dump_element_file = NULL;
8244 MMPLAYER_FREEIF(dump_s);
8246 g_list_free(dump_list);
8251 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8253 mm_player_t *player = (mm_player_t *)hplayer;
8257 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8258 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8260 *exist = (bool)player->has_closed_caption;
8264 return MM_ERROR_NONE;
8268 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8272 // LOGD("unref internal gst buffer %p", buffer);
8273 gst_buffer_unref((GstBuffer *)buffer);
8280 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8282 mm_player_t *player = (mm_player_t *)hplayer;
8286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8287 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8289 if (MMPLAYER_IS_STREAMING(player))
8290 *timeout = (int)player->ini.live_state_change_timeout;
8292 *timeout = (int)player->ini.localplayback_state_change_timeout;
8294 LOGD("timeout = %d", *timeout);
8297 return MM_ERROR_NONE;
8301 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8303 mm_player_t *player = (mm_player_t *)hplayer;
8307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8308 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8310 *num = player->video_num_buffers;
8311 *extra_num = player->video_extra_num_buffers;
8313 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8316 return MM_ERROR_NONE;
8320 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8324 MMPLAYER_RETURN_IF_FAIL(player);
8326 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8328 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8329 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8330 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8331 player->storage_info[i].id = -1;
8332 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8334 if (path_type != MMPLAYER_PATH_MAX)
8343 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8345 int ret = MM_ERROR_NONE;
8346 mm_player_t *player = (mm_player_t *)hplayer;
8347 MMMessageParamType msg_param = {0, };
8350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8352 LOGW("state changed storage %d:%d", id, state);
8354 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8355 return MM_ERROR_NONE;
8357 /* FIXME: text path should be handled seperately. */
8358 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8359 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8360 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8361 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8362 LOGW("external storage is removed");
8364 if (player->msg_posted == FALSE) {
8365 memset(&msg_param, 0, sizeof(MMMessageParamType));
8366 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8367 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8368 player->msg_posted = TRUE;
8371 /* unrealize the player */
8372 ret = _mmplayer_unrealize(hplayer);
8373 if (ret != MM_ERROR_NONE)
8374 LOGE("failed to unrealize");
8382 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8384 int ret = MM_ERROR_NONE;
8385 mm_player_t *player = (mm_player_t *)hplayer;
8386 int idx = 0, total = 0;
8387 gchar *result = NULL, *tmp = NULL;
8390 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8391 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8393 total = *num = g_list_length(player->adaptive_info.var_list);
8395 LOGW("There is no stream variant info.");
8399 result = g_strdup("");
8400 for (idx = 0 ; idx < total ; idx++) {
8401 VariantData *v_data = NULL;
8402 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8405 gchar data[64] = {0};
8406 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8408 tmp = g_strconcat(result, data, NULL);
8412 LOGW("There is no variant data in %d", idx);
8417 *var_info = (char *)result;
8419 LOGD("variant info %d:%s", *num, *var_info);
8425 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8427 int ret = MM_ERROR_NONE;
8428 mm_player_t *player = (mm_player_t *)hplayer;
8431 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8433 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8435 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8436 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8437 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8439 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8440 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8441 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8442 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8444 /* FIXME: seek to current position for applying new variant limitation */
8453 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8455 int ret = MM_ERROR_NONE;
8456 mm_player_t *player = (mm_player_t *)hplayer;
8459 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8460 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8462 *bandwidth = player->adaptive_info.limit.bandwidth;
8463 *width = player->adaptive_info.limit.width;
8464 *height = player->adaptive_info.limit.height;
8466 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8473 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8475 int ret = MM_ERROR_NONE;
8476 mm_player_t *player = (mm_player_t *)hplayer;
8479 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8480 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8481 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8483 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8485 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8486 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8487 else /* live case */
8488 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8490 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8497 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8499 #define IDX_FIRST_SW_CODEC 0
8500 mm_player_t *player = (mm_player_t *)hplayer;
8501 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8502 MMHandleType attrs = 0;
8505 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8507 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8508 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8509 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8511 switch (stream_type) {
8512 case MM_PLAYER_STREAM_TYPE_AUDIO:
8513 /* to support audio codec selection, codec info have to be added in ini file as below.
8514 audio codec element hw = xxxx
8515 audio codec element sw = avdec */
8516 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8517 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8518 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8519 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8520 LOGE("There is no audio codec info for codec_type %d", codec_type);
8521 return MM_ERROR_PLAYER_NO_OP;
8524 case MM_PLAYER_STREAM_TYPE_VIDEO:
8525 /* to support video codec selection, codec info have to be added in ini file as below.
8526 video codec element hw = omx
8527 video codec element sw = avdec */
8528 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8529 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8530 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8531 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8532 LOGE("There is no video codec info for codec_type %d", codec_type);
8533 return MM_ERROR_PLAYER_NO_OP;
8537 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8538 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8542 LOGD("update %s codec_type to %d", attr_name, codec_type);
8544 attrs = MMPLAYER_GET_ATTRS(player);
8545 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8547 if (mm_attrs_commit_all(player->attrs)) {
8548 LOGE("failed to commit codec_type attributes");
8549 return MM_ERROR_PLAYER_INTERNAL;
8553 return MM_ERROR_NONE;
8557 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8559 mm_player_t *player = (mm_player_t *)hplayer;
8560 GstElement *rg_vol_element = NULL;
8564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8566 player->sound.rg_enable = enabled;
8568 /* just hold rgvolume enable value if pipeline is not ready */
8569 if (!player->pipeline || !player->pipeline->audiobin) {
8570 LOGD("pipeline is not ready. holding rgvolume enable value");
8571 return MM_ERROR_NONE;
8574 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8576 if (!rg_vol_element) {
8577 LOGD("rgvolume element is not created");
8578 return MM_ERROR_PLAYER_INTERNAL;
8582 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8584 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8588 return MM_ERROR_NONE;
8592 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8594 mm_player_t *player = (mm_player_t *)hplayer;
8595 GstElement *rg_vol_element = NULL;
8596 gboolean enable = FALSE;
8600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8601 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8603 /* just hold enable_rg value if pipeline is not ready */
8604 if (!player->pipeline || !player->pipeline->audiobin) {
8605 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8606 *enabled = player->sound.rg_enable;
8607 return MM_ERROR_NONE;
8610 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8612 if (!rg_vol_element) {
8613 LOGD("rgvolume element is not created");
8614 return MM_ERROR_PLAYER_INTERNAL;
8617 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8618 *enabled = (bool)enable;
8622 return MM_ERROR_NONE;
8626 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8628 mm_player_t *player = (mm_player_t *)hplayer;
8629 MMHandleType attrs = 0;
8630 void *handle = NULL;
8631 int ret = MM_ERROR_NONE;
8635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8637 attrs = MMPLAYER_GET_ATTRS(player);
8638 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8640 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8642 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8643 return MM_ERROR_PLAYER_INTERNAL;
8646 player->video_roi.scale_x = scale_x;
8647 player->video_roi.scale_y = scale_y;
8648 player->video_roi.scale_width = scale_width;
8649 player->video_roi.scale_height = scale_height;
8651 /* check video sinkbin is created */
8652 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8653 return MM_ERROR_NONE;
8655 if (!gst_video_overlay_set_video_roi_area(
8656 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8657 scale_x, scale_y, scale_width, scale_height))
8658 ret = MM_ERROR_PLAYER_INTERNAL;
8660 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8661 scale_x, scale_y, scale_width, scale_height);
8669 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8671 mm_player_t *player = (mm_player_t *)hplayer;
8672 int ret = MM_ERROR_NONE;
8676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8677 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8679 *scale_x = player->video_roi.scale_x;
8680 *scale_y = player->video_roi.scale_y;
8681 *scale_width = player->video_roi.scale_width;
8682 *scale_height = player->video_roi.scale_height;
8684 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8685 *scale_x, *scale_y, *scale_width, *scale_height);
8691 __mmplayer_update_duration_value(mm_player_t *player)
8693 gboolean ret = FALSE;
8694 gint64 dur_nsec = 0;
8695 LOGD("try to update duration");
8697 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8698 player->duration = dur_nsec;
8699 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8703 if (player->duration < 0) {
8704 LOGW("duration is Non-Initialized !!!");
8705 player->duration = 0;
8708 /* update streaming service type */
8709 player->streaming_type = __mmplayer_get_stream_service_type(player);
8711 /* check duration is OK */
8712 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8713 /* FIXIT : find another way to get duration here. */
8714 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8720 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8722 /* update audio params
8723 NOTE : We need original audio params and it can be only obtained from src pad of audio
8724 decoder. Below code only valid when we are not using 'resampler' just before
8725 'audioconverter'. */
8726 GstCaps *caps_a = NULL;
8728 gint samplerate = 0, channels = 0;
8729 GstStructure *p = NULL;
8731 LOGD("try to update audio attrs");
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8734 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8736 pad = gst_element_get_static_pad(
8737 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8740 LOGW("failed to get pad from audiosink");
8744 caps_a = gst_pad_get_current_caps(pad);
8746 LOGW("not ready to get audio caps");
8747 gst_object_unref(pad);
8751 p = gst_caps_get_structure(caps_a, 0);
8753 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8755 gst_structure_get_int(p, "rate", &samplerate);
8756 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8758 gst_structure_get_int(p, "channels", &channels);
8759 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8761 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8763 gst_caps_unref(caps_a);
8764 gst_object_unref(pad);
8770 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8772 LOGD("try to update video attrs");
8774 GstCaps *caps_v = NULL;
8778 GstStructure *p = NULL;
8780 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8781 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8783 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8785 LOGD("no videosink sink pad");
8789 caps_v = gst_pad_get_current_caps(pad);
8790 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8791 if (!caps_v && player->v_stream_caps) {
8792 caps_v = player->v_stream_caps;
8793 gst_caps_ref(caps_v);
8797 LOGD("no negitiated caps from videosink");
8798 gst_object_unref(pad);
8802 p = gst_caps_get_structure(caps_v, 0);
8803 gst_structure_get_int(p, "width", &width);
8804 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8806 gst_structure_get_int(p, "height", &height);
8807 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8809 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8811 SECURE_LOGD("width : %d height : %d", width, height);
8813 gst_caps_unref(caps_v);
8814 gst_object_unref(pad);
8817 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8818 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8825 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8827 gboolean ret = FALSE;
8828 guint64 data_size = 0;
8832 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8833 if (!player->duration)
8836 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8837 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8838 if (stat(path, &sb) == 0)
8839 data_size = (guint64)sb.st_size;
8841 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8842 data_size = player->http_content_size;
8845 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8848 guint64 bitrate = 0;
8849 guint64 msec_dur = 0;
8851 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8853 bitrate = data_size * 8 * 1000 / msec_dur;
8854 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8855 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8859 LOGD("player duration is less than 0");
8863 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8864 if (player->total_bitrate) {
8865 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8874 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8876 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8877 data->uri_type = uri_type;
8881 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8883 int ret = MM_ERROR_PLAYER_INVALID_URI;
8885 char *buffer = NULL;
8886 char *seperator = strchr(path, ',');
8887 char ext[100] = {0,}, size[100] = {0,};
8890 if ((buffer = strstr(path, "ext="))) {
8891 buffer += strlen("ext=");
8893 if (strlen(buffer)) {
8894 strncpy(ext, buffer, 99);
8896 if ((seperator = strchr(ext, ','))
8897 || (seperator = strchr(ext, ' '))
8898 || (seperator = strchr(ext, '\0'))) {
8899 seperator[0] = '\0';
8904 if ((buffer = strstr(path, "size="))) {
8905 buffer += strlen("size=");
8907 if (strlen(buffer) > 0) {
8908 strncpy(size, buffer, 99);
8910 if ((seperator = strchr(size, ','))
8911 || (seperator = strchr(size, ' '))
8912 || (seperator = strchr(size, '\0'))) {
8913 seperator[0] = '\0';
8916 mem_size = atoi(size);
8921 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8923 if (mem_size && param) {
8924 if (data->input_mem.buf)
8925 free(data->input_mem.buf);
8926 data->input_mem.buf = malloc(mem_size);
8928 if (data->input_mem.buf) {
8929 memcpy(data->input_mem.buf, param, mem_size);
8930 data->input_mem.len = mem_size;
8931 ret = MM_ERROR_NONE;
8933 LOGE("failed to alloc mem %d", mem_size);
8934 ret = MM_ERROR_PLAYER_INTERNAL;
8937 data->input_mem.offset = 0;
8938 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8945 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8947 gchar *location = NULL;
8950 int ret = MM_ERROR_NONE;
8952 if ((path = strstr(uri, "file://"))) {
8953 location = g_filename_from_uri(uri, NULL, &err);
8954 if (!location || (err != NULL)) {
8955 LOGE("Invalid URI '%s' for filesrc: %s", path,
8956 (err != NULL) ? err->message : "unknown error");
8960 MMPLAYER_FREEIF(location);
8962 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8963 return MM_ERROR_PLAYER_INVALID_URI;
8965 LOGD("path from uri: %s", location);
8968 path = (location != NULL) ? (location) : ((char *)uri);
8971 ret = util_exist_file_path(path);
8973 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8974 if (ret == MM_ERROR_NONE) {
8975 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8976 if (util_is_sdp_file(path)) {
8977 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8978 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8980 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8982 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8983 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8985 LOGE("invalid uri, could not play..");
8986 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8989 MMPLAYER_FREEIF(location);
8994 static MMPlayerVideoStreamDataType *
8995 __mmplayer_create_stream_from_pad(GstPad *pad)
8997 GstCaps *caps = NULL;
8998 GstStructure *structure = NULL;
8999 unsigned int fourcc = 0;
9000 const gchar *string_format = NULL;
9001 MMPlayerVideoStreamDataType *stream = NULL;
9003 MMPixelFormatType format;
9005 caps = gst_pad_get_current_caps(pad);
9007 LOGE("Caps is NULL.");
9011 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9012 structure = gst_caps_get_structure(caps, 0);
9013 gst_structure_get_int(structure, "width", &width);
9014 gst_structure_get_int(structure, "height", &height);
9015 string_format = gst_structure_get_string(structure, "format");
9017 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9018 format = util_get_pixtype(fourcc);
9019 gst_caps_unref(caps);
9022 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9023 LOGE("Wrong condition!!");
9027 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9029 LOGE("failed to alloc mem for video data");
9033 stream->width = width;
9034 stream->height = height;
9035 stream->format = format;
9041 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9043 unsigned int pitch = 0;
9045 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9047 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9048 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9049 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9050 stream->stride[index] = pitch;
9051 stream->elevation[index] = stream->height;
9056 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9058 if (stream->format == MM_PIXEL_FORMAT_I420) {
9059 int ret = TBM_SURFACE_ERROR_NONE;
9060 tbm_surface_h surface;
9061 tbm_surface_info_s info;
9063 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9065 ret = tbm_surface_get_info(surface, &info);
9066 if (ret != TBM_SURFACE_ERROR_NONE) {
9067 tbm_surface_destroy(surface);
9071 tbm_surface_destroy(surface);
9072 stream->stride[0] = info.planes[0].stride;
9073 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9074 stream->stride[1] = info.planes[1].stride;
9075 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9076 stream->stride[2] = info.planes[2].stride;
9077 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9078 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9079 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9080 stream->stride[0] = stream->width * 4;
9081 stream->elevation[0] = stream->height;
9082 stream->bo_size = stream->stride[0] * stream->height;
9084 LOGE("Not support format %d", stream->format);
9092 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9094 tbm_bo_handle thandle;
9096 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9097 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9098 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9102 unsigned char *src = NULL;
9103 unsigned char *dest = NULL;
9104 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9106 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9108 LOGE("fail to gst_memory_map");
9112 if (!mapinfo.data) {
9113 LOGE("data pointer is wrong");
9117 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9118 if (!stream->bo[0]) {
9119 LOGE("Fail to tbm_bo_alloc!!");
9123 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9125 LOGE("thandle pointer is wrong");
9129 if (stream->format == MM_PIXEL_FORMAT_I420) {
9130 src_stride[0] = GST_ROUND_UP_4(stream->width);
9131 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9132 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9133 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9136 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9137 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9139 for (i = 0; i < 3; i++) {
9140 src = mapinfo.data + src_offset[i];
9141 dest = thandle.ptr + dest_offset[i];
9146 for (j = 0; j < stream->height >> k; j++) {
9147 memcpy(dest, src, stream->width>>k);
9148 src += src_stride[i];
9149 dest += stream->stride[i];
9152 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9153 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9155 LOGE("Not support format %d", stream->format);
9159 tbm_bo_unmap(stream->bo[0]);
9160 gst_memory_unmap(mem, &mapinfo);
9166 tbm_bo_unmap(stream->bo[0]);
9169 gst_memory_unmap(mem, &mapinfo);
9175 __mmplayer_set_pause_state(mm_player_t *player)
9177 if (player->sent_bos)
9180 /* rtsp case, get content attrs by GstMessage */
9181 if (MMPLAYER_IS_RTSP_STREAMING(player))
9184 /* it's first time to update all content attrs. */
9185 __mmplayer_update_content_attrs(player, ATTR_ALL);
9189 __mmplayer_set_playing_state(mm_player_t *player)
9191 gchar *audio_codec = NULL;
9193 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9194 /* initialize because auto resume is done well. */
9195 player->resumed_by_rewind = FALSE;
9196 player->playback_rate = 1.0;
9199 if (player->sent_bos)
9202 /* try to get content metadata */
9204 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9205 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9206 * legacy mmfw-player api
9208 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9210 if ((player->cmd == MMPLAYER_COMMAND_START)
9211 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9212 __mmplayer_handle_missed_plugin(player);
9215 /* check audio codec field is set or not
9216 * we can get it from typefinder or codec's caps.
9218 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9220 /* The codec format can't be sent for audio only case like amr, mid etc.
9221 * Because, parser don't make related TAG.
9222 * So, if it's not set yet, fill it with found data.
9225 if (g_strrstr(player->type, "audio/midi"))
9226 audio_codec = "MIDI";
9227 else if (g_strrstr(player->type, "audio/x-amr"))
9228 audio_codec = "AMR";
9229 else if (g_strrstr(player->type, "audio/mpeg")
9230 && !g_strrstr(player->type, "mpegversion= (int)1"))
9231 audio_codec = "AAC";
9233 audio_codec = "unknown";
9235 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9237 if (mm_attrs_commit_all(player->attrs))
9238 LOGE("failed to update attributes");
9240 LOGD("set audio codec type with caps");