4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
113 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
114 We are defining our own and will be removed when it actually exposed */
116 GST_AUTOPLUG_SELECT_TRY,
117 GST_AUTOPLUG_SELECT_EXPOSE,
118 GST_AUTOPLUG_SELECT_SKIP
119 } GstAutoplugSelectResult;
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
135 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
136 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
137 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
142 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
143 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
144 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
152 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_release_misc(mm_player_t *player);
154 static void __mmplayer_release_misc_post(mm_player_t *player);
155 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
156 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
159 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
161 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
162 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
163 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
164 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
165 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
166 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
167 static gpointer __mmplayer_gapless_play_thread(gpointer data);
168 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
169 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static void __mmplayer_release_dump_list(GList *dump_list);
171 static int __mmplayer_gst_realize(mm_player_t *player);
172 static int __mmplayer_gst_unrealize(mm_player_t *player);
173 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
174 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
177 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
178 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
179 static void __mmplayer_check_pipeline(mm_player_t *player);
180 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
181 static void __mmplayer_deactivate_old_path(mm_player_t *player);
182 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
183 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
184 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
185 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
186 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
187 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
188 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
189 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
193 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
194 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
195 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
197 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
198 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
199 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
200 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
202 static void __mmplayer_set_pause_state(mm_player_t *player);
203 static void __mmplayer_set_playing_state(mm_player_t *player);
204 /*===========================================================================================
206 | FUNCTION DEFINITIONS |
208 ========================================================================================== */
212 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
216 count = gst_tag_list_get_tag_size(list, tag);
218 LOGD("count = %d", count);
220 for (i = 0; i < count; i++) {
223 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
224 if (!gst_tag_list_get_string_index(list, tag, i, &str))
225 g_assert_not_reached();
227 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
231 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
233 g_print(" : %s", str);
240 /* This function should be called after the pipeline goes PAUSED or higher
243 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
245 static gboolean has_duration = FALSE;
246 static gboolean has_video_attrs = FALSE;
247 static gboolean has_audio_attrs = FALSE;
248 static gboolean has_bitrate = FALSE;
249 gboolean missing_only = FALSE;
250 gboolean all = FALSE;
251 MMHandleType attrs = 0;
255 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
257 /* check player state here */
258 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
259 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
260 /* give warning now only */
261 LOGW("be careful. content attributes may not available in this state ");
264 /* get content attribute first */
265 attrs = MMPLAYER_GET_ATTRS(player);
267 LOGE("cannot get content attribute");
271 /* get update flag */
273 if (flag & ATTR_MISSING_ONLY) {
275 LOGD("updating missed attr only");
278 if (flag & ATTR_ALL) {
280 has_duration = FALSE;
281 has_video_attrs = FALSE;
282 has_audio_attrs = FALSE;
285 LOGD("updating all attrs");
288 if (missing_only && all) {
289 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
290 missing_only = FALSE;
293 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
294 has_duration = __mmplayer_update_duration_value(player);
296 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
297 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
299 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
300 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
302 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
303 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
306 if (mm_attrs_commit_all(attrs)) {
307 LOGE("failed to update attributes");
317 __mmplayer_get_stream_service_type(mm_player_t *player)
319 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
325 player->pipeline->mainbin &&
326 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
327 STREAMING_SERVICE_NONE);
329 /* streaming service type if streaming */
330 if (!MMPLAYER_IS_STREAMING(player))
331 return STREAMING_SERVICE_NONE;
333 streaming_type = (player->duration == 0) ?
334 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
336 switch (streaming_type) {
337 case STREAMING_SERVICE_LIVE:
338 LOGD("it's live streaming");
340 case STREAMING_SERVICE_VOD:
341 LOGD("it's vod streaming");
344 LOGE("should not get here");
350 return streaming_type;
353 /* this function sets the player state and also report
354 * it to applicaton by calling callback function
357 __mmplayer_set_state(mm_player_t *player, int state)
359 MMMessageParamType msg = {0, };
361 MMPLAYER_RETURN_IF_FAIL(player);
363 if (MMPLAYER_CURRENT_STATE(player) == state) {
364 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
365 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
369 /* update player states */
370 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
371 MMPLAYER_CURRENT_STATE(player) = state;
373 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
374 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
377 MMPLAYER_PRINT_STATE(player);
379 switch (MMPLAYER_CURRENT_STATE(player)) {
380 case MM_PLAYER_STATE_NULL:
381 case MM_PLAYER_STATE_READY:
383 case MM_PLAYER_STATE_PAUSED:
384 __mmplayer_set_pause_state(player);
386 case MM_PLAYER_STATE_PLAYING:
387 __mmplayer_set_playing_state(player);
389 case MM_PLAYER_STATE_NONE:
391 LOGW("invalid target state, there is nothing to do.");
396 /* post message to application */
397 if (MMPLAYER_TARGET_STATE(player) == state) {
398 /* fill the message with state of player */
399 msg.union_type = MM_MSG_UNION_STATE;
400 msg.state.previous = MMPLAYER_PREV_STATE(player);
401 msg.state.current = MMPLAYER_CURRENT_STATE(player);
403 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
405 /* state changed by resource callback */
406 if (player->interrupted_by_resource)
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
408 else /* state changed by usecase */
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
412 LOGD("intermediate state, do nothing.");
413 MMPLAYER_PRINT_STATE(player);
417 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
418 && !player->sent_bos) {
419 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
420 player->sent_bos = TRUE;
427 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
429 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
430 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
434 //LOGD("incomming command : %d ", command);
436 current_state = MMPLAYER_CURRENT_STATE(player);
437 pending_state = MMPLAYER_PENDING_STATE(player);
439 MMPLAYER_PRINT_STATE(player);
442 case MMPLAYER_COMMAND_CREATE:
444 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
446 if (current_state == MM_PLAYER_STATE_NULL ||
447 current_state == MM_PLAYER_STATE_READY ||
448 current_state == MM_PLAYER_STATE_PAUSED ||
449 current_state == MM_PLAYER_STATE_PLAYING)
454 case MMPLAYER_COMMAND_DESTROY:
456 /* destroy can called anytime */
458 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
462 case MMPLAYER_COMMAND_REALIZE:
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
466 if (pending_state != MM_PLAYER_STATE_NONE) {
469 /* need ready state to realize */
470 if (current_state == MM_PLAYER_STATE_READY)
473 if (current_state != MM_PLAYER_STATE_NULL)
479 case MMPLAYER_COMMAND_UNREALIZE:
481 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
483 if (current_state == MM_PLAYER_STATE_NULL)
488 case MMPLAYER_COMMAND_START:
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PLAYING)
495 else if (current_state != MM_PLAYER_STATE_READY &&
496 current_state != MM_PLAYER_STATE_PAUSED)
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
501 LOGD("player is going to paused state, just change the pending state as playing");
508 case MMPLAYER_COMMAND_STOP:
510 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
512 if (current_state == MM_PLAYER_STATE_READY)
515 /* need playing/paused state to stop */
516 if (current_state != MM_PLAYER_STATE_PLAYING &&
517 current_state != MM_PLAYER_STATE_PAUSED)
522 case MMPLAYER_COMMAND_PAUSE:
524 if (MMPLAYER_IS_LIVE_STREAMING(player))
527 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
528 goto NOT_COMPLETED_SEEK;
530 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
532 if (pending_state == MM_PLAYER_STATE_NONE) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
535 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
537 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
539 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
540 if (current_state == MM_PLAYER_STATE_PAUSED)
541 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
548 case MMPLAYER_COMMAND_RESUME:
550 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
551 goto NOT_COMPLETED_SEEK;
553 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
555 if (pending_state == MM_PLAYER_STATE_NONE) {
556 if (current_state == MM_PLAYER_STATE_PLAYING)
558 else if (current_state != MM_PLAYER_STATE_PAUSED)
560 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
562 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
563 LOGD("player is going to paused state, just change the pending state as playing");
573 player->cmd = command;
575 return MM_ERROR_NONE;
578 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
579 MMPLAYER_STATE_GET_NAME(current_state), command);
580 return MM_ERROR_PLAYER_INVALID_STATE;
583 LOGW("not completed seek");
584 return MM_ERROR_PLAYER_DOING_SEEK;
587 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
592 return MM_ERROR_PLAYER_NO_OP;
596 __mmplayer_gapless_play_thread(gpointer data)
598 mm_player_t *player = (mm_player_t *)data;
599 MMPlayerGstElement *mainbin = NULL;
601 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
603 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
604 while (!player->gapless_play_thread_exit) {
605 LOGD("gapless play thread started. waiting for signal.");
606 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
608 LOGD("reconfigure pipeline for gapless play.");
610 if (player->gapless_play_thread_exit) {
611 if (player->gapless.reconfigure) {
612 player->gapless.reconfigure = false;
613 MMPLAYER_PLAYBACK_UNLOCK(player);
615 LOGD("exiting gapless play thread");
619 mainbin = player->pipeline->mainbin;
621 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
622 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
627 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
629 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
635 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
637 GSource *source = NULL;
641 source = g_main_context_find_source_by_id(context, source_id);
642 if (source != NULL) {
643 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
644 g_source_destroy(source);
651 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
653 mm_player_t *player = (mm_player_t *)hplayer;
654 GstMessage *msg = NULL;
655 GQueue *queue = NULL;
658 MMPLAYER_RETURN_IF_FAIL(player);
660 /* disconnecting bus watch */
661 if (player->bus_watcher)
662 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
663 player->bus_watcher = 0;
665 /* destroy the gst bus msg thread */
666 if (player->bus_msg_thread) {
667 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
668 player->bus_msg_thread_exit = TRUE;
669 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
670 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
672 LOGD("gst bus msg thread exit.");
673 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
674 player->bus_msg_thread = NULL;
676 g_mutex_clear(&player->bus_msg_thread_mutex);
677 g_cond_clear(&player->bus_msg_thread_cond);
680 g_mutex_lock(&player->bus_msg_q_lock);
681 queue = player->bus_msg_q;
682 while (!g_queue_is_empty(queue)) {
683 msg = (GstMessage *)g_queue_pop_head(queue);
688 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
689 gst_message_unref(msg);
691 g_mutex_unlock(&player->bus_msg_q_lock);
697 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
699 GstElement *parent = NULL;
701 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
703 /* if we have no fakesink. this meas we are using decodebin which doesn'
704 t need to add extra fakesink */
705 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
708 MMPLAYER_FSINK_LOCK(player);
713 /* get parent of fakesink */
714 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
716 LOGD("fakesink already removed");
720 gst_element_set_locked_state(fakesink->gst, TRUE);
722 /* setting the state to NULL never returns async
723 * so no need to wait for completion of state transiton
725 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
726 LOGE("fakesink state change failure!");
727 /* FIXIT : should I return here? or try to proceed to next? */
730 /* remove fakesink from it's parent */
731 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
732 LOGE("failed to remove fakesink");
734 gst_object_unref(parent);
739 gst_object_unref(parent);
741 LOGD("state-holder removed");
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
750 gst_element_set_locked_state(fakesink->gst, FALSE);
752 MMPLAYER_FSINK_UNLOCK(player);
756 static GstPadProbeReturn
757 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
759 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
760 return GST_PAD_PROBE_OK;
764 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
766 gint64 stop_running_time = 0;
767 gint64 position_running_time = 0;
771 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
772 if ((player->gapless.update_segment[idx] == TRUE) ||
773 !(player->selector[idx].event_probe_id)) {
774 /* LOGW("[%d] skip", idx); */
778 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
780 gst_segment_to_running_time(&player->gapless.segment[idx],
781 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
782 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
787 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->duration);
793 position_running_time =
794 gst_segment_to_running_time(&player->gapless.segment[idx],
795 GST_FORMAT_TIME, player->gapless.segment[idx].position);
797 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
798 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
800 GST_TIME_ARGS(stop_running_time),
801 GST_TIME_ARGS(position_running_time),
802 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
803 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
805 position_running_time = MAX(position_running_time, stop_running_time);
806 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
807 GST_FORMAT_TIME, player->gapless.segment[idx].start);
808 position_running_time = MAX(0, position_running_time);
809 position = MAX(position, position_running_time);
813 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
814 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
815 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
817 player->gapless.start_time[stream_type] += position;
823 static GstPadProbeReturn
824 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
826 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
827 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
828 mm_player_t *player = (mm_player_t *)data;
829 GstCaps *caps = NULL;
830 GstStructure *str = NULL;
831 const gchar *name = NULL;
832 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
833 gboolean caps_ret = TRUE;
835 if (GST_EVENT_IS_DOWNSTREAM(event) &&
836 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
837 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
838 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
839 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
841 } else if (GST_EVENT_IS_UPSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
846 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
850 if (strstr(name, "audio")) {
851 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
852 } else if (strstr(name, "video")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
855 /* text track is not supportable */
856 LOGE("invalid name %s", name);
860 switch (GST_EVENT_TYPE(event)) {
863 /* in case of gapless, drop eos event not to send it to sink */
864 if (player->gapless.reconfigure && !player->msg_posted) {
865 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
866 ret = GST_PAD_PROBE_DROP;
870 case GST_EVENT_STREAM_START:
872 __mmplayer_gst_selector_update_start_time(player, stream_type);
875 case GST_EVENT_FLUSH_STOP:
877 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
878 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
879 player->gapless.start_time[stream_type] = 0;
882 case GST_EVENT_SEGMENT:
887 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
888 gst_event_copy_segment(event, &segment);
890 if (segment.format != GST_FORMAT_TIME)
893 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
894 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
895 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
896 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
897 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
898 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
900 /* keep the all the segment ev to cover the seeking */
901 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
902 player->gapless.update_segment[stream_type] = TRUE;
904 if (!player->gapless.running)
907 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
909 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
911 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
912 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
913 gst_event_unref(event);
914 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
920 gdouble proportion = 0.0;
921 GstClockTimeDiff diff = 0;
922 GstClockTime timestamp = 0;
923 gint64 running_time_diff = -1;
925 GstEvent *tmpev = NULL;
927 running_time_diff = player->gapless.segment[stream_type].base;
929 if (running_time_diff <= 0) /* don't need to adjust */
932 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
933 gst_event_unref(event);
935 if (timestamp < running_time_diff) {
936 LOGW("QOS event from previous group");
937 ret = GST_PAD_PROBE_DROP;
941 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
942 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(timestamp),
944 GST_TIME_ARGS(running_time_diff),
945 GST_TIME_ARGS(timestamp - running_time_diff));
947 timestamp -= running_time_diff;
949 /* That case is invalid for QoS events */
950 if (diff < 0 && -diff > timestamp) {
951 LOGW("QOS event from previous group");
952 ret = GST_PAD_PROBE_DROP;
956 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
957 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
967 gst_caps_unref(caps);
971 /* create fakesink for audio or video path witout audiobin or videobin */
973 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
975 GstElement *pipeline = NULL;
976 GstElement *fakesink = NULL;
977 GstPad *sinkpad = NULL;
980 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
982 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
985 fakesink = gst_element_factory_make("fakesink", NULL);
986 if (fakesink == NULL) {
987 LOGE("failed to create fakesink");
991 /* store it as it's sink element */
992 __mmplayer_add_sink(player, fakesink);
994 gst_bin_add(GST_BIN(pipeline), fakesink);
997 sinkpad = gst_element_get_static_pad(fakesink, "sink");
999 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1001 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1002 LOGE("failed to link fakesink");
1003 gst_object_unref(GST_OBJECT(fakesink));
1007 if (strstr(name, "video")) {
1008 if (player->v_stream_caps) {
1009 gst_caps_unref(player->v_stream_caps);
1010 player->v_stream_caps = NULL;
1012 if (player->ini.set_dump_element_flag)
1013 __mmplayer_add_dump_buffer_probe(player, fakesink);
1016 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1017 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1021 gst_object_unref(GST_OBJECT(sinkpad));
1028 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1030 GstElement *pipeline = NULL;
1031 GstElement *selector = NULL;
1032 GstPad *srcpad = NULL;
1035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1037 selector = gst_element_factory_make("input-selector", NULL);
1039 LOGE("failed to create input-selector");
1042 g_object_set(selector, "sync-streams", TRUE, NULL);
1044 player->pipeline->mainbin[elem_idx].id = elem_idx;
1045 player->pipeline->mainbin[elem_idx].gst = selector;
1047 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1049 srcpad = gst_element_get_static_pad(selector, "src");
1051 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1052 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1053 __mmplayer_gst_selector_blocked, NULL, NULL);
1054 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1055 __mmplayer_gst_selector_event_probe, player, NULL);
1057 gst_element_set_state(selector, GST_STATE_PAUSED);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1060 gst_bin_add(GST_BIN(pipeline), selector);
1067 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1069 mm_player_t *player = (mm_player_t *)data;
1070 GstElement *selector = NULL;
1071 GstCaps *caps = NULL;
1072 GstStructure *str = NULL;
1073 const gchar *name = NULL;
1074 GstPad *sinkpad = NULL;
1075 gboolean first_track = FALSE;
1076 gboolean caps_ret = TRUE;
1078 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1079 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1082 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1083 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1085 LOGD("pad-added signal handling");
1087 /* get mimetype from caps */
1088 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1092 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1093 /* LOGD("detected mimetype : %s", name); */
1095 if (strstr(name, "video")) {
1097 gchar *caps_str = NULL;
1099 caps_str = gst_caps_to_string(caps);
1100 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1101 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1102 player->set_mode.video_zc = true;
1104 MMPLAYER_FREEIF(caps_str);
1106 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1107 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1109 LOGD("surface type : %d", stype);
1111 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1112 __mmplayer_gst_create_sinkbin(elem, pad, player);
1116 /* in case of exporting video frame, it requires the 360 video filter.
1117 * it will be handled in _no_more_pads(). */
1118 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1119 __mmplayer_gst_make_fakesink(player, pad, name);
1123 LOGD("video selector is required");
1124 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1125 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1126 } else if (strstr(name, "audio")) {
1127 gint samplerate = 0;
1130 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1131 if (player->build_audio_offload)
1132 player->no_more_pad = TRUE; /* remove state holder */
1133 __mmplayer_gst_create_sinkbin(elem, pad, player);
1137 gst_structure_get_int(str, "rate", &samplerate);
1138 gst_structure_get_int(str, "channels", &channels);
1140 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1141 __mmplayer_gst_make_fakesink(player, pad, name);
1145 LOGD("audio selector is required");
1146 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1147 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1149 } else if (strstr(name, "text")) {
1150 LOGD("text selector is required");
1151 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1152 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1154 LOGE("invalid caps info");
1158 /* check selector and create it */
1159 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1160 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1165 LOGD("input-selector is already created.");
1169 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1171 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1173 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1174 LOGE("failed to link selector");
1175 gst_object_unref(GST_OBJECT(selector));
1180 LOGD("this track will be activated");
1181 g_object_set(selector, "active-pad", sinkpad, NULL);
1184 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1190 gst_caps_unref(caps);
1193 gst_object_unref(GST_OBJECT(sinkpad));
1201 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1203 GstPad *srcpad = NULL;
1206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1208 LOGD("type %d", type);
1211 LOGD("there is no %d track", type);
1215 srcpad = gst_element_get_static_pad(selector, "src");
1217 LOGE("failed to get srcpad from selector");
1221 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1223 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1225 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1226 if (player->selector[type].block_id) {
1227 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1228 player->selector[type].block_id = 0;
1232 gst_object_unref(GST_OBJECT(srcpad));
1241 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1243 MMHandleType attrs = 0;
1244 gint active_index = 0;
1247 MMPLAYER_RETURN_IF_FAIL(player);
1249 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1251 /* change track to active pad */
1252 active_index = player->selector[type].active_pad_index;
1253 if ((active_index != DEFAULT_TRACK) &&
1254 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1255 LOGW("failed to change %d type track to %d", type, active_index);
1256 player->selector[type].active_pad_index = DEFAULT_TRACK;
1260 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1261 attrs = MMPLAYER_GET_ATTRS(player);
1263 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1264 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1266 if (mm_attrs_commit_all(attrs))
1267 LOGW("failed to commit attrs.");
1269 LOGW("cannot get content attribute");
1278 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1281 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1283 if (!audio_selector) {
1284 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1286 /* in case the source is changed, output can be changed. */
1287 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1288 LOGD("remove previous audiobin if it exist");
1290 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1291 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1293 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1294 MMPLAYER_FREEIF(player->pipeline->audiobin);
1297 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1298 __mmplayer_pipeline_complete(NULL, player);
1303 /* apply the audio track information */
1304 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1306 /* create audio sink path */
1307 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1308 LOGE("failed to create audio sink path");
1317 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1320 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1322 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1323 LOGD("text path is not supproted");
1327 /* apply the text track information */
1328 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1330 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1331 player->has_closed_caption = TRUE;
1333 /* create text decode path */
1334 player->no_more_pad = TRUE;
1336 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1337 LOGE("failed to create text sink path");
1346 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1348 gint64 dur_bytes = 0L;
1351 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1352 player->pipeline->mainbin && player->streamer, FALSE);
1354 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1355 LOGE("fail to get duration.");
1357 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1358 * use file information was already set on Q2 when it was created. */
1359 __mm_player_streaming_set_queue2(player->streamer,
1360 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1361 TRUE, /* use_buffering */
1362 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1363 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1370 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1372 mm_player_t *player = NULL;
1373 GstElement *video_selector = NULL;
1374 GstElement *audio_selector = NULL;
1375 GstElement *text_selector = NULL;
1378 player = (mm_player_t *)data;
1380 LOGD("no-more-pad signal handling");
1382 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1383 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1384 LOGW("player is shutting down");
1388 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1389 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1390 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1391 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1392 LOGE("failed to set queue2 buffering");
1397 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1398 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1399 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1401 if (!video_selector && !audio_selector && !text_selector) {
1402 LOGW("there is no selector");
1403 player->no_more_pad = TRUE;
1407 /* create video path followed by video-select */
1408 if (video_selector && !audio_selector && !text_selector)
1409 player->no_more_pad = TRUE;
1411 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1414 /* create audio path followed by audio-select */
1415 if (audio_selector && !text_selector)
1416 player->no_more_pad = TRUE;
1418 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1421 /* create text path followed by text-select */
1422 __mmplayer_create_text_sink_path(player, text_selector);
1425 if (player->gapless.reconfigure) {
1426 player->gapless.reconfigure = FALSE;
1427 MMPLAYER_PLAYBACK_UNLOCK(player);
1434 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1436 gboolean ret = FALSE;
1437 GstElement *pipeline = NULL;
1438 GstPad *sinkpad = NULL;
1441 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1444 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1446 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1448 LOGE("failed to get pad from sinkbin");
1454 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1455 LOGE("failed to link sinkbin for reusing");
1456 goto EXIT; /* exit either pass or fail */
1460 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1461 LOGE("failed to set state(READY) to sinkbin");
1466 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1467 LOGE("failed to add sinkbin to pipeline");
1472 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1473 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1478 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1479 LOGE("failed to set state(PAUSED) to sinkbin");
1488 gst_object_unref(GST_OBJECT(sinkpad));
1496 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t *player = NULL;
1499 GstCaps *caps = NULL;
1500 gchar *caps_str = NULL;
1501 GstStructure *str = NULL;
1502 const gchar *name = NULL;
1503 GstElement *sinkbin = NULL;
1504 gboolean reusing = FALSE;
1505 gboolean caps_ret = TRUE;
1506 gchar *sink_pad_name = "sink";
1509 player = (mm_player_t *)data;
1512 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1513 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1515 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1519 caps_str = gst_caps_to_string(caps);
1521 /* LOGD("detected mimetype : %s", name); */
1522 if (strstr(name, "audio")) {
1523 if (player->pipeline->audiobin == NULL) {
1524 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1525 LOGE("failed to create audiobin. continuing without audio");
1529 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1530 LOGD("creating audiobin success");
1533 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1534 LOGD("reusing audiobin");
1535 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1537 } else if (strstr(name, "video")) {
1538 /* 1. zero copy is updated at _decode_pad_added()
1539 * 2. NULL surface type is handled in _decode_pad_added() */
1540 LOGD("zero copy %d", player->set_mode.video_zc);
1541 if (player->pipeline->videobin == NULL) {
1542 int surface_type = 0;
1543 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1544 LOGD("display_surface_type (%d)", surface_type);
1546 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1547 LOGD("mark video overlay for acquire");
1548 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1549 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1550 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1551 &player->video_overlay_resource)
1552 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1553 LOGE("could not mark video_overlay resource for acquire");
1558 player->interrupted_by_resource = FALSE;
1560 if (mm_resource_manager_commit(player->resource_manager) !=
1561 MM_RESOURCE_MANAGER_ERROR_NONE) {
1562 LOGE("could not acquire resources for video playing");
1566 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1567 LOGE("failed to create videobin. continuing without video");
1571 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1572 LOGD("creating videosink bin success");
1575 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1576 LOGD("re-using videobin");
1577 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1579 } else if (strstr(name, "text")) {
1580 if (player->pipeline->textbin == NULL) {
1581 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1582 LOGE("failed to create text sink bin. continuing without text");
1586 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1587 player->textsink_linked = 1;
1588 LOGD("creating textsink bin success");
1590 if (!player->textsink_linked) {
1591 LOGD("re-using textbin");
1593 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1594 player->textsink_linked = 1;
1596 /* linked textbin exist which means that the external subtitle path exist already */
1597 LOGW("ignoring internal subtutle since external subtitle is available");
1600 sink_pad_name = "text_sink";
1602 LOGW("unknown mime type %s, ignoring it", name);
1606 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1609 LOGD("[handle: %p] success to create and link sink bin", player);
1611 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1612 * streaming task. if the task blocked, then buffer will not flow to the next element
1613 *(autoplugging element). so this is special hack for streaming. please try to remove it
1615 /* dec stream count. we can remove fakesink if it's zero */
1616 if (player->num_dynamic_pad)
1617 player->num_dynamic_pad--;
1619 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1621 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1622 __mmplayer_pipeline_complete(NULL, player);
1626 MMPLAYER_FREEIF(caps_str);
1629 gst_caps_unref(caps);
1635 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1637 int required_angle = 0; /* Angle required for straight view */
1638 int rotation_angle = 0;
1640 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1641 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1643 /* Counter clockwise */
1644 switch (orientation) {
1649 required_angle = 270;
1652 required_angle = 180;
1655 required_angle = 90;
1659 rotation_angle = display_angle + required_angle;
1660 if (rotation_angle >= 360)
1661 rotation_angle -= 360;
1663 /* chech if supported or not */
1664 if (rotation_angle % 90) {
1665 LOGD("not supported rotation angle = %d", rotation_angle);
1669 switch (rotation_angle) {
1671 *value = MM_DISPLAY_ROTATION_NONE;
1674 *value = MM_DISPLAY_ROTATION_90;
1677 *value = MM_DISPLAY_ROTATION_180;
1680 *value = MM_DISPLAY_ROTATION_270;
1684 LOGD("setting rotation property value : %d", *value);
1690 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1692 /* check video sinkbin is created */
1693 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1695 player->pipeline->videobin &&
1696 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1697 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1698 MM_ERROR_PLAYER_NOT_INITIALIZED);
1700 return MM_ERROR_NONE;
1704 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1706 int display_rotation = 0;
1707 gchar *org_orient = NULL;
1708 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1711 LOGE("cannot get content attribute");
1712 return MM_ERROR_PLAYER_INTERNAL;
1715 if (display_angle) {
1716 /* update user roation */
1717 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1719 /* Counter clockwise */
1720 switch (display_rotation) {
1721 case MM_DISPLAY_ROTATION_NONE:
1724 case MM_DISPLAY_ROTATION_90:
1725 *display_angle = 90;
1727 case MM_DISPLAY_ROTATION_180:
1728 *display_angle = 180;
1730 case MM_DISPLAY_ROTATION_270:
1731 *display_angle = 270;
1734 LOGW("wrong angle type : %d", display_rotation);
1737 LOGD("check user angle: %d", *display_angle);
1741 /* Counter clockwise */
1742 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1745 if (!strcmp(org_orient, "rotate-90"))
1747 else if (!strcmp(org_orient, "rotate-180"))
1749 else if (!strcmp(org_orient, "rotate-270"))
1752 LOGD("original rotation is %s", org_orient);
1754 LOGD("content_video_orientation get fail");
1757 LOGD("check orientation: %d", *orientation);
1760 return MM_ERROR_NONE;
1764 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1766 int rotation_value = 0;
1767 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1768 int display_angle = 0;
1771 /* check video sinkbin is created */
1772 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1775 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1777 /* get rotation value to set */
1778 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1779 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1780 LOGD("set video param : rotate %d", rotation_value);
1784 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1786 MMHandleType attrs = 0;
1790 /* check video sinkbin is created */
1791 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1794 attrs = MMPLAYER_GET_ATTRS(player);
1795 MMPLAYER_RETURN_IF_FAIL(attrs);
1797 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1798 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1799 LOGD("set video param : visible %d", visible);
1803 __mmplayer_video_param_set_display_method(mm_player_t *player)
1805 MMHandleType attrs = 0;
1806 int display_method = 0;
1809 /* check video sinkbin is created */
1810 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1813 attrs = MMPLAYER_GET_ATTRS(player);
1814 MMPLAYER_RETURN_IF_FAIL(attrs);
1816 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1817 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1818 LOGD("set video param : method %d", display_method);
1822 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1824 MMHandleType attrs = 0;
1825 void *handle = NULL;
1828 /* check video sinkbin is created */
1829 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1830 LOGW("There is no video sink");
1834 attrs = MMPLAYER_GET_ATTRS(player);
1835 MMPLAYER_RETURN_IF_FAIL(attrs);
1836 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1838 gst_video_overlay_set_video_roi_area(
1839 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1840 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1841 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1842 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1847 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1849 MMHandleType attrs = 0;
1850 void *handle = NULL;
1854 int win_roi_width = 0;
1855 int win_roi_height = 0;
1858 /* check video sinkbin is created */
1859 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1860 LOGW("There is no video sink");
1864 attrs = MMPLAYER_GET_ATTRS(player);
1865 MMPLAYER_RETURN_IF_FAIL(attrs);
1867 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1870 /* It should be set after setting window */
1871 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1872 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1873 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1874 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1876 /* After setting window handle, set display roi area */
1877 gst_video_overlay_set_display_roi_area(
1878 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1879 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1880 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1881 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1886 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1888 MMHandleType attrs = 0;
1889 void *handle = NULL;
1891 /* check video sinkbin is created */
1892 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1895 attrs = MMPLAYER_GET_ATTRS(player);
1896 MMPLAYER_RETURN_IF_FAIL(attrs);
1898 /* common case if using overlay surface */
1899 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1902 /* default is using wl_surface_id */
1903 unsigned int wl_surface_id = 0;
1904 wl_surface_id = *(int *)handle;
1905 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1906 gst_video_overlay_set_wl_window_wl_surface_id(
1907 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1910 /* FIXIT : is it error case? */
1911 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1916 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1918 gboolean update_all_param = FALSE;
1921 /* check video sinkbin is created */
1922 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1923 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1925 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1926 LOGE("can not find tizenwlsink");
1927 return MM_ERROR_PLAYER_INTERNAL;
1930 LOGD("param_name : %s", param_name);
1931 if (!g_strcmp0(param_name, "update_all_param"))
1932 update_all_param = TRUE;
1934 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1935 __mmplayer_video_param_set_display_overlay(player);
1936 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1937 __mmplayer_video_param_set_display_method(player);
1938 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1939 __mmplayer_video_param_set_display_visible(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1941 __mmplayer_video_param_set_display_rotation(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1943 __mmplayer_video_param_set_roi_area(player);
1944 if (update_all_param)
1945 __mmplayer_video_param_set_video_roi_area(player);
1947 return MM_ERROR_NONE;
1951 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1953 MMHandleType attrs = 0;
1954 int surface_type = 0;
1955 int ret = MM_ERROR_NONE;
1959 /* check video sinkbin is created */
1960 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1961 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1963 attrs = MMPLAYER_GET_ATTRS(player);
1965 LOGE("cannot get content attribute");
1966 return MM_ERROR_PLAYER_INTERNAL;
1968 LOGD("param_name : %s", param_name);
1970 /* update display surface */
1971 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1972 LOGD("check display surface type attribute: %d", surface_type);
1974 /* configuring display */
1975 switch (surface_type) {
1976 case MM_DISPLAY_SURFACE_OVERLAY:
1978 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1979 if (ret != MM_ERROR_NONE)
1987 return MM_ERROR_NONE;
1991 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1993 gboolean disable_overlay = FALSE;
1994 mm_player_t *player = (mm_player_t *)hplayer;
1995 int ret = MM_ERROR_NONE;
1998 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1999 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2000 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2001 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2003 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2004 LOGW("Display control is not supported");
2005 return MM_ERROR_PLAYER_INTERNAL;
2008 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2010 if (audio_only == (bool)disable_overlay) {
2011 LOGE("It's the same with current setting: (%d)", audio_only);
2012 return MM_ERROR_NONE;
2016 LOGE("disable overlay");
2017 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2019 /* release overlay resource */
2020 if (player->video_overlay_resource != NULL) {
2021 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2022 player->video_overlay_resource);
2023 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2024 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2027 player->video_overlay_resource = NULL;
2030 ret = mm_resource_manager_commit(player->resource_manager);
2031 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2032 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2036 /* mark video overlay for acquire */
2037 if (player->video_overlay_resource == NULL) {
2038 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2039 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2040 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2041 &player->video_overlay_resource);
2042 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2043 LOGE("could not prepare for video_overlay resource");
2048 player->interrupted_by_resource = FALSE;
2049 /* acquire resources for video overlay */
2050 ret = mm_resource_manager_commit(player->resource_manager);
2051 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2052 LOGE("could not acquire resources for video playing");
2056 LOGD("enable overlay");
2057 __mmplayer_video_param_set_display_overlay(player);
2058 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2063 return MM_ERROR_NONE;
2067 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2069 mm_player_t *player = (mm_player_t *)hplayer;
2070 gboolean disable_overlay = FALSE;
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2075 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2077 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2078 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2080 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2081 LOGW("Display control is not supported");
2082 return MM_ERROR_PLAYER_INTERNAL;
2085 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2087 *paudio_only = (bool)disable_overlay;
2089 LOGD("audio_only : %d", *paudio_only);
2093 return MM_ERROR_NONE;
2097 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2099 GList *bucket = element_bucket;
2100 MMPlayerGstElement *element = NULL;
2101 MMPlayerGstElement *prv_element = NULL;
2102 gint successful_link_count = 0;
2106 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2108 prv_element = (MMPlayerGstElement *)bucket->data;
2109 bucket = bucket->next;
2111 for (; bucket; bucket = bucket->next) {
2112 element = (MMPlayerGstElement *)bucket->data;
2114 if (element && element->gst) {
2115 if (prv_element && prv_element->gst) {
2116 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2117 LOGD("linking [%s] to [%s] success",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2120 successful_link_count++;
2122 LOGD("linking [%s] to [%s] failed",
2123 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2124 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2130 prv_element = element;
2135 return successful_link_count;
2139 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2141 GList *bucket = element_bucket;
2142 MMPlayerGstElement *element = NULL;
2143 int successful_add_count = 0;
2147 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2148 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2150 for (; bucket; bucket = bucket->next) {
2151 element = (MMPlayerGstElement *)bucket->data;
2153 if (element && element->gst) {
2154 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2155 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2156 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2157 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2160 successful_add_count++;
2166 return successful_add_count;
2170 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2172 mm_player_t *player = (mm_player_t *)data;
2173 GstCaps *caps = NULL;
2174 GstStructure *str = NULL;
2176 gboolean caps_ret = TRUE;
2180 MMPLAYER_RETURN_IF_FAIL(pad);
2181 MMPLAYER_RETURN_IF_FAIL(unused);
2182 MMPLAYER_RETURN_IF_FAIL(data);
2184 caps = gst_pad_get_current_caps(pad);
2188 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2192 LOGD("name = %s", name);
2194 if (strstr(name, "audio")) {
2195 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2197 if (player->audio_stream_changed_cb) {
2198 LOGE("call the audio stream changed cb");
2199 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2201 } else if (strstr(name, "video")) {
2202 if ((name = gst_structure_get_string(str, "format")))
2203 player->set_mode.video_zc = name[0] == 'S';
2205 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2207 if (player->video_stream_changed_cb) {
2208 LOGE("call the video stream changed cb");
2209 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2212 LOGW("invalid caps info");
2217 gst_caps_unref(caps);
2225 * This function is to create audio pipeline for playing.
2227 * @param player [in] handle of player
2229 * @return This function returns zero on success.
2231 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2233 /* macro for code readability. just for sinkbin-creation functions */
2234 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2236 x_bin[x_id].id = x_id;\
2237 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2238 if (!x_bin[x_id].gst) {\
2239 LOGE("failed to create %s", x_factory);\
2242 if (x_player->ini.set_dump_element_flag)\
2243 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2246 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2250 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2255 MMPLAYER_RETURN_IF_FAIL(player);
2257 if (player->audio_stream_buff_list) {
2258 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2259 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2262 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2263 __mmplayer_audio_stream_send_data(player, tmp);
2265 MMPLAYER_FREEIF(tmp->pcm_data);
2266 MMPLAYER_FREEIF(tmp);
2269 g_list_free(player->audio_stream_buff_list);
2270 player->audio_stream_buff_list = NULL;
2277 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2279 MMPlayerAudioStreamDataType audio_stream = { 0, };
2282 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2284 audio_stream.bitrate = a_buffer->bitrate;
2285 audio_stream.channel = a_buffer->channel;
2286 audio_stream.depth = a_buffer->depth;
2287 audio_stream.is_little_endian = a_buffer->is_little_endian;
2288 audio_stream.channel_mask = a_buffer->channel_mask;
2289 audio_stream.data_size = a_buffer->data_size;
2290 audio_stream.data = a_buffer->pcm_data;
2292 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2293 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2299 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2301 mm_player_t *player = (mm_player_t *)data;
2305 gint endianness = 0;
2306 guint64 channel_mask = 0;
2307 void *a_data = NULL;
2309 mm_player_audio_stream_buff_t *a_buffer = NULL;
2310 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2314 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2316 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2317 a_data = mapinfo.data;
2318 a_size = mapinfo.size;
2320 GstCaps *caps = gst_pad_get_current_caps(pad);
2321 GstStructure *structure = gst_caps_get_structure(caps, 0);
2323 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2324 gst_structure_get_int(structure, "rate", &rate);
2325 gst_structure_get_int(structure, "channels", &channel);
2326 gst_structure_get_int(structure, "depth", &depth);
2327 gst_structure_get_int(structure, "endianness", &endianness);
2328 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2329 gst_caps_unref(GST_CAPS(caps));
2331 /* In case of the sync is false, use buffer list. *
2332 * The num of buffer list depends on the num of audio channels */
2333 if (player->audio_stream_buff_list) {
2334 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2335 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2337 if (channel_mask == tmp->channel_mask) {
2338 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2339 if (tmp->data_size + a_size < tmp->buff_size) {
2340 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2341 tmp->data_size += a_size;
2343 /* send data to client */
2344 __mmplayer_audio_stream_send_data(player, tmp);
2346 if (a_size > tmp->buff_size) {
2347 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2348 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2349 if (tmp->pcm_data == NULL) {
2350 LOGE("failed to realloc data.");
2353 tmp->buff_size = a_size;
2355 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2356 memcpy(tmp->pcm_data, a_data, a_size);
2357 tmp->data_size = a_size;
2362 LOGE("data is empty in list.");
2368 /* create new audio stream data */
2369 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2370 if (a_buffer == NULL) {
2371 LOGE("failed to alloc data.");
2374 a_buffer->bitrate = rate;
2375 a_buffer->channel = channel;
2376 a_buffer->depth = depth;
2377 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2378 a_buffer->channel_mask = channel_mask;
2379 a_buffer->data_size = a_size;
2381 if (!player->audio_stream_sink_sync) {
2382 /* If sync is FALSE, use buffer list to reduce the IPC. */
2383 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2384 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2385 if (a_buffer->pcm_data == NULL) {
2386 LOGE("failed to alloc data.");
2387 MMPLAYER_FREEIF(a_buffer);
2390 memcpy(a_buffer->pcm_data, a_data, a_size);
2391 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2392 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2394 /* If sync is TRUE, send data directly. */
2395 a_buffer->pcm_data = a_data;
2396 __mmplayer_audio_stream_send_data(player, a_buffer);
2397 MMPLAYER_FREEIF(a_buffer);
2401 gst_buffer_unmap(buffer, &mapinfo);
2406 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2408 mm_player_t *player = (mm_player_t *)data;
2409 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2410 GstPad *sinkpad = NULL;
2411 GstElement *queue = NULL, *sink = NULL;
2414 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2416 queue = gst_element_factory_make("queue", NULL);
2417 if (queue == NULL) {
2418 LOGD("fail make queue");
2422 sink = gst_element_factory_make("fakesink", NULL);
2424 LOGD("fail make fakesink");
2428 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2430 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2431 LOGW("failed to link queue & sink");
2435 sinkpad = gst_element_get_static_pad(queue, "sink");
2437 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2438 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2442 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2444 gst_object_unref(sinkpad);
2445 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2446 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2448 gst_element_set_state(sink, GST_STATE_PAUSED);
2449 gst_element_set_state(queue, GST_STATE_PAUSED);
2451 __mmplayer_add_signal_connection(player,
2453 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2455 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2462 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2464 gst_object_unref(GST_OBJECT(queue));
2468 gst_object_unref(GST_OBJECT(sink));
2472 gst_object_unref(GST_OBJECT(sinkpad));
2480 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2482 #define MAX_PROPS_LEN 128
2483 gint latency_mode = 0;
2484 gchar *stream_type = NULL;
2485 gchar *latency = NULL;
2487 gchar stream_props[MAX_PROPS_LEN] = {0,};
2488 GstStructure *props = NULL;
2491 * It should be set after player creation through attribute.
2492 * But, it can not be changed during playing.
2495 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2497 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2498 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2501 LOGE("stream_type is null.");
2503 if (player->sound.focus_id)
2504 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2505 stream_type, stream_id, player->sound.focus_id);
2507 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2508 stream_type, stream_id);
2509 props = gst_structure_from_string(stream_props, NULL);
2510 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2511 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2512 stream_type, stream_id, player->sound.focus_id, stream_props);
2513 gst_structure_free(props);
2516 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2518 switch (latency_mode) {
2519 case AUDIO_LATENCY_MODE_LOW:
2520 latency = g_strndup("low", 3);
2522 case AUDIO_LATENCY_MODE_MID:
2523 latency = g_strndup("mid", 3);
2525 case AUDIO_LATENCY_MODE_HIGH:
2526 latency = g_strndup("high", 4);
2530 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2534 LOGD("audiosink property - latency=%s", latency);
2536 MMPLAYER_FREEIF(latency);
2542 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2544 MMPlayerGstElement *audiobin = NULL;
2547 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2549 audiobin = player->pipeline->audiobin;
2551 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2552 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2555 if (player->video360_yaw_radians <= M_PI &&
2556 player->video360_yaw_radians >= -M_PI &&
2557 player->video360_pitch_radians <= M_PI_2 &&
2558 player->video360_pitch_radians >= -M_PI_2) {
2559 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2560 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2561 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2562 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", player->video360_metadata.init_view_heading,
2565 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2572 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2574 MMPlayerGstElement *audiobin = NULL;
2575 MMHandleType attrs = 0;
2576 GList *element_bucket = NULL;
2577 GstCaps *acaps = NULL;
2578 GstPad *sink_pad = NULL;
2579 int pitch_control = 0;
2580 double pitch_value = 1.0;
2583 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2584 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2586 audiobin = player->pipeline->audiobin;
2587 attrs = MMPLAYER_GET_ATTRS(player);
2589 if (player->build_audio_offload) { /* skip all the audio filters */
2590 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2591 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2593 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2598 mm_attrs_multiple_get(player->attrs, NULL,
2599 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2600 MM_PLAYER_PITCH_VALUE, &pitch_value,
2603 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2604 if (pitch_control && (player->videodec_linked == 0)) {
2605 GstElementFactory *factory;
2607 factory = gst_element_factory_find("pitch");
2609 gst_object_unref(factory);
2612 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2615 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2616 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2618 LOGW("there is no pitch element");
2623 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2625 /* replaygain volume */
2626 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2627 if (player->sound.rg_enable)
2628 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2630 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2635 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2636 gchar *dst_format = NULL;
2638 int dst_samplerate = 0;
2639 int dst_channels = 0;
2640 GstCaps *caps = NULL;
2641 char *caps_str = NULL;
2643 /* get conf. values */
2644 mm_attrs_multiple_get(player->attrs, NULL,
2645 "pcm_audioformat", &dst_format, &dst_len,
2646 "pcm_extraction_samplerate", &dst_samplerate,
2647 "pcm_extraction_channels", &dst_channels,
2650 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2654 caps = gst_caps_new_simple("audio/x-raw",
2655 "format", G_TYPE_STRING, dst_format,
2656 "rate", G_TYPE_INT, dst_samplerate,
2657 "channels", G_TYPE_INT, dst_channels,
2660 caps_str = gst_caps_to_string(caps);
2661 LOGD("new caps : %s", caps_str);
2663 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2666 gst_caps_unref(caps);
2667 MMPLAYER_FREEIF(caps_str);
2669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2671 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2673 /* raw pad handling signal, audiosink will be added after getting signal */
2674 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2675 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2679 /* normal playback */
2682 /* for logical volume control */
2683 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2686 if (player->sound.mute) {
2687 LOGD("mute enabled");
2688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2691 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2693 /* audio effect element. if audio effect is enabled */
2694 if ((strcmp(player->ini.audioeffect_element, ""))
2696 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2697 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2699 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2701 if ((!player->bypass_audio_effect)
2702 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2703 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2704 if (!_mmplayer_audio_effect_custom_apply(player))
2705 LOGI("apply audio effect(custom) setting success");
2709 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2710 && (player->set_mode.rich_audio))
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2714 /* create audio sink */
2715 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2716 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2717 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2719 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2720 if (player->is_360_feature_enabled &&
2721 player->is_content_spherical &&
2723 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2724 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2725 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2727 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2729 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2732 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2734 gst_caps_unref(acaps);
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2738 player->is_openal_plugin_used = TRUE;
2740 if (player->is_360_feature_enabled && player->is_content_spherical)
2741 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2745 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2746 (player->videodec_linked && player->ini.use_system_clock)) {
2747 LOGD("system clock will be used.");
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2751 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2752 __mmplayer_gst_set_pulsesink_property(player, attrs);
2753 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2754 __mmplayer_gst_set_openalsink_property(player);
2757 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2758 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2760 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2761 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2762 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2763 gst_object_unref(GST_OBJECT(sink_pad));
2765 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2769 *bucket = element_bucket;
2772 return MM_ERROR_NONE;
2775 g_list_free(element_bucket);
2779 return MM_ERROR_PLAYER_INTERNAL;
2783 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2785 MMPlayerGstElement *first_element = NULL;
2786 MMPlayerGstElement *audiobin = NULL;
2788 GstPad *ghostpad = NULL;
2789 GList *element_bucket = NULL;
2793 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2796 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2798 LOGE("failed to allocate memory for audiobin");
2799 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2803 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2804 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2805 if (!audiobin[MMPLAYER_A_BIN].gst) {
2806 LOGE("failed to create audiobin");
2811 player->pipeline->audiobin = audiobin;
2813 /* create audio filters and audiosink */
2814 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2817 /* adding created elements to bin */
2818 LOGD("adding created elements to bin");
2819 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2822 /* linking elements in the bucket by added order. */
2823 LOGD("Linking elements in the bucket by added order.");
2824 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2827 /* get first element's sinkpad for creating ghostpad */
2828 first_element = (MMPlayerGstElement *)element_bucket->data;
2829 if (!first_element) {
2830 LOGE("failed to get first elem");
2834 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2836 LOGE("failed to get pad from first element of audiobin");
2840 ghostpad = gst_ghost_pad_new("sink", pad);
2842 LOGE("failed to create ghostpad");
2846 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2847 LOGE("failed to add ghostpad to audiobin");
2851 gst_object_unref(pad);
2853 g_list_free(element_bucket);
2856 return MM_ERROR_NONE;
2859 LOGD("ERROR : releasing audiobin");
2862 gst_object_unref(GST_OBJECT(pad));
2865 gst_object_unref(GST_OBJECT(ghostpad));
2868 g_list_free(element_bucket);
2870 /* release element which are not added to bin */
2871 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2872 /* NOTE : skip bin */
2873 if (audiobin[i].gst) {
2874 GstObject *parent = NULL;
2875 parent = gst_element_get_parent(audiobin[i].gst);
2878 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2879 audiobin[i].gst = NULL;
2881 gst_object_unref(GST_OBJECT(parent));
2885 /* release audiobin with it's childs */
2886 if (audiobin[MMPLAYER_A_BIN].gst)
2887 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2889 MMPLAYER_FREEIF(audiobin);
2891 player->pipeline->audiobin = NULL;
2893 return MM_ERROR_PLAYER_INTERNAL;
2897 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2899 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2903 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2905 int ret = MM_ERROR_NONE;
2907 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2908 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2910 MMPLAYER_VIDEO_BO_LOCK(player);
2912 if (player->video_bo_list) {
2913 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2914 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2915 if (tmp && tmp->bo == bo) {
2917 LOGD("release bo %p", bo);
2918 tbm_bo_unref(tmp->bo);
2919 MMPLAYER_VIDEO_BO_UNLOCK(player);
2920 MMPLAYER_VIDEO_BO_SIGNAL(player);
2925 /* hw codec is running or the list was reset for DRC. */
2926 LOGW("there is no bo list.");
2928 MMPLAYER_VIDEO_BO_UNLOCK(player);
2930 LOGW("failed to find bo %p", bo);
2935 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2940 MMPLAYER_RETURN_IF_FAIL(player);
2942 MMPLAYER_VIDEO_BO_LOCK(player);
2943 if (player->video_bo_list) {
2944 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2945 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2946 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2949 tbm_bo_unref(tmp->bo);
2953 g_list_free(player->video_bo_list);
2954 player->video_bo_list = NULL;
2956 player->video_bo_size = 0;
2957 MMPLAYER_VIDEO_BO_UNLOCK(player);
2964 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2967 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2968 gboolean ret = TRUE;
2970 /* check DRC, if it is, destroy the prev bo list to create again */
2971 if (player->video_bo_size != size) {
2972 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2973 __mmplayer_video_stream_destroy_bo_list(player);
2974 player->video_bo_size = size;
2977 MMPLAYER_VIDEO_BO_LOCK(player);
2979 if ((!player->video_bo_list) ||
2980 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2982 /* create bo list */
2984 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2986 if (player->video_bo_list) {
2987 /* if bo list did not created all, try it again. */
2988 idx = g_list_length(player->video_bo_list);
2989 LOGD("bo list exist(len: %d)", idx);
2992 for (; idx < player->ini.num_of_video_bo; idx++) {
2993 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2995 LOGE("Fail to alloc bo_info.");
2998 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3000 LOGE("Fail to tbm_bo_alloc.");
3001 MMPLAYER_FREEIF(bo_info);
3004 bo_info->used = FALSE;
3005 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3008 /* update video num buffers */
3009 player->video_num_buffers = idx;
3010 if (idx == player->ini.num_of_video_bo)
3011 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3014 MMPLAYER_VIDEO_BO_UNLOCK(player);
3018 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3022 /* get bo from list*/
3023 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3024 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3025 if (tmp && (tmp->used == FALSE)) {
3026 LOGD("found bo %p to use", tmp->bo);
3028 MMPLAYER_VIDEO_BO_UNLOCK(player);
3029 return tbm_bo_ref(tmp->bo);
3033 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3034 MMPLAYER_VIDEO_BO_UNLOCK(player);
3038 if (player->ini.video_bo_timeout <= 0) {
3039 MMPLAYER_VIDEO_BO_WAIT(player);
3041 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3042 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3049 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3051 mm_player_t *player = (mm_player_t *)data;
3053 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3055 /* send prerolled pkt */
3056 player->video_stream_prerolled = false;
3058 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3060 /* not to send prerolled pkt again */
3061 player->video_stream_prerolled = true;
3065 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3067 mm_player_t *player = (mm_player_t *)data;
3068 MMPlayerVideoStreamDataType *stream = NULL;
3069 GstMemory *mem = NULL;
3072 MMPLAYER_RETURN_IF_FAIL(player);
3073 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3075 if (player->video_stream_prerolled) {
3076 player->video_stream_prerolled = false;
3077 LOGD("skip the prerolled pkt not to send it again");
3081 /* clear stream data structure */
3082 stream = __mmplayer_create_stream_from_pad(pad);
3084 LOGE("failed to alloc stream");
3088 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3090 /* set size and timestamp */
3091 mem = gst_buffer_peek_memory(buffer, 0);
3092 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3093 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3095 /* check zero-copy */
3096 if (player->set_mode.video_zc &&
3097 player->set_mode.media_packet_video_stream &&
3098 gst_is_tizen_memory(mem)) {
3099 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3100 stream->internal_buffer = gst_buffer_ref(buffer);
3101 } else { /* sw codec */
3102 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3105 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3109 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3110 LOGE("failed to send video stream data.");
3117 LOGE("release video stream resource.");
3118 if (gst_is_tizen_memory(mem)) {
3120 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3122 tbm_bo_unref(stream->bo[i]);
3125 /* unref gst buffer */
3126 if (stream->internal_buffer)
3127 gst_buffer_unref(stream->internal_buffer);
3130 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3132 MMPLAYER_FREEIF(stream);
3137 __mmplayer_gst_set_video360_property(mm_player_t *player)
3139 MMPlayerGstElement *videobin = NULL;
3142 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3144 videobin = player->pipeline->videobin;
3146 /* Set spatial media metadata and/or user settings to the element.
3148 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3149 "projection-type", player->video360_metadata.projection_type, NULL);
3151 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3152 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3154 if (player->video360_metadata.full_pano_width_pixels &&
3155 player->video360_metadata.full_pano_height_pixels &&
3156 player->video360_metadata.cropped_area_image_width &&
3157 player->video360_metadata.cropped_area_image_height) {
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3160 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3161 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3162 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3163 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3164 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3168 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3169 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3170 "horizontal-fov", player->video360_horizontal_fov,
3171 "vertical-fov", player->video360_vertical_fov, NULL);
3174 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3175 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3176 "zoom", 1.0f / player->video360_zoom, NULL);
3179 if (player->video360_yaw_radians <= M_PI &&
3180 player->video360_yaw_radians >= -M_PI &&
3181 player->video360_pitch_radians <= M_PI_2 &&
3182 player->video360_pitch_radians >= -M_PI_2) {
3183 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3184 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3185 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3186 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3187 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188 "pose-yaw", player->video360_metadata.init_view_heading,
3189 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3192 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3193 "passthrough", !player->is_video360_enabled, NULL);
3200 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3202 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3203 GList *element_bucket = NULL;
3206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3208 /* create video360 filter */
3209 if (player->is_360_feature_enabled && player->is_content_spherical) {
3210 LOGD("create video360 element");
3211 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3212 __mmplayer_gst_set_video360_property(player);
3216 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3217 LOGD("skip creating the videoconv and rotator");
3218 return MM_ERROR_NONE;
3221 /* in case of sw codec & overlay surface type, except 360 playback.
3222 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3223 LOGD("create video converter: %s", video_csc);
3224 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3226 /* set video rotator */
3227 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3230 *bucket = element_bucket;
3232 return MM_ERROR_NONE;
3234 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3235 g_list_free(element_bucket);
3239 return MM_ERROR_PLAYER_INTERNAL;
3243 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3245 gchar *factory_name = NULL;
3247 switch (surface_type) {
3248 case MM_DISPLAY_SURFACE_OVERLAY:
3249 if (strlen(player->ini.videosink_element_overlay) > 0)
3250 factory_name = player->ini.videosink_element_overlay;
3252 case MM_DISPLAY_SURFACE_REMOTE:
3253 case MM_DISPLAY_SURFACE_NULL:
3254 if (strlen(player->ini.videosink_element_fake) > 0)
3255 factory_name = player->ini.videosink_element_fake;
3258 LOGE("unidentified surface type");
3262 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3263 return factory_name;
3267 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3269 gchar *factory_name = NULL;
3270 MMPlayerGstElement *videobin = NULL;
3275 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3277 videobin = player->pipeline->videobin;
3278 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3280 attrs = MMPLAYER_GET_ATTRS(player);
3282 LOGE("cannot get content attribute");
3283 return MM_ERROR_PLAYER_INTERNAL;
3286 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3287 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3288 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3290 /* support shard memory with S/W codec on HawkP */
3291 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3292 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3293 "use-tbm", use_tbm, NULL);
3297 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3298 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3301 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3303 LOGD("disable last-sample");
3304 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3307 if (player->set_mode.media_packet_video_stream) {
3309 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3310 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3311 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3313 __mmplayer_add_signal_connection(player,
3314 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3315 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3317 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3320 __mmplayer_add_signal_connection(player,
3321 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3322 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3324 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3328 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3329 return MM_ERROR_PLAYER_INTERNAL;
3331 if (videobin[MMPLAYER_V_SINK].gst) {
3332 GstPad *sink_pad = NULL;
3333 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3335 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3336 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3337 gst_object_unref(GST_OBJECT(sink_pad));
3339 LOGE("failed to get sink pad from videosink");
3343 return MM_ERROR_NONE;
3348 * - video overlay surface(arm/x86) : tizenwlsink
3351 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3354 GList *element_bucket = NULL;
3355 MMPlayerGstElement *first_element = NULL;
3356 MMPlayerGstElement *videobin = NULL;
3357 gchar *videosink_factory_name = NULL;
3360 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3363 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3365 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3367 player->pipeline->videobin = videobin;
3370 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3371 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3372 if (!videobin[MMPLAYER_V_BIN].gst) {
3373 LOGE("failed to create videobin");
3377 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3380 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3381 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3383 /* additional setting for sink plug-in */
3384 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3385 LOGE("failed to set video property");
3389 /* store it as it's sink element */
3390 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3392 /* adding created elements to bin */
3393 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3394 LOGE("failed to add elements");
3398 /* Linking elements in the bucket by added order */
3399 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3400 LOGE("failed to link elements");
3404 /* get first element's sinkpad for creating ghostpad */
3405 first_element = (MMPlayerGstElement *)element_bucket->data;
3406 if (!first_element) {
3407 LOGE("failed to get first element from bucket");
3411 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3413 LOGE("failed to get pad from first element");
3417 /* create ghostpad */
3418 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3419 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3420 LOGE("failed to add ghostpad to videobin");
3423 gst_object_unref(pad);
3425 /* done. free allocated variables */
3426 g_list_free(element_bucket);
3430 return MM_ERROR_NONE;
3433 LOGE("ERROR : releasing videobin");
3434 g_list_free(element_bucket);
3437 gst_object_unref(GST_OBJECT(pad));
3439 /* release videobin with it's childs */
3440 if (videobin[MMPLAYER_V_BIN].gst)
3441 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3443 MMPLAYER_FREEIF(videobin);
3444 player->pipeline->videobin = NULL;
3446 return MM_ERROR_PLAYER_INTERNAL;
3450 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3452 GList *element_bucket = NULL;
3453 MMPlayerGstElement *textbin = player->pipeline->textbin;
3455 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3456 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3457 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3458 "signal-handoffs", FALSE,
3461 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3462 __mmplayer_add_signal_connection(player,
3463 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3464 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3466 G_CALLBACK(__mmplayer_update_subtitle),
3469 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3470 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3472 if (!player->play_subtitle) {
3473 LOGD("add textbin sink as sink element of whole pipeline.");
3474 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3477 /* adding created elements to bin */
3478 LOGD("adding created elements to bin");
3479 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3480 LOGE("failed to add elements");
3484 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3485 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3486 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3488 /* linking elements in the bucket by added order. */
3489 LOGD("Linking elements in the bucket by added order.");
3490 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3491 LOGE("failed to link elements");
3495 /* done. free allocated variables */
3496 g_list_free(element_bucket);
3498 if (textbin[MMPLAYER_T_QUEUE].gst) {
3500 GstPad *ghostpad = NULL;
3502 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3504 LOGE("failed to get sink pad of text queue");
3508 ghostpad = gst_ghost_pad_new("text_sink", pad);
3509 gst_object_unref(pad);
3512 LOGE("failed to create ghostpad of textbin");
3516 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3517 LOGE("failed to add ghostpad to textbin");
3518 gst_object_unref(ghostpad);
3523 return MM_ERROR_NONE;
3526 g_list_free(element_bucket);
3528 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3529 LOGE("remove textbin sink from sink list");
3530 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3533 /* release element at __mmplayer_gst_create_text_sink_bin */
3534 return MM_ERROR_PLAYER_INTERNAL;
3538 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3540 MMPlayerGstElement *textbin = NULL;
3541 GList *element_bucket = NULL;
3542 int surface_type = 0;
3547 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3550 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3552 LOGE("failed to allocate memory for textbin");
3553 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3557 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3558 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3559 if (!textbin[MMPLAYER_T_BIN].gst) {
3560 LOGE("failed to create textbin");
3565 player->pipeline->textbin = textbin;
3568 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3569 LOGD("surface type for subtitle : %d", surface_type);
3570 switch (surface_type) {
3571 case MM_DISPLAY_SURFACE_OVERLAY:
3572 case MM_DISPLAY_SURFACE_NULL:
3573 case MM_DISPLAY_SURFACE_REMOTE:
3574 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3575 LOGE("failed to make plain text elements");
3586 return MM_ERROR_NONE;
3590 LOGD("ERROR : releasing textbin");
3592 g_list_free(element_bucket);
3594 /* release signal */
3595 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3597 /* release element which are not added to bin */
3598 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3599 /* NOTE : skip bin */
3600 if (textbin[i].gst) {
3601 GstObject *parent = NULL;
3602 parent = gst_element_get_parent(textbin[i].gst);
3605 gst_object_unref(GST_OBJECT(textbin[i].gst));
3606 textbin[i].gst = NULL;
3608 gst_object_unref(GST_OBJECT(parent));
3613 /* release textbin with it's childs */
3614 if (textbin[MMPLAYER_T_BIN].gst)
3615 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3617 MMPLAYER_FREEIF(player->pipeline->textbin);
3618 player->pipeline->textbin = NULL;
3621 return MM_ERROR_PLAYER_INTERNAL;
3625 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3627 MMPlayerGstElement *mainbin = NULL;
3628 MMPlayerGstElement *textbin = NULL;
3629 MMHandleType attrs = 0;
3630 GstElement *subsrc = NULL;
3631 GstElement *subparse = NULL;
3632 gchar *subtitle_uri = NULL;
3633 const gchar *charset = NULL;
3639 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3641 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3643 mainbin = player->pipeline->mainbin;
3645 attrs = MMPLAYER_GET_ATTRS(player);
3647 LOGE("cannot get content attribute");
3648 return MM_ERROR_PLAYER_INTERNAL;
3651 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3652 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3653 LOGE("subtitle uri is not proper filepath.");
3654 return MM_ERROR_PLAYER_INVALID_URI;
3657 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3658 LOGE("failed to get storage info of subtitle path");
3659 return MM_ERROR_PLAYER_INVALID_URI;
3662 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3664 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3665 player->subtitle_language_list = NULL;
3666 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3668 /* create the subtitle source */
3669 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3671 LOGE("failed to create filesrc element");
3674 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3676 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3677 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3679 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3680 LOGW("failed to add queue");
3681 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3682 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3683 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3688 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3690 LOGE("failed to create subparse element");
3694 charset = util_get_charset(subtitle_uri);
3696 LOGD("detected charset is %s", charset);
3697 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3700 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3701 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3703 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3704 LOGW("failed to add subparse");
3705 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3706 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3707 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3711 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3712 LOGW("failed to link subsrc and subparse");
3716 player->play_subtitle = TRUE;
3717 player->adjust_subtitle_pos = 0;
3719 LOGD("play subtitle using subtitle file");
3721 if (player->pipeline->textbin == NULL) {
3722 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3723 LOGE("failed to create text sink bin. continuing without text");
3727 textbin = player->pipeline->textbin;
3729 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3730 LOGW("failed to add textbin");
3732 /* release signal */
3733 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3735 /* release textbin with it's childs */
3736 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3737 MMPLAYER_FREEIF(player->pipeline->textbin);
3738 player->pipeline->textbin = textbin = NULL;
3742 LOGD("link text input selector and textbin ghost pad");
3744 player->textsink_linked = 1;
3745 player->external_text_idx = 0;
3746 LOGI("textsink is linked");
3748 textbin = player->pipeline->textbin;
3749 LOGD("text bin has been created. reuse it.");
3750 player->external_text_idx = 1;
3753 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3754 LOGW("failed to link subparse and textbin");
3758 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3760 LOGE("failed to get sink pad from textsink to probe data");
3764 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3765 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3767 gst_object_unref(pad);
3770 /* create dot. for debugging */
3771 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3774 return MM_ERROR_NONE;
3777 /* release text pipeline resource */
3778 player->textsink_linked = 0;
3780 /* release signal */
3781 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3783 if (player->pipeline->textbin) {
3784 LOGE("remove textbin");
3786 /* release textbin with it's childs */
3787 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3788 MMPLAYER_FREEIF(player->pipeline->textbin);
3789 player->pipeline->textbin = NULL;
3793 /* release subtitle elem */
3794 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3795 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3797 return MM_ERROR_PLAYER_INTERNAL;
3801 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3803 mm_player_t *player = (mm_player_t *)data;
3804 MMMessageParamType msg = {0, };
3805 GstClockTime duration = 0;
3806 gpointer text = NULL;
3807 guint text_size = 0;
3808 gboolean ret = TRUE;
3809 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3813 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3814 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3816 if (player->is_subtitle_force_drop) {
3817 LOGW("subtitle is dropped forcedly.");
3821 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3822 text = mapinfo.data;
3823 text_size = mapinfo.size;
3825 if (player->set_mode.subtitle_off) {
3826 LOGD("subtitle is OFF.");
3830 if (!text || (text_size == 0)) {
3831 LOGD("There is no subtitle to be displayed.");
3835 msg.data = (void *)text;
3837 duration = GST_BUFFER_DURATION(buffer);
3839 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3840 if (player->duration > GST_BUFFER_PTS(buffer))
3841 duration = player->duration - GST_BUFFER_PTS(buffer);
3844 LOGI("subtitle duration is invalid, subtitle duration change "
3845 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3847 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3849 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3851 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3852 gst_buffer_unmap(buffer, &mapinfo);
3859 static GstPadProbeReturn
3860 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3862 mm_player_t *player = (mm_player_t *)u_data;
3863 GstClockTime cur_timestamp = 0;
3864 gint64 adjusted_timestamp = 0;
3865 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3867 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3869 if (player->set_mode.subtitle_off) {
3870 LOGD("subtitle is OFF.");
3874 if (player->adjust_subtitle_pos == 0) {
3875 LOGD("nothing to do");
3879 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3880 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3882 if (adjusted_timestamp < 0) {
3883 LOGD("adjusted_timestamp under zero");
3888 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3889 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3890 GST_TIME_ARGS(cur_timestamp),
3891 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3893 return GST_PAD_PROBE_OK;
3897 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3901 /* check player and subtitlebin are created */
3902 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3903 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3905 if (position == 0) {
3906 LOGD("nothing to do");
3908 return MM_ERROR_NONE;
3912 case MM_PLAYER_POS_FORMAT_TIME:
3914 /* check current postion */
3915 player->adjust_subtitle_pos = position;
3917 LOGD("save adjust_subtitle_pos in player") ;
3923 LOGW("invalid format.");
3925 return MM_ERROR_INVALID_ARGUMENT;
3931 return MM_ERROR_NONE;
3935 * This function is to create audio or video pipeline for playing.
3937 * @param player [in] handle of player
3939 * @return This function returns zero on success.
3944 __mmplayer_gst_create_pipeline(mm_player_t *player)
3946 int ret = MM_ERROR_NONE;
3947 MMPlayerGstElement *mainbin = NULL;
3948 MMHandleType attrs = 0;
3951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3953 /* get profile attribute */
3954 attrs = MMPLAYER_GET_ATTRS(player);
3956 LOGE("failed to get content attribute");
3960 /* create pipeline handles */
3961 if (player->pipeline) {
3962 LOGE("pipeline should be released before create new one");
3966 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3967 if (player->pipeline == NULL)
3970 /* create mainbin */
3971 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3972 if (mainbin == NULL)
3975 /* create pipeline */
3976 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3977 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3978 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3979 LOGE("failed to create pipeline");
3984 player->pipeline->mainbin = mainbin;
3986 /* create the source and decoder elements */
3987 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3988 ret = __mmplayer_gst_build_es_pipeline(player);
3990 ret = __mmplayer_gst_build_pipeline(player);
3992 if (ret != MM_ERROR_NONE) {
3993 LOGE("failed to create some elements");
3997 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3998 if (__mmplayer_check_subtitle(player)
3999 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4000 LOGE("failed to create text pipeline");
4003 ret = __mmplayer_gst_add_bus_watch(player);
4004 if (ret != MM_ERROR_NONE) {
4005 LOGE("failed to add bus watch");
4010 return MM_ERROR_NONE;
4013 __mmplayer_gst_destroy_pipeline(player);
4014 return MM_ERROR_PLAYER_INTERNAL;
4018 __mmplayer_reset_gapless_state(mm_player_t *player)
4021 MMPLAYER_RETURN_IF_FAIL(player
4023 && player->pipeline->audiobin
4024 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4026 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4033 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4036 int ret = MM_ERROR_NONE;
4040 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4042 /* cleanup stuffs */
4043 MMPLAYER_FREEIF(player->type);
4044 player->no_more_pad = FALSE;
4045 player->num_dynamic_pad = 0;
4046 player->demux_pad_index = 0;
4048 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4049 player->subtitle_language_list = NULL;
4050 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4052 __mmplayer_reset_gapless_state(player);
4054 if (player->streamer) {
4055 __mm_player_streaming_initialize(player->streamer, FALSE);
4056 __mm_player_streaming_destroy(player->streamer);
4057 player->streamer = NULL;
4060 /* cleanup unlinked mime type */
4061 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4062 MMPLAYER_FREEIF(player->unlinked_video_mime);
4063 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4065 /* cleanup running stuffs */
4066 __mmplayer_cancel_eos_timer(player);
4068 /* cleanup gst stuffs */
4069 if (player->pipeline) {
4070 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4071 GstTagList *tag_list = player->pipeline->tag_list;
4073 /* first we need to disconnect all signal hander */
4074 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4077 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4078 MMPlayerGstElement *videobin = player->pipeline->videobin;
4079 MMPlayerGstElement *textbin = player->pipeline->textbin;
4080 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4081 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4082 gst_object_unref(bus);
4084 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4085 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4086 if (ret != MM_ERROR_NONE) {
4087 LOGE("fail to change state to NULL");
4088 return MM_ERROR_PLAYER_INTERNAL;
4091 LOGW("succeeded in changing state to NULL");
4093 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4096 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4097 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4099 /* free avsysaudiosink
4100 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4101 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4103 MMPLAYER_FREEIF(audiobin);
4104 MMPLAYER_FREEIF(videobin);
4105 MMPLAYER_FREEIF(textbin);
4106 MMPLAYER_FREEIF(mainbin);
4110 gst_tag_list_unref(tag_list);
4112 MMPLAYER_FREEIF(player->pipeline);
4114 MMPLAYER_FREEIF(player->album_art);
4116 if (player->v_stream_caps) {
4117 gst_caps_unref(player->v_stream_caps);
4118 player->v_stream_caps = NULL;
4121 if (player->a_stream_caps) {
4122 gst_caps_unref(player->a_stream_caps);
4123 player->a_stream_caps = NULL;
4126 if (player->s_stream_caps) {
4127 gst_caps_unref(player->s_stream_caps);
4128 player->s_stream_caps = NULL;
4130 __mmplayer_track_destroy(player);
4132 if (player->sink_elements)
4133 g_list_free(player->sink_elements);
4134 player->sink_elements = NULL;
4136 if (player->bufmgr) {
4137 tbm_bufmgr_deinit(player->bufmgr);
4138 player->bufmgr = NULL;
4141 LOGW("finished destroy pipeline");
4149 __mmplayer_gst_realize(mm_player_t *player)
4152 int ret = MM_ERROR_NONE;
4156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4158 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4160 ret = __mmplayer_gst_create_pipeline(player);
4162 LOGE("failed to create pipeline");
4166 /* set pipeline state to READY */
4167 /* NOTE : state change to READY must be performed sync. */
4168 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4169 ret = __mmplayer_gst_set_state(player,
4170 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4172 if (ret != MM_ERROR_NONE) {
4173 /* return error if failed to set state */
4174 LOGE("failed to set READY state");
4178 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4180 /* create dot before error-return. for debugging */
4181 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4189 __mmplayer_gst_unrealize(mm_player_t *player)
4191 int ret = MM_ERROR_NONE;
4195 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4197 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4198 MMPLAYER_PRINT_STATE(player);
4200 /* release miscellaneous information */
4201 __mmplayer_release_misc(player);
4203 /* destroy pipeline */
4204 ret = __mmplayer_gst_destroy_pipeline(player);
4205 if (ret != MM_ERROR_NONE) {
4206 LOGE("failed to destory pipeline");
4210 /* release miscellaneous information.
4211 these info needs to be released after pipeline is destroyed. */
4212 __mmplayer_release_misc_post(player);
4214 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4222 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4227 LOGW("set_message_callback is called with invalid player handle");
4228 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4231 player->msg_cb = callback;
4232 player->msg_cb_param = user_param;
4234 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4238 return MM_ERROR_NONE;
4242 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4244 int ret = MM_ERROR_NONE;
4249 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4250 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4251 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4253 memset(data, 0, sizeof(MMPlayerParseProfile));
4255 if (strstr(uri, "es_buff://")) {
4256 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4257 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4258 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4259 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4261 tmp = g_ascii_strdown(uri, strlen(uri));
4262 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4263 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4265 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4267 } else if (strstr(uri, "mms://")) {
4268 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4269 } else if ((path = strstr(uri, "mem://"))) {
4270 ret = __mmplayer_set_mem_uri(data, path, param);
4272 ret = __mmplayer_set_file_uri(data, uri);
4275 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4276 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4277 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4278 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4280 /* dump parse result */
4281 SECURE_LOGW("incoming uri : %s", uri);
4282 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4283 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4291 __mmplayer_can_do_interrupt(mm_player_t *player)
4293 if (!player || !player->pipeline || !player->attrs) {
4294 LOGW("not initialized");
4298 if (player->audio_stream_render_cb) {
4299 LOGW("not support in pcm extraction mode");
4303 /* check if seeking */
4304 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4305 MMMessageParamType msg_param;
4306 memset(&msg_param, 0, sizeof(MMMessageParamType));
4307 msg_param.code = MM_ERROR_PLAYER_SEEK;
4308 player->seek_state = MMPLAYER_SEEK_NONE;
4309 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4313 /* check other thread */
4314 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4315 LOGW("locked already, cmd state : %d", player->cmd);
4317 /* check application command */
4318 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4319 LOGW("playing.. should wait cmd lock then, will be interrupted");
4321 /* lock will be released at mrp_resource_release_cb() */
4322 MMPLAYER_CMD_LOCK(player);
4325 LOGW("nothing to do");
4328 LOGW("can interrupt immediately");
4332 FAILED: /* with CMD UNLOCKED */
4335 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4340 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4343 mm_player_t *player = NULL;
4347 if (user_data == NULL) {
4348 LOGE("- user_data is null");
4351 player = (mm_player_t *)user_data;
4353 /* do something to release resource here.
4354 * player stop and interrupt forwarding */
4355 if (!__mmplayer_can_do_interrupt(player)) {
4356 LOGW("no need to interrupt, so leave");
4358 MMMessageParamType msg = {0, };
4361 player->interrupted_by_resource = TRUE;
4363 /* get last play position */
4364 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4365 LOGW("failed to get play position.");
4367 msg.union_type = MM_MSG_UNION_TIME;
4368 msg.time.elapsed = pos;
4369 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4371 LOGD("video resource conflict so, resource will be freed by unrealizing");
4372 if (_mmplayer_unrealize((MMHandleType)player))
4373 LOGW("failed to unrealize");
4375 /* lock is called in __mmplayer_can_do_interrupt() */
4376 MMPLAYER_CMD_UNLOCK(player);
4379 if (res == player->video_overlay_resource)
4380 player->video_overlay_resource = FALSE;
4382 player->video_decoder_resource = FALSE;
4390 __mmplayer_initialize_video_roi(mm_player_t *player)
4392 player->video_roi.scale_x = 0.0;
4393 player->video_roi.scale_y = 0.0;
4394 player->video_roi.scale_width = 1.0;
4395 player->video_roi.scale_height = 1.0;
4399 _mmplayer_create_player(MMHandleType handle)
4401 int ret = MM_ERROR_PLAYER_INTERNAL;
4402 bool enabled = false;
4404 mm_player_t *player = MM_PLAYER_CAST(handle);
4408 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4410 /* initialize player state */
4411 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4412 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4413 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4414 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4416 /* check current state */
4417 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4419 /* construct attributes */
4420 player->attrs = _mmplayer_construct_attribute(handle);
4422 if (!player->attrs) {
4423 LOGE("Failed to construct attributes");
4427 /* initialize gstreamer with configured parameter */
4428 if (!__mmplayer_init_gstreamer(player)) {
4429 LOGE("Initializing gstreamer failed");
4430 _mmplayer_deconstruct_attribute(handle);
4434 /* create lock. note that g_tread_init() has already called in gst_init() */
4435 g_mutex_init(&player->fsink_lock);
4437 /* create update tag lock */
4438 g_mutex_init(&player->update_tag_lock);
4440 /* create gapless play mutex */
4441 g_mutex_init(&player->gapless_play_thread_mutex);
4443 /* create gapless play cond */
4444 g_cond_init(&player->gapless_play_thread_cond);
4446 /* create gapless play thread */
4447 player->gapless_play_thread =
4448 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4449 if (!player->gapless_play_thread) {
4450 LOGE("failed to create gapless play thread");
4451 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4452 g_mutex_clear(&player->gapless_play_thread_mutex);
4453 g_cond_clear(&player->gapless_play_thread_cond);
4457 player->bus_msg_q = g_queue_new();
4458 if (!player->bus_msg_q) {
4459 LOGE("failed to create queue for bus_msg");
4460 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4464 ret = _mmplayer_initialize_video_capture(player);
4465 if (ret != MM_ERROR_NONE) {
4466 LOGE("failed to initialize video capture");
4470 /* initialize resource manager */
4471 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4472 __resource_release_cb, player, &player->resource_manager)
4473 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4474 LOGE("failed to initialize resource manager");
4475 ret = MM_ERROR_PLAYER_INTERNAL;
4479 /* create video bo lock and cond */
4480 g_mutex_init(&player->video_bo_mutex);
4481 g_cond_init(&player->video_bo_cond);
4483 /* create media stream callback mutex */
4484 g_mutex_init(&player->media_stream_cb_lock);
4486 /* create subtitle info lock and cond */
4487 g_mutex_init(&player->subtitle_info_mutex);
4488 g_cond_init(&player->subtitle_info_cond);
4490 player->streaming_type = STREAMING_SERVICE_NONE;
4492 /* give default value of audio effect setting */
4493 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4494 player->sound.rg_enable = false;
4495 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4497 player->play_subtitle = FALSE;
4498 player->has_closed_caption = FALSE;
4499 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4500 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4501 player->pending_resume = FALSE;
4502 if (player->ini.dump_element_keyword[0][0] == '\0')
4503 player->ini.set_dump_element_flag = FALSE;
4505 player->ini.set_dump_element_flag = TRUE;
4507 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4508 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4509 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4511 /* Set video360 settings to their defaults for just-created player.
4514 player->is_360_feature_enabled = FALSE;
4515 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4516 LOGI("spherical feature info: %d", enabled);
4518 player->is_360_feature_enabled = TRUE;
4520 LOGE("failed to get spherical feature info");
4523 player->is_content_spherical = FALSE;
4524 player->is_video360_enabled = TRUE;
4525 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4526 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4527 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4528 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4529 player->video360_zoom = 1.0f;
4530 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4531 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4533 __mmplayer_initialize_video_roi(player);
4535 /* set player state to null */
4536 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4537 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4541 return MM_ERROR_NONE;
4545 g_mutex_clear(&player->fsink_lock);
4546 /* free update tag lock */
4547 g_mutex_clear(&player->update_tag_lock);
4548 g_queue_free(player->bus_msg_q);
4549 /* free gapless play thread */
4550 if (player->gapless_play_thread) {
4551 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4552 player->gapless_play_thread_exit = TRUE;
4553 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4554 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4556 g_thread_join(player->gapless_play_thread);
4557 player->gapless_play_thread = NULL;
4559 g_mutex_clear(&player->gapless_play_thread_mutex);
4560 g_cond_clear(&player->gapless_play_thread_cond);
4563 /* release attributes */
4564 _mmplayer_deconstruct_attribute(handle);
4572 __mmplayer_init_gstreamer(mm_player_t *player)
4574 static gboolean initialized = FALSE;
4575 static const int max_argc = 50;
4577 gchar **argv = NULL;
4578 gchar **argv2 = NULL;
4584 LOGD("gstreamer already initialized.");
4589 argc = malloc(sizeof(int));
4590 argv = malloc(sizeof(gchar *) * max_argc);
4591 argv2 = malloc(sizeof(gchar *) * max_argc);
4593 if (!argc || !argv || !argv2)
4596 memset(argv, 0, sizeof(gchar *) * max_argc);
4597 memset(argv2, 0, sizeof(gchar *) * max_argc);
4601 argv[0] = g_strdup("mmplayer");
4604 for (i = 0; i < 5; i++) {
4605 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4606 if (strlen(player->ini.gst_param[i]) > 0) {
4607 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4612 /* we would not do fork for scanning plugins */
4613 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4616 /* check disable registry scan */
4617 if (player->ini.skip_rescan) {
4618 argv[*argc] = g_strdup("--gst-disable-registry-update");
4622 /* check disable segtrap */
4623 if (player->ini.disable_segtrap) {
4624 argv[*argc] = g_strdup("--gst-disable-segtrap");
4628 LOGD("initializing gstreamer with following parameter");
4629 LOGD("argc : %d", *argc);
4632 for (i = 0; i < arg_count; i++) {
4634 LOGD("argv[%d] : %s", i, argv2[i]);
4637 /* initializing gstreamer */
4638 if (!gst_init_check(argc, &argv, &err)) {
4639 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4646 for (i = 0; i < arg_count; i++) {
4647 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4648 MMPLAYER_FREEIF(argv2[i]);
4651 MMPLAYER_FREEIF(argv);
4652 MMPLAYER_FREEIF(argv2);
4653 MMPLAYER_FREEIF(argc);
4663 for (i = 0; i < arg_count; i++) {
4664 LOGD("free[%d] : %s", i, argv2[i]);
4665 MMPLAYER_FREEIF(argv2[i]);
4668 MMPLAYER_FREEIF(argv);
4669 MMPLAYER_FREEIF(argv2);
4670 MMPLAYER_FREEIF(argc);
4676 __mmplayer_check_async_state_transition(mm_player_t *player)
4678 GstState element_state = GST_STATE_VOID_PENDING;
4679 GstState element_pending_state = GST_STATE_VOID_PENDING;
4680 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4681 GstElement *element = NULL;
4682 gboolean async = FALSE;
4684 /* check player handle */
4685 MMPLAYER_RETURN_IF_FAIL(player &&
4687 player->pipeline->mainbin &&
4688 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4691 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4693 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4694 LOGD("don't need to check the pipeline state");
4698 MMPLAYER_PRINT_STATE(player);
4700 /* wait for state transition */
4701 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4702 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4704 if (ret == GST_STATE_CHANGE_FAILURE) {
4705 LOGE(" [%s] state : %s pending : %s",
4706 GST_ELEMENT_NAME(element),
4707 gst_element_state_get_name(element_state),
4708 gst_element_state_get_name(element_pending_state));
4710 /* dump state of all element */
4711 __mmplayer_dump_pipeline_state(player);
4716 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4721 _mmplayer_destroy(MMHandleType handle)
4723 mm_player_t *player = MM_PLAYER_CAST(handle);
4727 /* check player handle */
4728 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4730 /* destroy can called at anytime */
4731 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4733 /* check async state transition */
4734 __mmplayer_check_async_state_transition(player);
4736 /* release gapless play thread */
4737 if (player->gapless_play_thread) {
4738 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4739 player->gapless_play_thread_exit = TRUE;
4740 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4741 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4743 LOGD("waitting for gapless play thread exit");
4744 g_thread_join(player->gapless_play_thread);
4745 g_mutex_clear(&player->gapless_play_thread_mutex);
4746 g_cond_clear(&player->gapless_play_thread_cond);
4747 LOGD("gapless play thread released");
4750 _mmplayer_release_video_capture(player);
4752 /* de-initialize resource manager */
4753 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4754 player->resource_manager))
4755 LOGE("failed to deinitialize resource manager");
4757 /* release pipeline */
4758 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4759 LOGE("failed to destory pipeline");
4760 return MM_ERROR_PLAYER_INTERNAL;
4763 g_queue_free(player->bus_msg_q);
4765 /* release subtitle info lock and cond */
4766 g_mutex_clear(&player->subtitle_info_mutex);
4767 g_cond_clear(&player->subtitle_info_cond);
4769 __mmplayer_release_dump_list(player->dump_list);
4771 /* release miscellaneous information */
4772 __mmplayer_release_misc(player);
4774 /* release miscellaneous information.
4775 these info needs to be released after pipeline is destroyed. */
4776 __mmplayer_release_misc_post(player);
4778 /* release attributes */
4779 _mmplayer_deconstruct_attribute(handle);
4782 g_mutex_clear(&player->fsink_lock);
4785 g_mutex_clear(&player->update_tag_lock);
4787 /* release video bo lock and cond */
4788 g_mutex_clear(&player->video_bo_mutex);
4789 g_cond_clear(&player->video_bo_cond);
4791 /* release media stream callback lock */
4792 g_mutex_clear(&player->media_stream_cb_lock);
4796 return MM_ERROR_NONE;
4800 _mmplayer_realize(MMHandleType hplayer)
4802 mm_player_t *player = (mm_player_t *)hplayer;
4805 MMHandleType attrs = 0;
4806 int ret = MM_ERROR_NONE;
4810 /* check player handle */
4811 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4813 /* check current state */
4814 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4816 attrs = MMPLAYER_GET_ATTRS(player);
4818 LOGE("fail to get attributes.");
4819 return MM_ERROR_PLAYER_INTERNAL;
4821 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4822 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4824 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4825 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4827 if (ret != MM_ERROR_NONE) {
4828 LOGE("failed to parse profile");
4833 if (uri && (strstr(uri, "es_buff://"))) {
4834 if (strstr(uri, "es_buff://push_mode"))
4835 player->es_player_push_mode = TRUE;
4837 player->es_player_push_mode = FALSE;
4840 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4841 LOGW("mms protocol is not supported format.");
4842 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4845 if (MMPLAYER_IS_STREAMING(player))
4846 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4848 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4850 player->smooth_streaming = FALSE;
4851 player->videodec_linked = 0;
4852 player->audiodec_linked = 0;
4853 player->textsink_linked = 0;
4854 player->is_external_subtitle_present = FALSE;
4855 player->is_external_subtitle_added_now = FALSE;
4856 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4857 player->video360_metadata.is_spherical = -1;
4858 player->is_openal_plugin_used = FALSE;
4859 player->demux_pad_index = 0;
4860 player->subtitle_language_list = NULL;
4861 player->is_subtitle_force_drop = FALSE;
4862 player->last_multiwin_status = FALSE;
4864 __mmplayer_track_initialize(player);
4865 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4867 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4868 gint prebuffer_ms = 0, rebuffer_ms = 0;
4870 player->streamer = __mm_player_streaming_create();
4871 __mm_player_streaming_initialize(player->streamer, TRUE);
4873 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4874 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4876 if (prebuffer_ms > 0) {
4877 prebuffer_ms = MAX(prebuffer_ms, 1000);
4878 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4881 if (rebuffer_ms > 0) {
4882 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4883 rebuffer_ms = MAX(rebuffer_ms, 1000);
4884 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4887 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4888 player->streamer->buffering_req.rebuffer_time);
4891 /* realize pipeline */
4892 ret = __mmplayer_gst_realize(player);
4893 if (ret != MM_ERROR_NONE)
4894 LOGE("fail to realize the player.");
4896 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4904 _mmplayer_unrealize(MMHandleType hplayer)
4906 mm_player_t *player = (mm_player_t *)hplayer;
4907 int ret = MM_ERROR_NONE;
4911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4913 MMPLAYER_CMD_UNLOCK(player);
4914 /* destroy the gst bus msg thread which is created during realize.
4915 this funct have to be called before getting cmd lock. */
4916 __mmplayer_bus_msg_thread_destroy(player);
4917 MMPLAYER_CMD_LOCK(player);
4919 /* check current state */
4920 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4922 /* check async state transition */
4923 __mmplayer_check_async_state_transition(player);
4925 /* unrealize pipeline */
4926 ret = __mmplayer_gst_unrealize(player);
4928 /* set asm stop if success */
4929 if (MM_ERROR_NONE == ret) {
4930 if (!player->interrupted_by_resource) {
4931 if (player->video_decoder_resource != NULL) {
4932 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4933 player->video_decoder_resource);
4934 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4935 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4937 player->video_decoder_resource = NULL;
4940 if (player->video_overlay_resource != NULL) {
4941 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4942 player->video_overlay_resource);
4943 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4944 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4946 player->video_overlay_resource = NULL;
4949 ret = mm_resource_manager_commit(player->resource_manager);
4950 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4951 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4954 LOGE("failed and don't change asm state to stop");
4962 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4964 mm_player_t *player = (mm_player_t *)hplayer;
4966 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4968 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4972 _mmplayer_get_state(MMHandleType hplayer, int *state)
4974 mm_player_t *player = (mm_player_t *)hplayer;
4976 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4978 *state = MMPLAYER_CURRENT_STATE(player);
4980 return MM_ERROR_NONE;
4985 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4987 mm_player_t *player = (mm_player_t *)hplayer;
4988 GstElement *vol_element = NULL;
4993 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4995 LOGD("volume [L]=%f:[R]=%f",
4996 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4998 /* invalid factor range or not */
4999 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5000 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5001 LOGE("Invalid factor!(valid factor:0~1.0)");
5002 return MM_ERROR_INVALID_ARGUMENT;
5006 /* not support to set other value into each channel */
5007 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5008 return MM_ERROR_INVALID_ARGUMENT;
5010 /* Save volume to handle. Currently the first array element will be saved. */
5011 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5013 /* check pipeline handle */
5014 if (!player->pipeline || !player->pipeline->audiobin) {
5015 LOGD("audiobin is not created yet");
5016 LOGD("but, current stored volume will be set when it's created.");
5018 /* NOTE : stored volume will be used in create_audiobin
5019 * returning MM_ERROR_NONE here makes application to able to
5020 * set volume at anytime.
5022 return MM_ERROR_NONE;
5025 /* setting volume to volume element */
5026 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5029 LOGD("volume is set [%f]", player->sound.volume);
5030 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5035 return MM_ERROR_NONE;
5039 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5041 mm_player_t *player = (mm_player_t *)hplayer;
5046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5047 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5049 /* returning stored volume */
5050 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5051 volume->level[i] = player->sound.volume;
5055 return MM_ERROR_NONE;
5059 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5061 mm_player_t *player = (mm_player_t *)hplayer;
5062 GstElement *vol_element = NULL;
5066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5068 /* mute value shoud 0 or 1 */
5069 if (mute != 0 && mute != 1) {
5070 LOGE("bad mute value");
5072 /* FIXIT : definitly, we need _BAD_PARAM error code */
5073 return MM_ERROR_INVALID_ARGUMENT;
5076 player->sound.mute = mute;
5078 /* just hold mute value if pipeline is not ready */
5079 if (!player->pipeline || !player->pipeline->audiobin) {
5080 LOGD("pipeline is not ready. holding mute value");
5081 return MM_ERROR_NONE;
5084 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5086 /* NOTE : volume will only created when the bt is enabled */
5088 LOGD("mute : %d", mute);
5089 g_object_set(vol_element, "mute", mute, NULL);
5091 LOGD("volume elemnet is not created. using volume in audiosink");
5095 return MM_ERROR_NONE;
5099 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5101 mm_player_t *player = (mm_player_t *)hplayer;
5105 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5108 /* just hold mute value if pipeline is not ready */
5109 if (!player->pipeline || !player->pipeline->audiobin) {
5110 LOGD("pipeline is not ready. returning stored value");
5111 *pmute = player->sound.mute;
5112 return MM_ERROR_NONE;
5115 *pmute = player->sound.mute;
5119 return MM_ERROR_NONE;
5123 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5125 mm_player_t *player = (mm_player_t *)hplayer;
5129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5131 player->video_stream_changed_cb = callback;
5132 player->video_stream_changed_cb_user_param = user_param;
5133 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5137 return MM_ERROR_NONE;
5141 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5143 mm_player_t *player = (mm_player_t *)hplayer;
5147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 player->audio_stream_changed_cb = callback;
5150 player->audio_stream_changed_cb_user_param = user_param;
5151 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5155 return MM_ERROR_NONE;
5159 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5161 mm_player_t *player = (mm_player_t *)hplayer;
5165 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5167 player->audio_stream_render_cb = callback;
5168 player->audio_stream_cb_user_param = user_param;
5169 player->audio_stream_sink_sync = sync;
5170 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5174 return MM_ERROR_NONE;
5178 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5180 mm_player_t *player = (mm_player_t *)hplayer;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186 if (callback && !player->bufmgr)
5187 player->bufmgr = tbm_bufmgr_init(-1);
5189 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5190 player->video_stream_cb = callback;
5191 player->video_stream_cb_user_param = user_param;
5193 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5197 return MM_ERROR_NONE;
5201 _mmplayer_start(MMHandleType hplayer)
5203 mm_player_t *player = (mm_player_t *)hplayer;
5204 gint ret = MM_ERROR_NONE;
5208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5210 /* check current state */
5211 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5213 /* start pipeline */
5214 ret = __mmplayer_gst_start(player);
5215 if (ret != MM_ERROR_NONE)
5216 LOGE("failed to start player.");
5218 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5219 LOGD("force playing start even during buffering");
5220 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5228 /* NOTE: post "not supported codec message" to application
5229 * when one codec is not found during AUTOPLUGGING in MSL.
5230 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5231 * And, if any codec is not found, don't send message here.
5232 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5235 __mmplayer_handle_missed_plugin(mm_player_t *player)
5237 MMMessageParamType msg_param;
5238 memset(&msg_param, 0, sizeof(MMMessageParamType));
5239 gboolean post_msg_direct = FALSE;
5243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5246 player->not_supported_codec, player->can_support_codec);
5248 if (player->not_found_demuxer) {
5249 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5250 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5252 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5253 MMPLAYER_FREEIF(msg_param.data);
5255 return MM_ERROR_NONE;
5258 if (player->not_supported_codec) {
5259 if (player->can_support_codec) {
5260 // There is one codec to play
5261 post_msg_direct = TRUE;
5263 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5264 post_msg_direct = TRUE;
5267 if (post_msg_direct) {
5268 MMMessageParamType msg_param;
5269 memset(&msg_param, 0, sizeof(MMMessageParamType));
5271 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5272 LOGW("not found AUDIO codec, posting error code to application.");
5274 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5275 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5276 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5277 LOGW("not found VIDEO codec, posting error code to application.");
5279 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5280 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5283 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5285 MMPLAYER_FREEIF(msg_param.data);
5287 return MM_ERROR_NONE;
5289 // no any supported codec case
5290 LOGW("not found any codec, posting error code to application.");
5292 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5293 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5294 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5296 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5297 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5300 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5302 MMPLAYER_FREEIF(msg_param.data);
5308 return MM_ERROR_NONE;
5312 __mmplayer_check_pipeline(mm_player_t *player)
5314 GstState element_state = GST_STATE_VOID_PENDING;
5315 GstState element_pending_state = GST_STATE_VOID_PENDING;
5317 int ret = MM_ERROR_NONE;
5319 if (!player->gapless.reconfigure)
5322 LOGW("pipeline is under construction.");
5324 MMPLAYER_PLAYBACK_LOCK(player);
5325 MMPLAYER_PLAYBACK_UNLOCK(player);
5327 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5329 /* wait for state transition */
5330 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5331 if (ret == GST_STATE_CHANGE_FAILURE)
5332 LOGE("failed to change pipeline state within %d sec", timeout);
5335 /* NOTE : it should be able to call 'stop' anytime*/
5337 _mmplayer_stop(MMHandleType hplayer)
5339 mm_player_t *player = (mm_player_t *)hplayer;
5340 int ret = MM_ERROR_NONE;
5344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346 /* check current state */
5347 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5349 /* check pipline building state */
5350 __mmplayer_check_pipeline(player);
5351 __mmplayer_reset_gapless_state(player);
5353 /* NOTE : application should not wait for EOS after calling STOP */
5354 __mmplayer_cancel_eos_timer(player);
5357 player->seek_state = MMPLAYER_SEEK_NONE;
5360 ret = __mmplayer_gst_stop(player);
5362 if (ret != MM_ERROR_NONE)
5363 LOGE("failed to stop player.");
5371 _mmplayer_pause(MMHandleType hplayer)
5373 mm_player_t *player = (mm_player_t *)hplayer;
5374 gint64 pos_nsec = 0;
5375 gboolean async = FALSE;
5376 gint ret = MM_ERROR_NONE;
5380 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5382 /* check current state */
5383 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5385 /* check pipline building state */
5386 __mmplayer_check_pipeline(player);
5388 switch (MMPLAYER_CURRENT_STATE(player)) {
5389 case MM_PLAYER_STATE_READY:
5391 /* check prepare async or not.
5392 * In the case of streaming playback, it's recommned to avoid blocking wait.
5394 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5395 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5397 /* Changing back sync of rtspsrc to async */
5398 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5399 LOGD("async prepare working mode for rtsp");
5405 case MM_PLAYER_STATE_PLAYING:
5407 /* NOTE : store current point to overcome some bad operation
5408 *(returning zero when getting current position in paused state) of some
5411 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5412 LOGW("getting current position failed in paused");
5414 player->last_position = pos_nsec;
5416 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5417 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5418 This causes problem is position calculation during normal pause resume scenarios also.
5419 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5420 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5421 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5422 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5428 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5429 LOGD("doing async pause in case of ms buff src");
5433 /* pause pipeline */
5434 ret = __mmplayer_gst_pause(player, async);
5436 if (ret != MM_ERROR_NONE)
5437 LOGE("failed to pause player. ret : 0x%x", ret);
5439 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5440 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5441 LOGE("failed to update display_rotation");
5449 /* in case of streaming, pause could take long time.*/
5451 _mmplayer_abort_pause(MMHandleType hplayer)
5453 mm_player_t *player = (mm_player_t *)hplayer;
5454 int ret = MM_ERROR_NONE;
5458 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5460 player->pipeline->mainbin,
5461 MM_ERROR_PLAYER_NOT_INITIALIZED);
5463 LOGD("set the pipeline state to READY");
5465 /* set state to READY */
5466 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5467 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5468 if (ret != MM_ERROR_NONE) {
5469 LOGE("fail to change state to READY");
5470 return MM_ERROR_PLAYER_INTERNAL;
5473 LOGD("succeeded in changing state to READY");
5478 _mmplayer_resume(MMHandleType hplayer)
5480 mm_player_t *player = (mm_player_t *)hplayer;
5481 int ret = MM_ERROR_NONE;
5482 gboolean async = FALSE;
5486 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5488 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5489 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5490 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5494 /* Changing back sync mode rtspsrc to async */
5495 LOGD("async resume for rtsp case");
5499 /* check current state */
5500 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5502 ret = __mmplayer_gst_resume(player, async);
5503 if (ret != MM_ERROR_NONE)
5504 LOGE("failed to resume player.");
5506 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5507 LOGD("force resume even during buffering");
5508 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5517 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5519 mm_player_t *player = (mm_player_t *)hplayer;
5520 gint64 pos_nsec = 0;
5521 int ret = MM_ERROR_NONE;
5523 signed long long start = 0, stop = 0;
5524 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5528 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5530 /* The sound of video is not supported under 0.0 and over 2.0. */
5531 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5532 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5535 _mmplayer_set_mute(hplayer, mute);
5537 if (player->playback_rate == rate)
5538 return MM_ERROR_NONE;
5540 /* If the position is reached at start potion during fast backward, EOS is posted.
5541 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5543 player->playback_rate = rate;
5545 current_state = MMPLAYER_CURRENT_STATE(player);
5547 if (current_state != MM_PLAYER_STATE_PAUSED)
5548 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5550 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5552 if ((current_state == MM_PLAYER_STATE_PAUSED)
5553 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5554 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5555 pos_nsec = player->last_position;
5560 stop = GST_CLOCK_TIME_NONE;
5562 start = GST_CLOCK_TIME_NONE;
5566 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5567 player->playback_rate,
5569 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5570 GST_SEEK_TYPE_SET, start,
5571 GST_SEEK_TYPE_SET, stop)) {
5572 LOGE("failed to set speed playback");
5573 return MM_ERROR_PLAYER_SEEK;
5576 LOGD("succeeded to set speed playback as %0.1f", rate);
5580 return MM_ERROR_NONE;;
5584 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5586 mm_player_t *player = (mm_player_t *)hplayer;
5587 int ret = MM_ERROR_NONE;
5591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5593 /* check pipline building state */
5594 __mmplayer_check_pipeline(player);
5596 ret = __mmplayer_gst_set_position(player, position, FALSE);
5604 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5606 mm_player_t *player = (mm_player_t *)hplayer;
5607 int ret = MM_ERROR_NONE;
5609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5611 ret = __mmplayer_gst_get_position(player, position);
5617 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5619 mm_player_t *player = (mm_player_t *)hplayer;
5620 int ret = MM_ERROR_NONE;
5622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5623 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5625 if (g_strrstr(player->type, "video/mpegts"))
5626 __mmplayer_update_duration_value(player);
5628 *duration = player->duration;
5633 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5635 mm_player_t *player = (mm_player_t *)hplayer;
5636 int ret = MM_ERROR_NONE;
5638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5640 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5646 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5648 mm_player_t *player = (mm_player_t *)hplayer;
5649 int ret = MM_ERROR_NONE;
5653 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5655 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5663 __mmplayer_is_midi_type(gchar *str_caps)
5665 if ((g_strrstr(str_caps, "audio/midi")) ||
5666 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5667 (g_strrstr(str_caps, "application/x-smaf")) ||
5668 (g_strrstr(str_caps, "audio/x-imelody")) ||
5669 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5670 (g_strrstr(str_caps, "audio/xmf")) ||
5671 (g_strrstr(str_caps, "audio/mxmf"))) {
5680 __mmplayer_is_only_mp3_type(gchar *str_caps)
5682 if (g_strrstr(str_caps, "application/x-id3") ||
5683 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5689 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5691 GstStructure *caps_structure = NULL;
5692 gint samplerate = 0;
5696 MMPLAYER_RETURN_IF_FAIL(player && caps);
5698 caps_structure = gst_caps_get_structure(caps, 0);
5700 /* set stream information */
5701 gst_structure_get_int(caps_structure, "rate", &samplerate);
5702 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5704 gst_structure_get_int(caps_structure, "channels", &channels);
5705 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5707 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5711 __mmplayer_update_content_type_info(mm_player_t *player)
5714 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5716 if (__mmplayer_is_midi_type(player->type)) {
5717 player->bypass_audio_effect = TRUE;
5721 if (!player->streamer) {
5722 LOGD("no need to check streaming type");
5726 if (g_strrstr(player->type, "application/x-hls")) {
5727 /* If it can't know exact type when it parses uri because of redirection case,
5728 * it will be fixed by typefinder or when doing autoplugging.
5730 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5731 player->streamer->is_adaptive_streaming = TRUE;
5732 } else if (g_strrstr(player->type, "application/dash+xml")) {
5733 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5734 player->streamer->is_adaptive_streaming = TRUE;
5737 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5738 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5739 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5741 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5742 if (player->streamer->is_adaptive_streaming)
5743 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5745 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5749 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5754 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5755 GstCaps *caps, gpointer data)
5757 mm_player_t *player = (mm_player_t *)data;
5762 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5764 /* store type string */
5765 MMPLAYER_FREEIF(player->type);
5766 player->type = gst_caps_to_string(caps);
5768 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5769 player, player->type, probability, gst_caps_get_size(caps));
5771 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5772 (g_strrstr(player->type, "audio/x-raw-int"))) {
5773 LOGE("not support media format");
5775 if (player->msg_posted == FALSE) {
5776 MMMessageParamType msg_param;
5777 memset(&msg_param, 0, sizeof(MMMessageParamType));
5779 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5780 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5782 /* don't post more if one was sent already */
5783 player->msg_posted = TRUE;
5788 __mmplayer_update_content_type_info(player);
5790 pad = gst_element_get_static_pad(tf, "src");
5792 LOGE("fail to get typefind src pad.");
5796 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5797 gboolean async = FALSE;
5798 LOGE("failed to autoplug %s", player->type);
5800 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5802 if (async && player->msg_posted == FALSE)
5803 __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));
5995 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5996 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5998 /* set decodebin property about buffer in streaming playback. *
5999 * in case of HLS/DASH, it does not need to have big buffer *
6000 * because it is kind of adaptive streaming. */
6001 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6002 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6003 gint high_percent = 0;
6005 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6006 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6008 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6010 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6012 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6013 "high-percent", high_percent,
6014 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6015 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6016 "max-size-buffers", 0, NULL); // disable or automatic
6019 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6020 LOGE("failed to sync decodebin state with parent");
6031 gst_object_unref(GST_OBJECT(sinkpad));
6034 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6035 * You need to explicitly set elements to the NULL state before
6036 * dropping the final reference, to allow them to clean up.
6038 gst_element_set_state(queue2, GST_STATE_NULL);
6040 /* And, it still has a parent "player".
6041 * You need to let the parent manage the object instead of unreffing the object directly.
6043 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6044 gst_object_unref(queue2);
6049 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6050 * You need to explicitly set elements to the NULL state before
6051 * dropping the final reference, to allow them to clean up.
6053 gst_element_set_state(decodebin, GST_STATE_NULL);
6055 /* And, it still has a parent "player".
6056 * You need to let the parent manage the object instead of unreffing the object directly.
6059 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6060 gst_object_unref(decodebin);
6068 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6072 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6073 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6075 LOGD("class : %s, mime : %s", factory_class, mime);
6077 /* add missing plugin */
6078 /* NOTE : msl should check missing plugin for image mime type.
6079 * Some motion jpeg clips can have playable audio track.
6080 * So, msl have to play audio after displaying popup written video format not supported.
6082 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6083 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6084 LOGD("not found demuxer");
6085 player->not_found_demuxer = TRUE;
6086 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6092 if (!g_strrstr(factory_class, "Demuxer")) {
6093 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6094 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6095 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6097 /* check that clip have multi tracks or not */
6098 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6099 LOGD("video plugin is already linked");
6101 LOGW("add VIDEO to missing plugin");
6102 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6103 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6105 } else if (g_str_has_prefix(mime, "audio")) {
6106 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6107 LOGD("audio plugin is already linked");
6109 LOGW("add AUDIO to missing plugin");
6110 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6111 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6119 return MM_ERROR_NONE;
6123 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6125 mm_player_t *player = (mm_player_t *)data;
6129 MMPLAYER_RETURN_IF_FAIL(player);
6131 /* remove fakesink. */
6132 if (!__mmplayer_gst_remove_fakesink(player,
6133 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6134 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6135 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6136 * source element are not same. To overcome this situation, this function will called
6137 * several places and several times. Therefore, this is not an error case.
6142 LOGD("[handle: %p] pipeline has completely constructed", player);
6144 if ((player->ini.async_start) &&
6145 (player->msg_posted == FALSE) &&
6146 (player->cmd >= MMPLAYER_COMMAND_START))
6147 __mmplayer_handle_missed_plugin(player);
6149 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6153 __mmplayer_check_profile(void)
6156 static int profile_tv = -1;
6158 if (__builtin_expect(profile_tv != -1, 1))
6161 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6162 switch (*profileName) {
6177 __mmplayer_get_next_uri(mm_player_t *player)
6179 MMPlayerParseProfile profile;
6181 guint num_of_list = 0;
6184 num_of_list = g_list_length(player->uri_info.uri_list);
6185 uri_idx = player->uri_info.uri_idx;
6187 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6188 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6189 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6191 LOGW("next uri does not exist");
6195 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6196 LOGE("failed to parse profile");
6200 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6201 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6202 LOGW("uri type is not supported(%d)", profile.uri_type);
6206 LOGD("success to find next uri %d", uri_idx);
6210 if (uri_idx == num_of_list) {
6211 LOGE("failed to find next uri");
6215 player->uri_info.uri_idx = uri_idx;
6216 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6218 if (mm_attrs_commit_all(player->attrs)) {
6219 LOGE("failed to commit");
6223 SECURE_LOGD("next playback uri: %s", uri);
6228 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6230 #define REPEAT_COUNT_INFINITELY -1
6231 #define REPEAT_COUNT_MIN 2
6233 MMHandleType attrs = 0;
6237 guint num_of_list = 0;
6238 int profile_tv = -1;
6242 LOGD("checking for gapless play option");
6244 if (player->pipeline->textbin) {
6245 LOGE("subtitle path is enabled. gapless play is not supported.");
6249 attrs = MMPLAYER_GET_ATTRS(player);
6251 LOGE("fail to get attributes.");
6255 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6257 /* gapless playback is not supported in case of video at TV profile. */
6258 profile_tv = __mmplayer_check_profile();
6259 if (profile_tv && video) {
6260 LOGW("not support video gapless playback");
6264 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6265 LOGE("failed to get play count");
6267 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6268 LOGE("failed to get gapless mode");
6270 /* check repeat count in case of audio */
6272 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6273 LOGW("gapless is disabled");
6277 num_of_list = g_list_length(player->uri_info.uri_list);
6279 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6281 if (num_of_list == 0) {
6282 /* audio looping path */
6283 if (count >= REPEAT_COUNT_MIN) {
6284 /* decrease play count */
6285 /* we succeeded to rewind. update play count and then wait for next EOS */
6287 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6288 /* commit attribute */
6289 if (mm_attrs_commit_all(attrs))
6290 LOGE("failed to commit attribute");
6292 } else if (count != REPEAT_COUNT_INFINITELY) {
6293 LOGD("there is no next uri and no repeat");
6296 LOGD("looping cnt %d", count);
6298 /* gapless playback path */
6299 if (!__mmplayer_get_next_uri(player)) {
6300 LOGE("failed to get next uri");
6307 LOGE("unable to play gapless path. EOS will be posted soon");
6312 __mmplayer_initialize_gapless_play(mm_player_t *player)
6318 player->smooth_streaming = FALSE;
6319 player->videodec_linked = 0;
6320 player->audiodec_linked = 0;
6321 player->textsink_linked = 0;
6322 player->is_external_subtitle_present = FALSE;
6323 player->is_external_subtitle_added_now = FALSE;
6324 player->not_supported_codec = MISSING_PLUGIN_NONE;
6325 player->can_support_codec = FOUND_PLUGIN_NONE;
6326 player->pending_seek.is_pending = false;
6327 player->pending_seek.pos = 0;
6328 player->msg_posted = FALSE;
6329 player->has_many_types = FALSE;
6330 player->no_more_pad = FALSE;
6331 player->not_found_demuxer = 0;
6332 player->seek_state = MMPLAYER_SEEK_NONE;
6333 player->is_subtitle_force_drop = FALSE;
6334 player->play_subtitle = FALSE;
6335 player->adjust_subtitle_pos = 0;
6337 player->total_bitrate = 0;
6338 player->total_maximum_bitrate = 0;
6340 __mmplayer_track_initialize(player);
6341 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6343 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6344 player->bitrate[i] = 0;
6345 player->maximum_bitrate[i] = 0;
6348 if (player->v_stream_caps) {
6349 gst_caps_unref(player->v_stream_caps);
6350 player->v_stream_caps = NULL;
6353 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6355 /* clean found parsers */
6356 if (player->parsers) {
6357 GList *parsers = player->parsers;
6358 for (; parsers; parsers = g_list_next(parsers)) {
6359 gchar *name = parsers->data;
6360 MMPLAYER_FREEIF(name);
6362 g_list_free(player->parsers);
6363 player->parsers = NULL;
6366 /* clean found audio decoders */
6367 if (player->audio_decoders) {
6368 GList *a_dec = player->audio_decoders;
6369 for (; a_dec; a_dec = g_list_next(a_dec)) {
6370 gchar *name = a_dec->data;
6371 MMPLAYER_FREEIF(name);
6373 g_list_free(player->audio_decoders);
6374 player->audio_decoders = NULL;
6381 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6383 MMPlayerGstElement *mainbin = NULL;
6384 MMMessageParamType msg_param = {0,};
6385 GstElement *element = NULL;
6386 MMHandleType attrs = 0;
6388 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6392 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6393 LOGE("player is not initialized");
6397 mainbin = player->pipeline->mainbin;
6398 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6400 attrs = MMPLAYER_GET_ATTRS(player);
6402 LOGE("fail to get attributes");
6406 /* Initialize Player values */
6407 __mmplayer_initialize_gapless_play(player);
6409 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6411 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6412 LOGE("failed to parse profile");
6413 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6417 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6418 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6419 LOGE("dash or hls is not supportable");
6420 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6424 element = __mmplayer_gst_create_source(player);
6426 LOGE("no source element was created");
6430 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6431 LOGE("failed to add source element to pipeline");
6432 gst_object_unref(GST_OBJECT(element));
6437 /* take source element */
6438 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6439 mainbin[MMPLAYER_M_SRC].gst = element;
6443 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6444 if (player->streamer == NULL) {
6445 player->streamer = __mm_player_streaming_create();
6446 __mm_player_streaming_initialize(player->streamer, TRUE);
6449 elem_idx = MMPLAYER_M_TYPEFIND;
6450 element = gst_element_factory_make("typefind", "typefinder");
6451 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6452 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6454 elem_idx = MMPLAYER_M_AUTOPLUG;
6455 element = __mmplayer_gst_make_decodebin(player);
6458 /* check autoplug element is OK */
6460 LOGE("can not create element(%d)", elem_idx);
6464 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6465 LOGE("failed to add sinkbin to pipeline");
6466 gst_object_unref(GST_OBJECT(element));
6471 mainbin[elem_idx].id = elem_idx;
6472 mainbin[elem_idx].gst = element;
6474 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6475 LOGE("Failed to link src - autoplug(or typefind)");
6479 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6480 LOGE("Failed to change state of src element");
6484 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6485 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6486 LOGE("Failed to change state of decodebin");
6490 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6491 LOGE("Failed to change state of src element");
6496 player->gapless.stream_changed = TRUE;
6497 player->gapless.running = TRUE;
6503 MMPLAYER_PLAYBACK_UNLOCK(player);
6505 if (!player->msg_posted) {
6506 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6507 player->msg_posted = TRUE;
6514 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6516 mm_player_selector_t *selector = &player->selector[type];
6517 MMPlayerGstElement *sinkbin = NULL;
6518 enum MainElementID selectorId = MMPLAYER_M_NUM;
6519 enum MainElementID sinkId = MMPLAYER_M_NUM;
6520 GstPad *srcpad = NULL;
6521 GstPad *sinkpad = NULL;
6522 gboolean send_notice = FALSE;
6525 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6527 LOGD("type %d", type);
6530 case MM_PLAYER_TRACK_TYPE_AUDIO:
6531 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6532 sinkId = MMPLAYER_A_BIN;
6533 sinkbin = player->pipeline->audiobin;
6535 case MM_PLAYER_TRACK_TYPE_VIDEO:
6536 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6537 sinkId = MMPLAYER_V_BIN;
6538 sinkbin = player->pipeline->videobin;
6541 case MM_PLAYER_TRACK_TYPE_TEXT:
6542 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6543 sinkId = MMPLAYER_T_BIN;
6544 sinkbin = player->pipeline->textbin;
6547 LOGE("requested type is not supportable");
6552 if (player->pipeline->mainbin[selectorId].gst) {
6555 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6557 if (selector->event_probe_id != 0)
6558 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6559 selector->event_probe_id = 0;
6561 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6562 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6564 if (srcpad && sinkpad) {
6565 /* after getting drained signal there is no data flows, so no need to do pad_block */
6566 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6567 gst_pad_unlink(srcpad, sinkpad);
6569 /* send custom event to sink pad to handle it at video sink */
6571 LOGD("send custom event to sinkpad");
6572 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6573 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6574 gst_pad_send_event(sinkpad, event);
6578 gst_object_unref(sinkpad);
6581 gst_object_unref(srcpad);
6584 LOGD("selector release");
6586 /* release and unref requests pad from the selector */
6587 for (n = 0; n < selector->channels->len; n++) {
6588 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6589 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6591 g_ptr_array_set_size(selector->channels, 0);
6593 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6594 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6596 player->pipeline->mainbin[selectorId].gst = NULL;
6604 __mmplayer_deactivate_old_path(mm_player_t *player)
6607 MMPLAYER_RETURN_IF_FAIL(player);
6609 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6610 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6611 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6612 LOGE("deactivate selector error");
6616 __mmplayer_track_destroy(player);
6617 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6619 if (player->streamer) {
6620 __mm_player_streaming_initialize(player->streamer, FALSE);
6621 __mm_player_streaming_destroy(player->streamer);
6622 player->streamer = NULL;
6625 MMPLAYER_PLAYBACK_LOCK(player);
6626 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6633 if (!player->msg_posted) {
6634 MMMessageParamType msg = {0,};
6637 msg.code = MM_ERROR_PLAYER_INTERNAL;
6638 LOGE("gapless_uri_play> deactivate error");
6640 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6641 player->msg_posted = TRUE;
6647 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6649 int result = MM_ERROR_NONE;
6650 mm_player_t *player = (mm_player_t *)hplayer;
6653 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6655 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6656 if (mm_attrs_commit_all(player->attrs)) {
6657 LOGE("failed to commit the original uri.");
6658 result = MM_ERROR_PLAYER_INTERNAL;
6660 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6661 LOGE("failed to add the original uri in the uri list.");
6669 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6671 mm_player_t *player = (mm_player_t *)hplayer;
6672 guint num_of_list = 0;
6676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6677 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6679 if (player->pipeline && player->pipeline->textbin) {
6680 LOGE("subtitle path is enabled.");
6681 return MM_ERROR_PLAYER_INVALID_STATE;
6684 num_of_list = g_list_length(player->uri_info.uri_list);
6686 if (is_first_path) {
6687 if (num_of_list == 0) {
6688 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6689 LOGD("add original path : %s", uri);
6691 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6692 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6694 LOGD("change original path : %s", uri);
6697 MMHandleType attrs = 0;
6698 attrs = MMPLAYER_GET_ATTRS(player);
6700 if (num_of_list == 0) {
6701 char *original_uri = NULL;
6704 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6706 if (!original_uri) {
6707 LOGE("there is no original uri.");
6708 return MM_ERROR_PLAYER_INVALID_STATE;
6711 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6712 player->uri_info.uri_idx = 0;
6714 LOGD("add original path at first : %s", original_uri);
6718 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6719 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6723 return MM_ERROR_NONE;
6727 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6729 mm_player_t *player = (mm_player_t *)hplayer;
6730 char *next_uri = NULL;
6731 guint num_of_list = 0;
6734 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6736 num_of_list = g_list_length(player->uri_info.uri_list);
6738 if (num_of_list > 0) {
6739 gint uri_idx = player->uri_info.uri_idx;
6741 if (uri_idx < num_of_list-1)
6746 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6747 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6749 *uri = g_strdup(next_uri);
6753 return MM_ERROR_NONE;
6757 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6758 GstCaps *caps, gpointer data)
6760 mm_player_t *player = (mm_player_t *)data;
6761 const gchar *klass = NULL;
6762 const gchar *mime = NULL;
6763 gchar *caps_str = NULL;
6765 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6766 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6767 caps_str = gst_caps_to_string(caps);
6769 LOGW("unknown type of caps : %s from %s",
6770 caps_str, GST_ELEMENT_NAME(elem));
6772 MMPLAYER_FREEIF(caps_str);
6774 /* There is no available codec. */
6775 __mmplayer_check_not_supported_codec(player, klass, mime);
6779 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6780 GstCaps *caps, gpointer data)
6782 mm_player_t *player = (mm_player_t *)data;
6783 const char *mime = NULL;
6784 gboolean ret = TRUE;
6786 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6787 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6789 if (g_str_has_prefix(mime, "audio")) {
6790 GstStructure *caps_structure = NULL;
6791 gint samplerate = 0;
6793 gchar *caps_str = NULL;
6795 caps_structure = gst_caps_get_structure(caps, 0);
6796 gst_structure_get_int(caps_structure, "rate", &samplerate);
6797 gst_structure_get_int(caps_structure, "channels", &channels);
6799 if ((channels > 0 && samplerate == 0)) {
6800 LOGD("exclude audio...");
6804 caps_str = gst_caps_to_string(caps);
6805 /* set it directly because not sent by TAG */
6806 if (g_strrstr(caps_str, "mobile-xmf"))
6807 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6808 MMPLAYER_FREEIF(caps_str);
6809 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6810 MMMessageParamType msg_param;
6811 memset(&msg_param, 0, sizeof(MMMessageParamType));
6812 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6813 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6814 LOGD("video file is not supported on this device");
6816 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6817 LOGD("already video linked");
6820 LOGD("found new stream");
6827 __mmplayer_check_offload_path(mm_player_t *player)
6829 gboolean ret = FALSE;
6830 GstElementFactory *factory = NULL;
6833 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6835 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6836 /* FIXME : 1. need to consider the current audio output path and
6837 player have to know whether it support offload or not.
6838 2. could be added new condition about content length */
6839 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6840 if (!__mmplayer_is_only_mp3_type(player->type))
6843 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6847 LOGD("can setup the audio offload path");
6848 gst_object_unref(factory);
6857 static GstAutoplugSelectResult
6858 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6860 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6862 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6863 int audio_offload = 0;
6865 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6866 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6868 if (audio_offload && __mmplayer_check_offload_path(player)) {
6869 LOGD("expose audio path to build offload path");
6870 player->build_audio_offload = TRUE;
6871 /* update codec info */
6872 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6873 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6874 player->audiodec_linked = 1;
6876 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6880 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6882 LOGD("audio codec type: %d", codec_type);
6883 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6884 /* sw codec will be skipped */
6885 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6886 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6887 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6888 ret = GST_AUTOPLUG_SELECT_SKIP;
6892 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6893 /* hw codec will be skipped */
6894 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6895 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6896 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6897 ret = GST_AUTOPLUG_SELECT_SKIP;
6902 /* set stream information */
6903 if (!player->audiodec_linked)
6904 __mmplayer_set_audio_attrs(player, caps);
6906 /* update codec info */
6907 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6908 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6909 player->audiodec_linked = 1;
6911 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6913 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6915 LOGD("video codec type: %d", codec_type);
6916 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6917 /* sw codec is skipped */
6918 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6919 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6920 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6921 ret = GST_AUTOPLUG_SELECT_SKIP;
6925 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6926 /* hw codec is skipped */
6927 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6928 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6929 ret = GST_AUTOPLUG_SELECT_SKIP;
6934 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6935 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6937 /* mark video decoder for acquire */
6938 if (player->video_decoder_resource == NULL) {
6939 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6940 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6941 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6942 &player->video_decoder_resource)
6943 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6944 LOGE("could not mark video_decoder resource for acquire");
6945 ret = GST_AUTOPLUG_SELECT_SKIP;
6949 LOGW("video decoder resource is already acquired, skip it.");
6950 ret = GST_AUTOPLUG_SELECT_SKIP;
6954 player->interrupted_by_resource = FALSE;
6955 /* acquire resources for video playing */
6956 if (mm_resource_manager_commit(player->resource_manager)
6957 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6958 LOGE("could not acquire resources for video decoding");
6959 ret = GST_AUTOPLUG_SELECT_SKIP;
6964 /* update codec info */
6965 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6966 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6967 player->videodec_linked = 1;
6975 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6976 GstCaps *caps, GstElementFactory *factory, gpointer data)
6978 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6979 mm_player_t *player = (mm_player_t *)data;
6981 gchar *factory_name = NULL;
6982 gchar *caps_str = NULL;
6983 const gchar *klass = NULL;
6986 factory_name = GST_OBJECT_NAME(factory);
6987 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6988 caps_str = gst_caps_to_string(caps);
6990 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6992 /* store type string */
6993 if (player->type == NULL) {
6994 player->type = gst_caps_to_string(caps);
6995 __mmplayer_update_content_type_info(player);
6998 /* filtering exclude keyword */
6999 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7000 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7001 LOGW("skipping [%s] by exculde keyword [%s]",
7002 factory_name, player->ini.exclude_element_keyword[idx]);
7004 result = GST_AUTOPLUG_SELECT_SKIP;
7009 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7010 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7011 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7012 factory_name, player->ini.unsupported_codec_keyword[idx]);
7013 result = GST_AUTOPLUG_SELECT_SKIP;
7018 /* exclude webm format */
7019 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7020 * because webm format is not supportable.
7021 * If webm is disabled in "autoplug-continue", there is no state change
7022 * failure or error because the decodebin will expose the pad directly.
7023 * It make MSL invoke _prepare_async_callback.
7024 * So, we need to disable webm format in "autoplug-select" */
7025 if (caps_str && strstr(caps_str, "webm")) {
7026 LOGW("webm is not supported");
7027 result = GST_AUTOPLUG_SELECT_SKIP;
7031 /* check factory class for filtering */
7032 /* NOTE : msl don't need to use image plugins.
7033 * So, those plugins should be skipped for error handling.
7035 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7036 LOGD("skipping [%s] by not required", factory_name);
7037 result = GST_AUTOPLUG_SELECT_SKIP;
7041 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7042 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7043 // TO CHECK : subtitle if needed, add subparse exception.
7044 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7045 result = GST_AUTOPLUG_SELECT_SKIP;
7049 if (g_strrstr(factory_name, "mpegpsdemux")) {
7050 LOGD("skipping PS container - not support");
7051 result = GST_AUTOPLUG_SELECT_SKIP;
7055 if (g_strrstr(factory_name, "mssdemux"))
7056 player->smooth_streaming = TRUE;
7058 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7059 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7062 GstStructure *str = NULL;
7063 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7065 /* don't make video because of not required */
7066 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7067 (!player->set_mode.media_packet_video_stream)) {
7068 LOGD("no need video decoding, expose pad");
7069 result = GST_AUTOPLUG_SELECT_EXPOSE;
7073 /* get w/h for omx state-tune */
7074 /* FIXME: deprecated? */
7075 str = gst_caps_get_structure(caps, 0);
7076 gst_structure_get_int(str, "width", &width);
7079 if (player->v_stream_caps) {
7080 gst_caps_unref(player->v_stream_caps);
7081 player->v_stream_caps = NULL;
7084 player->v_stream_caps = gst_caps_copy(caps);
7085 LOGD("take caps for video state tune");
7086 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7090 if (g_strrstr(klass, "Codec/Decoder")) {
7091 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7092 if (result != GST_AUTOPLUG_SELECT_TRY) {
7093 LOGW("skip add decoder");
7099 MMPLAYER_FREEIF(caps_str);
7105 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7108 //mm_player_t *player = (mm_player_t *)data;
7109 GstCaps *caps = NULL;
7111 LOGD("[Decodebin2] pad-removed signal");
7113 caps = gst_pad_query_caps(new_pad, NULL);
7115 LOGW("query caps is NULL");
7119 gchar *caps_str = NULL;
7120 caps_str = gst_caps_to_string(caps);
7122 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7124 MMPLAYER_FREEIF(caps_str);
7125 gst_caps_unref(caps);
7129 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7131 mm_player_t *player = (mm_player_t *)data;
7132 GstIterator *iter = NULL;
7133 GValue item = { 0, };
7135 gboolean done = FALSE;
7136 gboolean is_all_drained = TRUE;
7139 MMPLAYER_RETURN_IF_FAIL(player);
7141 LOGD("__mmplayer_gst_decode_drained");
7143 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7144 LOGW("Fail to get cmd lock");
7148 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7149 !__mmplayer_verify_gapless_play_path(player)) {
7150 LOGD("decoding is finished.");
7151 __mmplayer_reset_gapless_state(player);
7152 MMPLAYER_CMD_UNLOCK(player);
7156 player->gapless.reconfigure = TRUE;
7158 /* check decodebin src pads whether they received EOS or not */
7159 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7162 switch (gst_iterator_next(iter, &item)) {
7163 case GST_ITERATOR_OK:
7164 pad = g_value_get_object(&item);
7165 if (pad && !GST_PAD_IS_EOS(pad)) {
7166 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7167 is_all_drained = FALSE;
7170 g_value_reset(&item);
7172 case GST_ITERATOR_RESYNC:
7173 gst_iterator_resync(iter);
7175 case GST_ITERATOR_ERROR:
7176 case GST_ITERATOR_DONE:
7181 g_value_unset(&item);
7182 gst_iterator_free(iter);
7184 if (!is_all_drained) {
7185 LOGD("Wait util the all pads get EOS.");
7186 MMPLAYER_CMD_UNLOCK(player);
7191 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7192 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7194 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7195 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7196 __mmplayer_deactivate_old_path(player);
7197 MMPLAYER_CMD_UNLOCK(player);
7203 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7205 mm_player_t *player = (mm_player_t *)data;
7206 const gchar *klass = NULL;
7207 gchar *factory_name = NULL;
7209 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7210 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7212 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7214 if (__mmplayer_add_dump_buffer_probe(player, element))
7215 LOGD("add buffer probe");
7218 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7219 gchar *selected = NULL;
7220 selected = g_strdup(GST_ELEMENT_NAME(element));
7221 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7225 if (g_strrstr(klass, "Parser")) {
7226 gchar *selected = NULL;
7228 selected = g_strdup(factory_name);
7229 player->parsers = g_list_append(player->parsers, selected);
7232 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7233 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7234 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7236 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7237 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7239 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7240 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7241 "max-video-width", player->adaptive_info.limit.width,
7242 "max-video-height", player->adaptive_info.limit.height, NULL);
7244 } else if (g_strrstr(klass, "Demuxer")) {
7245 //LOGD("plugged element is demuxer. take it");
7246 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7247 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7250 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7251 int surface_type = 0;
7253 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7256 // to support trust-zone only
7257 if (g_strrstr(factory_name, "asfdemux")) {
7258 LOGD("set file-location %s", player->profile.uri);
7259 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7260 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7261 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7262 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7263 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7264 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7265 (__mmplayer_is_only_mp3_type(player->type))) {
7266 LOGD("[mpegaudioparse] set streaming pull mode.");
7267 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7269 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7270 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7273 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7274 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7275 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7277 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7278 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7280 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7281 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7282 (MMPLAYER_IS_DASH_STREAMING(player))) {
7283 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7284 __mm_player_streaming_set_multiqueue(player->streamer, element);
7285 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7294 __mmplayer_release_misc(mm_player_t *player)
7297 bool cur_mode = player->set_mode.rich_audio;
7300 MMPLAYER_RETURN_IF_FAIL(player);
7302 player->video_stream_cb = NULL;
7303 player->video_stream_cb_user_param = NULL;
7304 player->video_stream_prerolled = false;
7306 player->audio_stream_render_cb = NULL;
7307 player->audio_stream_cb_user_param = NULL;
7308 player->audio_stream_sink_sync = false;
7310 player->video_stream_changed_cb = NULL;
7311 player->video_stream_changed_cb_user_param = NULL;
7313 player->audio_stream_changed_cb = NULL;
7314 player->audio_stream_changed_cb_user_param = NULL;
7316 player->sent_bos = FALSE;
7317 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7319 player->seek_state = MMPLAYER_SEEK_NONE;
7321 player->total_bitrate = 0;
7322 player->total_maximum_bitrate = 0;
7324 player->not_found_demuxer = 0;
7326 player->last_position = 0;
7327 player->duration = 0;
7328 player->http_content_size = 0;
7329 player->not_supported_codec = MISSING_PLUGIN_NONE;
7330 player->can_support_codec = FOUND_PLUGIN_NONE;
7331 player->pending_seek.is_pending = false;
7332 player->pending_seek.pos = 0;
7333 player->msg_posted = FALSE;
7334 player->has_many_types = FALSE;
7335 player->is_subtitle_force_drop = FALSE;
7336 player->play_subtitle = FALSE;
7337 player->adjust_subtitle_pos = 0;
7338 player->last_multiwin_status = FALSE;
7339 player->has_closed_caption = FALSE;
7340 player->set_mode.media_packet_video_stream = false;
7341 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7342 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7344 player->set_mode.rich_audio = cur_mode;
7346 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7347 player->bitrate[i] = 0;
7348 player->maximum_bitrate[i] = 0;
7351 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7353 /* remove media stream cb(appsrc cb) */
7354 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7355 player->media_stream_buffer_status_cb[i] = NULL;
7356 player->media_stream_seek_data_cb[i] = NULL;
7357 player->buffer_cb_user_param[i] = NULL;
7358 player->seek_cb_user_param[i] = NULL;
7360 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7362 /* free memory related to audio effect */
7363 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7365 if (player->adaptive_info.var_list) {
7366 g_list_free_full(player->adaptive_info.var_list, g_free);
7367 player->adaptive_info.var_list = NULL;
7370 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7371 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7372 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7374 /* Reset video360 settings to their defaults in case if the pipeline is to be
7377 player->video360_metadata.is_spherical = -1;
7378 player->is_openal_plugin_used = FALSE;
7380 player->is_content_spherical = FALSE;
7381 player->is_video360_enabled = TRUE;
7382 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7383 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7384 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7385 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7386 player->video360_zoom = 1.0f;
7387 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7388 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7390 player->sound.rg_enable = false;
7392 __mmplayer_initialize_video_roi(player);
7397 __mmplayer_release_misc_post(mm_player_t *player)
7399 char *original_uri = NULL;
7402 /* player->pipeline is already released before. */
7404 MMPLAYER_RETURN_IF_FAIL(player);
7406 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7408 /* clean found parsers */
7409 if (player->parsers) {
7410 GList *parsers = player->parsers;
7411 for (; parsers; parsers = g_list_next(parsers)) {
7412 gchar *name = parsers->data;
7413 MMPLAYER_FREEIF(name);
7415 g_list_free(player->parsers);
7416 player->parsers = NULL;
7419 /* clean found audio decoders */
7420 if (player->audio_decoders) {
7421 GList *a_dec = player->audio_decoders;
7422 for (; a_dec; a_dec = g_list_next(a_dec)) {
7423 gchar *name = a_dec->data;
7424 MMPLAYER_FREEIF(name);
7426 g_list_free(player->audio_decoders);
7427 player->audio_decoders = NULL;
7430 /* clean the uri list except original uri */
7431 if (player->uri_info.uri_list) {
7432 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7434 if (player->attrs) {
7435 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7436 LOGD("restore original uri = %s", original_uri);
7438 if (mm_attrs_commit_all(player->attrs))
7439 LOGE("failed to commit the original uri.");
7442 GList *uri_list = player->uri_info.uri_list;
7443 for (; uri_list; uri_list = g_list_next(uri_list)) {
7444 gchar *uri = uri_list->data;
7445 MMPLAYER_FREEIF(uri);
7447 g_list_free(player->uri_info.uri_list);
7448 player->uri_info.uri_list = NULL;
7451 /* clear the audio stream buffer list */
7452 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7454 /* clear the video stream bo list */
7455 __mmplayer_video_stream_destroy_bo_list(player);
7456 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7458 if (player->profile.input_mem.buf) {
7459 free(player->profile.input_mem.buf);
7460 player->profile.input_mem.buf = NULL;
7462 player->profile.input_mem.len = 0;
7463 player->profile.input_mem.offset = 0;
7465 player->uri_info.uri_idx = 0;
7470 __mmplayer_check_subtitle(mm_player_t *player)
7472 MMHandleType attrs = 0;
7473 char *subtitle_uri = NULL;
7477 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7479 /* get subtitle attribute */
7480 attrs = MMPLAYER_GET_ATTRS(player);
7484 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7485 if (!subtitle_uri || !strlen(subtitle_uri))
7488 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7489 player->is_external_subtitle_present = TRUE;
7497 __mmplayer_cancel_eos_timer(mm_player_t *player)
7499 MMPLAYER_RETURN_IF_FAIL(player);
7501 if (player->eos_timer) {
7502 LOGD("cancel eos timer");
7503 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7504 player->eos_timer = 0;
7511 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7515 MMPLAYER_RETURN_IF_FAIL(player);
7516 MMPLAYER_RETURN_IF_FAIL(sink);
7518 player->sink_elements = g_list_append(player->sink_elements, sink);
7524 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7528 MMPLAYER_RETURN_IF_FAIL(player);
7529 MMPLAYER_RETURN_IF_FAIL(sink);
7531 player->sink_elements = g_list_remove(player->sink_elements, sink);
7537 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7538 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7540 MMPlayerSignalItem *item = NULL;
7543 MMPLAYER_RETURN_IF_FAIL(player);
7545 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7546 LOGE("invalid signal type [%d]", type);
7550 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7552 LOGE("cannot connect signal [%s]", signal);
7557 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7558 player->signals[type] = g_list_append(player->signals[type], item);
7564 /* NOTE : be careful with calling this api. please refer to below glib comment
7565 * glib comment : Note that there is a bug in GObject that makes this function much
7566 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7567 * will no longer be called, but, the signal handler is not currently disconnected.
7568 * If the instance is itself being freed at the same time than this doesn't matter,
7569 * since the signal will automatically be removed, but if instance persists,
7570 * then the signal handler will leak. You should not remove the signal yourself
7571 * because in a future versions of GObject, the handler will automatically be
7574 * It's possible to work around this problem in a way that will continue to work
7575 * with future versions of GObject by checking that the signal handler is still
7576 * connected before disconnected it:
7578 * if (g_signal_handler_is_connected(instance, id))
7579 * g_signal_handler_disconnect(instance, id);
7582 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7584 GList *sig_list = NULL;
7585 MMPlayerSignalItem *item = NULL;
7589 MMPLAYER_RETURN_IF_FAIL(player);
7591 LOGD("release signals type : %d", type);
7593 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7594 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7595 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7596 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7598 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7602 sig_list = player->signals[type];
7604 for (; sig_list; sig_list = sig_list->next) {
7605 item = sig_list->data;
7607 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7608 if (g_signal_handler_is_connected(item->obj, item->sig))
7609 g_signal_handler_disconnect(item->obj, item->sig);
7612 MMPLAYER_FREEIF(item);
7615 g_list_free(player->signals[type]);
7616 player->signals[type] = NULL;
7624 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7626 mm_player_t *player = 0;
7627 int prev_display_surface_type = 0;
7628 void *prev_display_overlay = NULL;
7632 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7633 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7635 player = MM_PLAYER_CAST(handle);
7637 /* check video sinkbin is created */
7638 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7639 LOGE("Videosink is already created");
7640 return MM_ERROR_NONE;
7643 LOGD("videosink element is not yet ready");
7645 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7646 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7648 return MM_ERROR_INVALID_ARGUMENT;
7651 /* load previous attributes */
7652 if (player->attrs) {
7653 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7654 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7655 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7656 if (prev_display_surface_type == surface_type) {
7657 LOGD("incoming display surface type is same as previous one, do nothing..");
7659 return MM_ERROR_NONE;
7662 LOGE("failed to load attributes");
7664 return MM_ERROR_PLAYER_INTERNAL;
7667 /* videobin is not created yet, so we just set attributes related to display surface */
7668 LOGD("store display attribute for given surface type(%d)", surface_type);
7669 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7670 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7671 if (mm_attrs_commit_all(player->attrs)) {
7672 LOGE("failed to commit attribute");
7674 return MM_ERROR_PLAYER_INTERNAL;
7678 return MM_ERROR_NONE;
7681 /* Note : if silent is true, then subtitle would not be displayed. :*/
7683 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7685 mm_player_t *player = (mm_player_t *)hplayer;
7689 /* check player handle */
7690 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7692 player->set_mode.subtitle_off = silent;
7694 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7698 return MM_ERROR_NONE;
7702 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7704 MMPlayerGstElement *mainbin = NULL;
7705 MMPlayerGstElement *textbin = NULL;
7706 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7707 GstState current_state = GST_STATE_VOID_PENDING;
7708 GstState element_state = GST_STATE_VOID_PENDING;
7709 GstState element_pending_state = GST_STATE_VOID_PENDING;
7711 GstEvent *event = NULL;
7712 int result = MM_ERROR_NONE;
7714 GstClock *curr_clock = NULL;
7715 GstClockTime base_time, start_time, curr_time;
7720 /* check player handle */
7721 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7723 player->pipeline->mainbin &&
7724 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7726 mainbin = player->pipeline->mainbin;
7727 textbin = player->pipeline->textbin;
7729 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7731 // sync clock with current pipeline
7732 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7733 curr_time = gst_clock_get_time(curr_clock);
7735 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7736 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7738 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7739 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7741 if (current_state > GST_STATE_READY) {
7742 // sync state with current pipeline
7743 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7744 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7745 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7747 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7748 if (GST_STATE_CHANGE_FAILURE == ret) {
7749 LOGE("fail to state change.");
7750 result = MM_ERROR_PLAYER_INTERNAL;
7754 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7755 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7758 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7759 gst_object_unref(curr_clock);
7762 // seek to current position
7763 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7764 result = MM_ERROR_PLAYER_INVALID_STATE;
7765 LOGE("gst_element_query_position failed, invalid state");
7769 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7770 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);
7772 __mmplayer_gst_send_event_to_sink(player, event);
7774 result = MM_ERROR_PLAYER_INTERNAL;
7775 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7779 /* sync state with current pipeline */
7780 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7781 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7782 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7784 return MM_ERROR_NONE;
7787 /* release text pipeline resource */
7788 player->textsink_linked = 0;
7790 /* release signal */
7791 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7793 /* release textbin with it's childs */
7794 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7795 MMPLAYER_FREEIF(player->pipeline->textbin);
7796 player->pipeline->textbin = NULL;
7798 /* release subtitle elem */
7799 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7800 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7806 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7808 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7809 GstState current_state = GST_STATE_VOID_PENDING;
7811 MMHandleType attrs = 0;
7812 MMPlayerGstElement *mainbin = NULL;
7813 MMPlayerGstElement *textbin = NULL;
7815 gchar *subtitle_uri = NULL;
7816 int result = MM_ERROR_NONE;
7817 const gchar *charset = NULL;
7821 /* check player handle */
7822 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7824 player->pipeline->mainbin &&
7825 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7826 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7828 mainbin = player->pipeline->mainbin;
7829 textbin = player->pipeline->textbin;
7831 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7832 if (current_state < GST_STATE_READY) {
7833 result = MM_ERROR_PLAYER_INVALID_STATE;
7834 LOGE("Pipeline is not in proper state");
7838 attrs = MMPLAYER_GET_ATTRS(player);
7840 LOGE("cannot get content attribute");
7841 result = MM_ERROR_PLAYER_INTERNAL;
7845 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7846 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7847 LOGE("subtitle uri is not proper filepath");
7848 result = MM_ERROR_PLAYER_INVALID_URI;
7852 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7853 LOGE("failed to get storage info of subtitle path");
7854 result = MM_ERROR_PLAYER_INVALID_URI;
7858 LOGD("old subtitle file path is [%s]", subtitle_uri);
7859 LOGD("new subtitle file path is [%s]", filepath);
7861 if (!strcmp(filepath, subtitle_uri)) {
7862 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7865 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7866 if (mm_attrs_commit_all(player->attrs)) {
7867 LOGE("failed to commit.");
7872 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7873 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7874 player->subtitle_language_list = NULL;
7875 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7877 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7878 if (ret != GST_STATE_CHANGE_SUCCESS) {
7879 LOGE("failed to change state of textbin to READY");
7880 result = MM_ERROR_PLAYER_INTERNAL;
7884 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7885 if (ret != GST_STATE_CHANGE_SUCCESS) {
7886 LOGE("failed to change state of subparse to READY");
7887 result = MM_ERROR_PLAYER_INTERNAL;
7891 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7892 if (ret != GST_STATE_CHANGE_SUCCESS) {
7893 LOGE("failed to change state of filesrc to READY");
7894 result = MM_ERROR_PLAYER_INTERNAL;
7898 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7900 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7902 charset = util_get_charset(filepath);
7904 LOGD("detected charset is %s", charset);
7905 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7908 result = _mmplayer_sync_subtitle_pipeline(player);
7915 /* API to switch between external subtitles */
7917 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7919 int result = MM_ERROR_NONE;
7920 mm_player_t *player = (mm_player_t *)hplayer;
7925 /* check player handle */
7926 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7928 /* filepath can be null in idle state */
7930 /* check file path */
7931 if ((path = strstr(filepath, "file://")))
7932 result = util_exist_file_path(path + 7);
7934 result = util_exist_file_path(filepath);
7936 if (result != MM_ERROR_NONE) {
7937 LOGE("invalid subtitle path 0x%X", result);
7938 return result; /* file not found or permission denied */
7942 if (!player->pipeline) {
7944 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7945 if (mm_attrs_commit_all(player->attrs)) {
7946 LOGE("failed to commit"); /* subtitle path will not be created */
7947 return MM_ERROR_PLAYER_INTERNAL;
7950 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7951 /* check filepath */
7952 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7954 if (!__mmplayer_check_subtitle(player)) {
7955 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7956 if (mm_attrs_commit_all(player->attrs)) {
7957 LOGE("failed to commit");
7958 return MM_ERROR_PLAYER_INTERNAL;
7961 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7962 LOGE("fail to create text pipeline");
7963 return MM_ERROR_PLAYER_INTERNAL;
7966 result = _mmplayer_sync_subtitle_pipeline(player);
7968 result = __mmplayer_change_external_subtitle_language(player, filepath);
7971 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7972 player->is_external_subtitle_added_now = TRUE;
7974 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7975 if (!player->subtitle_language_list) {
7976 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7977 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7978 LOGW("subtitle language list is not updated yet");
7980 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7988 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7990 int result = MM_ERROR_NONE;
7991 gchar *change_pad_name = NULL;
7992 GstPad *sinkpad = NULL;
7993 MMPlayerGstElement *mainbin = NULL;
7994 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7995 GstCaps *caps = NULL;
7996 gint total_track_num = 0;
8000 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8001 MM_ERROR_PLAYER_NOT_INITIALIZED);
8003 LOGD("Change Track(%d) to %d", type, index);
8005 mainbin = player->pipeline->mainbin;
8007 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8008 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8009 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8010 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8012 /* Changing Video Track is not supported. */
8013 LOGE("Track Type Error");
8017 if (mainbin[elem_idx].gst == NULL) {
8018 result = MM_ERROR_PLAYER_NO_OP;
8019 LOGD("Req track doesn't exist");
8023 total_track_num = player->selector[type].total_track_num;
8024 if (total_track_num <= 0) {
8025 result = MM_ERROR_PLAYER_NO_OP;
8026 LOGD("Language list is not available");
8030 if ((index < 0) || (index >= total_track_num)) {
8031 result = MM_ERROR_INVALID_ARGUMENT;
8032 LOGD("Not a proper index : %d", index);
8036 /*To get the new pad from the selector*/
8037 change_pad_name = g_strdup_printf("sink_%u", index);
8038 if (change_pad_name == NULL) {
8039 result = MM_ERROR_PLAYER_INTERNAL;
8040 LOGD("Pad does not exists");
8044 LOGD("new active pad name: %s", change_pad_name);
8046 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8047 if (sinkpad == NULL) {
8048 LOGD("sinkpad is NULL");
8049 result = MM_ERROR_PLAYER_INTERNAL;
8053 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8054 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8056 caps = gst_pad_get_current_caps(sinkpad);
8057 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8060 gst_object_unref(sinkpad);
8062 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8063 __mmplayer_set_audio_attrs(player, caps);
8066 MMPLAYER_FREEIF(change_pad_name);
8071 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8073 int result = MM_ERROR_NONE;
8074 mm_player_t *player = NULL;
8075 MMPlayerGstElement *mainbin = NULL;
8077 gint current_active_index = 0;
8079 GstState current_state = GST_STATE_VOID_PENDING;
8080 GstEvent *event = NULL;
8085 player = (mm_player_t *)hplayer;
8086 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8088 if (!player->pipeline) {
8089 LOGE("Track %d pre setting -> %d", type, index);
8091 player->selector[type].active_pad_index = index;
8095 mainbin = player->pipeline->mainbin;
8097 current_active_index = player->selector[type].active_pad_index;
8099 /*If index is same as running index no need to change the pad*/
8100 if (current_active_index == index)
8103 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8104 result = MM_ERROR_PLAYER_INVALID_STATE;
8108 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8109 if (current_state < GST_STATE_PAUSED) {
8110 result = MM_ERROR_PLAYER_INVALID_STATE;
8111 LOGW("Pipeline not in porper state");
8115 result = __mmplayer_change_selector_pad(player, type, index);
8116 if (result != MM_ERROR_NONE) {
8117 LOGE("change selector pad error");
8121 player->selector[type].active_pad_index = index;
8123 if (current_state == GST_STATE_PLAYING) {
8124 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8125 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8126 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8128 __mmplayer_gst_send_event_to_sink(player, event);
8130 result = MM_ERROR_PLAYER_INTERNAL;
8140 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8142 mm_player_t *player = (mm_player_t *)hplayer;
8146 /* check player handle */
8147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8149 *silent = player->set_mode.subtitle_off;
8151 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8155 return MM_ERROR_NONE;
8159 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8161 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8162 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8164 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8165 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8169 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8170 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8171 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8172 mm_player_dump_t *dump_s;
8173 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8174 if (dump_s == NULL) {
8175 LOGE("malloc fail");
8179 dump_s->dump_element_file = NULL;
8180 dump_s->dump_pad = NULL;
8181 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8183 if (dump_s->dump_pad) {
8184 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8185 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]);
8186 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8187 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);
8188 /* add list for removed buffer probe and close FILE */
8189 player->dump_list = g_list_append(player->dump_list, dump_s);
8190 LOGD("%s sink pad added buffer probe for dump", factory_name);
8193 MMPLAYER_FREEIF(dump_s);
8194 LOGE("failed to get %s sink pad added", factory_name);
8201 static GstPadProbeReturn
8202 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8204 FILE *dump_data = (FILE *)u_data;
8206 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8207 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8209 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8211 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8213 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8215 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8217 return GST_PAD_PROBE_OK;
8221 __mmplayer_release_dump_list(GList *dump_list)
8223 GList *d_list = dump_list;
8228 for (; d_list; d_list = g_list_next(d_list)) {
8229 mm_player_dump_t *dump_s = d_list->data;
8230 if (dump_s->dump_pad) {
8231 if (dump_s->probe_handle_id)
8232 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8234 if (dump_s->dump_element_file) {
8235 fclose(dump_s->dump_element_file);
8236 dump_s->dump_element_file = NULL;
8238 MMPLAYER_FREEIF(dump_s);
8240 g_list_free(dump_list);
8245 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8247 mm_player_t *player = (mm_player_t *)hplayer;
8251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8252 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8254 *exist = (bool)player->has_closed_caption;
8258 return MM_ERROR_NONE;
8262 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8266 // LOGD("unref internal gst buffer %p", buffer);
8267 gst_buffer_unref((GstBuffer *)buffer);
8274 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8276 mm_player_t *player = (mm_player_t *)hplayer;
8280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8281 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8283 if (MMPLAYER_IS_STREAMING(player))
8284 *timeout = (int)player->ini.live_state_change_timeout;
8286 *timeout = (int)player->ini.localplayback_state_change_timeout;
8288 LOGD("timeout = %d", *timeout);
8291 return MM_ERROR_NONE;
8295 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8297 mm_player_t *player = (mm_player_t *)hplayer;
8301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8302 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8304 *num = player->video_num_buffers;
8305 *extra_num = player->video_extra_num_buffers;
8307 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8310 return MM_ERROR_NONE;
8314 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8318 MMPLAYER_RETURN_IF_FAIL(player);
8320 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8322 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8323 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8324 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8325 player->storage_info[i].id = -1;
8326 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8328 if (path_type != MMPLAYER_PATH_MAX)
8337 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8339 int ret = MM_ERROR_NONE;
8340 mm_player_t *player = (mm_player_t *)hplayer;
8341 MMMessageParamType msg_param = {0, };
8344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8346 LOGW("state changed storage %d:%d", id, state);
8348 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8349 return MM_ERROR_NONE;
8351 /* FIXME: text path should be handled seperately. */
8352 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8353 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8354 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8355 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8356 LOGW("external storage is removed");
8358 if (player->msg_posted == FALSE) {
8359 memset(&msg_param, 0, sizeof(MMMessageParamType));
8360 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8361 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8362 player->msg_posted = TRUE;
8365 /* unrealize the player */
8366 ret = _mmplayer_unrealize(hplayer);
8367 if (ret != MM_ERROR_NONE)
8368 LOGE("failed to unrealize");
8376 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8378 int ret = MM_ERROR_NONE;
8379 mm_player_t *player = (mm_player_t *)hplayer;
8380 int idx = 0, total = 0;
8381 gchar *result = NULL, *tmp = NULL;
8384 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8385 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8387 total = *num = g_list_length(player->adaptive_info.var_list);
8389 LOGW("There is no stream variant info.");
8393 result = g_strdup("");
8394 for (idx = 0 ; idx < total ; idx++) {
8395 VariantData *v_data = NULL;
8396 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8399 gchar data[64] = {0};
8400 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8402 tmp = g_strconcat(result, data, NULL);
8406 LOGW("There is no variant data in %d", idx);
8411 *var_info = (char *)result;
8413 LOGD("variant info %d:%s", *num, *var_info);
8419 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8421 int ret = MM_ERROR_NONE;
8422 mm_player_t *player = (mm_player_t *)hplayer;
8425 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8427 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8429 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8430 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8431 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8433 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8434 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8435 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8436 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8438 /* FIXME: seek to current position for applying new variant limitation */
8447 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8449 int ret = MM_ERROR_NONE;
8450 mm_player_t *player = (mm_player_t *)hplayer;
8453 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8454 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8456 *bandwidth = player->adaptive_info.limit.bandwidth;
8457 *width = player->adaptive_info.limit.width;
8458 *height = player->adaptive_info.limit.height;
8460 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8467 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8469 int ret = MM_ERROR_NONE;
8470 mm_player_t *player = (mm_player_t *)hplayer;
8473 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8475 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8477 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8479 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8480 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8481 else /* live case */
8482 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8484 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8491 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8493 #define IDX_FIRST_SW_CODEC 0
8494 mm_player_t *player = (mm_player_t *)hplayer;
8495 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8496 MMHandleType attrs = 0;
8499 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8501 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8502 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8503 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8505 switch (stream_type) {
8506 case MM_PLAYER_STREAM_TYPE_AUDIO:
8507 /* to support audio codec selection, codec info have to be added in ini file as below.
8508 audio codec element hw = xxxx
8509 audio codec element sw = avdec */
8510 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8511 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8512 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8513 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8514 LOGE("There is no audio codec info for codec_type %d", codec_type);
8515 return MM_ERROR_PLAYER_NO_OP;
8518 case MM_PLAYER_STREAM_TYPE_VIDEO:
8519 /* to support video codec selection, codec info have to be added in ini file as below.
8520 video codec element hw = omx
8521 video codec element sw = avdec */
8522 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8523 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8524 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8525 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8526 LOGE("There is no video codec info for codec_type %d", codec_type);
8527 return MM_ERROR_PLAYER_NO_OP;
8531 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8532 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8536 LOGD("update %s codec_type to %d", attr_name, codec_type);
8538 attrs = MMPLAYER_GET_ATTRS(player);
8539 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8541 if (mm_attrs_commit_all(player->attrs)) {
8542 LOGE("failed to commit codec_type attributes");
8543 return MM_ERROR_PLAYER_INTERNAL;
8547 return MM_ERROR_NONE;
8551 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8553 mm_player_t *player = (mm_player_t *)hplayer;
8554 GstElement *rg_vol_element = NULL;
8558 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8560 player->sound.rg_enable = enabled;
8562 /* just hold rgvolume enable value if pipeline is not ready */
8563 if (!player->pipeline || !player->pipeline->audiobin) {
8564 LOGD("pipeline is not ready. holding rgvolume enable value");
8565 return MM_ERROR_NONE;
8568 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8570 if (!rg_vol_element) {
8571 LOGD("rgvolume element is not created");
8572 return MM_ERROR_PLAYER_INTERNAL;
8576 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8578 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8582 return MM_ERROR_NONE;
8586 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8588 mm_player_t *player = (mm_player_t *)hplayer;
8589 GstElement *rg_vol_element = NULL;
8590 gboolean enable = FALSE;
8594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8597 /* just hold enable_rg value if pipeline is not ready */
8598 if (!player->pipeline || !player->pipeline->audiobin) {
8599 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8600 *enabled = player->sound.rg_enable;
8601 return MM_ERROR_NONE;
8604 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8606 if (!rg_vol_element) {
8607 LOGD("rgvolume element is not created");
8608 return MM_ERROR_PLAYER_INTERNAL;
8611 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8612 *enabled = (bool)enable;
8616 return MM_ERROR_NONE;
8620 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8622 mm_player_t *player = (mm_player_t *)hplayer;
8623 MMHandleType attrs = 0;
8624 void *handle = NULL;
8625 int ret = MM_ERROR_NONE;
8629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8631 attrs = MMPLAYER_GET_ATTRS(player);
8632 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8634 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8636 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8637 return MM_ERROR_PLAYER_INTERNAL;
8640 player->video_roi.scale_x = scale_x;
8641 player->video_roi.scale_y = scale_y;
8642 player->video_roi.scale_width = scale_width;
8643 player->video_roi.scale_height = scale_height;
8645 /* check video sinkbin is created */
8646 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8647 return MM_ERROR_NONE;
8649 if (!gst_video_overlay_set_video_roi_area(
8650 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8651 scale_x, scale_y, scale_width, scale_height))
8652 ret = MM_ERROR_PLAYER_INTERNAL;
8654 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8655 scale_x, scale_y, scale_width, scale_height);
8663 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8665 mm_player_t *player = (mm_player_t *)hplayer;
8666 int ret = MM_ERROR_NONE;
8670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8671 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8673 *scale_x = player->video_roi.scale_x;
8674 *scale_y = player->video_roi.scale_y;
8675 *scale_width = player->video_roi.scale_width;
8676 *scale_height = player->video_roi.scale_height;
8678 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8679 *scale_x, *scale_y, *scale_width, *scale_height);
8685 __mmplayer_update_duration_value(mm_player_t *player)
8687 gboolean ret = FALSE;
8688 gint64 dur_nsec = 0;
8689 LOGD("try to update duration");
8691 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8692 player->duration = dur_nsec;
8693 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8697 if (player->duration < 0) {
8698 LOGW("duration is Non-Initialized !!!");
8699 player->duration = 0;
8702 /* update streaming service type */
8703 player->streaming_type = __mmplayer_get_stream_service_type(player);
8705 /* check duration is OK */
8706 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8707 /* FIXIT : find another way to get duration here. */
8708 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8714 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8716 /* update audio params
8717 NOTE : We need original audio params and it can be only obtained from src pad of audio
8718 decoder. Below code only valid when we are not using 'resampler' just before
8719 'audioconverter'. */
8720 GstCaps *caps_a = NULL;
8722 gint samplerate = 0, channels = 0;
8723 GstStructure *p = NULL;
8725 LOGD("try to update audio attrs");
8727 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8728 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8730 pad = gst_element_get_static_pad(
8731 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8734 LOGW("failed to get pad from audiosink");
8738 caps_a = gst_pad_get_current_caps(pad);
8740 LOGW("not ready to get audio caps");
8741 gst_object_unref(pad);
8745 p = gst_caps_get_structure(caps_a, 0);
8747 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8749 gst_structure_get_int(p, "rate", &samplerate);
8750 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8752 gst_structure_get_int(p, "channels", &channels);
8753 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8755 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8757 gst_caps_unref(caps_a);
8758 gst_object_unref(pad);
8764 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8766 LOGD("try to update video attrs");
8768 GstCaps *caps_v = NULL;
8772 GstStructure *p = NULL;
8774 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8775 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8777 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8779 LOGD("no videosink sink pad");
8783 caps_v = gst_pad_get_current_caps(pad);
8784 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8785 if (!caps_v && player->v_stream_caps) {
8786 caps_v = player->v_stream_caps;
8787 gst_caps_ref(caps_v);
8791 LOGD("no negitiated caps from videosink");
8792 gst_object_unref(pad);
8796 p = gst_caps_get_structure(caps_v, 0);
8797 gst_structure_get_int(p, "width", &width);
8798 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8800 gst_structure_get_int(p, "height", &height);
8801 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8803 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8805 SECURE_LOGD("width : %d height : %d", width, height);
8807 gst_caps_unref(caps_v);
8808 gst_object_unref(pad);
8811 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8812 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8819 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8821 gboolean ret = FALSE;
8822 guint64 data_size = 0;
8826 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8827 if (!player->duration)
8830 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8831 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8832 if (stat(path, &sb) == 0)
8833 data_size = (guint64)sb.st_size;
8835 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8836 data_size = player->http_content_size;
8839 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8842 guint64 bitrate = 0;
8843 guint64 msec_dur = 0;
8845 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8847 bitrate = data_size * 8 * 1000 / msec_dur;
8848 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8849 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8853 LOGD("player duration is less than 0");
8857 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8858 if (player->total_bitrate) {
8859 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8868 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8870 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8871 data->uri_type = uri_type;
8875 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8877 int ret = MM_ERROR_PLAYER_INVALID_URI;
8879 char *buffer = NULL;
8880 char *seperator = strchr(path, ',');
8881 char ext[100] = {0,}, size[100] = {0,};
8884 if ((buffer = strstr(path, "ext="))) {
8885 buffer += strlen("ext=");
8887 if (strlen(buffer)) {
8888 strncpy(ext, buffer, 99);
8890 if ((seperator = strchr(ext, ','))
8891 || (seperator = strchr(ext, ' '))
8892 || (seperator = strchr(ext, '\0'))) {
8893 seperator[0] = '\0';
8898 if ((buffer = strstr(path, "size="))) {
8899 buffer += strlen("size=");
8901 if (strlen(buffer) > 0) {
8902 strncpy(size, buffer, 99);
8904 if ((seperator = strchr(size, ','))
8905 || (seperator = strchr(size, ' '))
8906 || (seperator = strchr(size, '\0'))) {
8907 seperator[0] = '\0';
8910 mem_size = atoi(size);
8915 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8917 if (mem_size && param) {
8918 if (data->input_mem.buf)
8919 free(data->input_mem.buf);
8920 data->input_mem.buf = malloc(mem_size);
8922 if (data->input_mem.buf) {
8923 memcpy(data->input_mem.buf, param, mem_size);
8924 data->input_mem.len = mem_size;
8925 ret = MM_ERROR_NONE;
8927 LOGE("failed to alloc mem %d", mem_size);
8928 ret = MM_ERROR_PLAYER_INTERNAL;
8931 data->input_mem.offset = 0;
8932 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8939 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8941 gchar *location = NULL;
8944 int ret = MM_ERROR_NONE;
8946 if ((path = strstr(uri, "file://"))) {
8947 location = g_filename_from_uri(uri, NULL, &err);
8948 if (!location || (err != NULL)) {
8949 LOGE("Invalid URI '%s' for filesrc: %s", path,
8950 (err != NULL) ? err->message : "unknown error");
8954 MMPLAYER_FREEIF(location);
8956 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8957 return MM_ERROR_PLAYER_INVALID_URI;
8959 LOGD("path from uri: %s", location);
8962 path = (location != NULL) ? (location) : ((char *)uri);
8965 ret = util_exist_file_path(path);
8967 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8968 if (ret == MM_ERROR_NONE) {
8969 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8970 if (util_is_sdp_file(path)) {
8971 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8972 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8974 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8976 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8977 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8979 LOGE("invalid uri, could not play..");
8980 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8983 MMPLAYER_FREEIF(location);
8988 static MMPlayerVideoStreamDataType *
8989 __mmplayer_create_stream_from_pad(GstPad *pad)
8991 GstCaps *caps = NULL;
8992 GstStructure *structure = NULL;
8993 unsigned int fourcc = 0;
8994 const gchar *string_format = NULL;
8995 MMPlayerVideoStreamDataType *stream = NULL;
8997 MMPixelFormatType format;
8999 caps = gst_pad_get_current_caps(pad);
9001 LOGE("Caps is NULL.");
9005 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9006 structure = gst_caps_get_structure(caps, 0);
9007 gst_structure_get_int(structure, "width", &width);
9008 gst_structure_get_int(structure, "height", &height);
9009 string_format = gst_structure_get_string(structure, "format");
9011 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9012 format = util_get_pixtype(fourcc);
9013 gst_caps_unref(caps);
9016 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9017 LOGE("Wrong condition!!");
9021 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9023 LOGE("failed to alloc mem for video data");
9027 stream->width = width;
9028 stream->height = height;
9029 stream->format = format;
9035 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9037 unsigned int pitch = 0;
9039 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9041 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9042 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9043 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9044 stream->stride[index] = pitch;
9045 stream->elevation[index] = stream->height;
9050 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9052 if (stream->format == MM_PIXEL_FORMAT_I420) {
9053 int ret = TBM_SURFACE_ERROR_NONE;
9054 tbm_surface_h surface;
9055 tbm_surface_info_s info;
9057 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9059 ret = tbm_surface_get_info(surface, &info);
9060 if (ret != TBM_SURFACE_ERROR_NONE) {
9061 tbm_surface_destroy(surface);
9065 tbm_surface_destroy(surface);
9066 stream->stride[0] = info.planes[0].stride;
9067 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9068 stream->stride[1] = info.planes[1].stride;
9069 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9070 stream->stride[2] = info.planes[2].stride;
9071 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9072 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9073 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9074 stream->stride[0] = stream->width * 4;
9075 stream->elevation[0] = stream->height;
9076 stream->bo_size = stream->stride[0] * stream->height;
9078 LOGE("Not support format %d", stream->format);
9086 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9088 tbm_bo_handle thandle;
9090 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9091 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9092 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9096 unsigned char *src = NULL;
9097 unsigned char *dest = NULL;
9098 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9100 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9102 LOGE("fail to gst_memory_map");
9106 if (!mapinfo.data) {
9107 LOGE("data pointer is wrong");
9111 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9112 if (!stream->bo[0]) {
9113 LOGE("Fail to tbm_bo_alloc!!");
9117 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9119 LOGE("thandle pointer is wrong");
9123 if (stream->format == MM_PIXEL_FORMAT_I420) {
9124 src_stride[0] = GST_ROUND_UP_4(stream->width);
9125 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9126 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9127 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9130 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9131 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9133 for (i = 0; i < 3; i++) {
9134 src = mapinfo.data + src_offset[i];
9135 dest = thandle.ptr + dest_offset[i];
9140 for (j = 0; j < stream->height >> k; j++) {
9141 memcpy(dest, src, stream->width>>k);
9142 src += src_stride[i];
9143 dest += stream->stride[i];
9146 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9147 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9149 LOGE("Not support format %d", stream->format);
9153 tbm_bo_unmap(stream->bo[0]);
9154 gst_memory_unmap(mem, &mapinfo);
9160 tbm_bo_unmap(stream->bo[0]);
9163 gst_memory_unmap(mem, &mapinfo);
9169 __mmplayer_set_pause_state(mm_player_t *player)
9171 if (player->sent_bos)
9174 /* rtsp case, get content attrs by GstMessage */
9175 if (MMPLAYER_IS_RTSP_STREAMING(player))
9178 /* it's first time to update all content attrs. */
9179 __mmplayer_update_content_attrs(player, ATTR_ALL);
9183 __mmplayer_set_playing_state(mm_player_t *player)
9185 gchar *audio_codec = NULL;
9187 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9188 /* initialize because auto resume is done well. */
9189 player->resumed_by_rewind = FALSE;
9190 player->playback_rate = 1.0;
9193 if (player->sent_bos)
9196 /* try to get content metadata */
9198 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9199 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9200 * legacy mmfw-player api
9202 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9204 if ((player->cmd == MMPLAYER_COMMAND_START)
9205 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9206 __mmplayer_handle_missed_plugin(player);
9209 /* check audio codec field is set or not
9210 * we can get it from typefinder or codec's caps.
9212 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9214 /* The codec format can't be sent for audio only case like amr, mid etc.
9215 * Because, parser don't make related TAG.
9216 * So, if it's not set yet, fill it with found data.
9219 if (g_strrstr(player->type, "audio/midi"))
9220 audio_codec = "MIDI";
9221 else if (g_strrstr(player->type, "audio/x-amr"))
9222 audio_codec = "AMR";
9223 else if (g_strrstr(player->type, "audio/mpeg")
9224 && !g_strrstr(player->type, "mpegversion= (int)1"))
9225 audio_codec = "AAC";
9227 audio_codec = "unknown";
9229 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9231 if (mm_attrs_commit_all(player->attrs))
9232 LOGE("failed to update attributes");
9234 LOGD("set audio codec type with caps");