4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
113 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
114 We are defining our own and will be removed when it actually exposed */
116 GST_AUTOPLUG_SELECT_TRY,
117 GST_AUTOPLUG_SELECT_EXPOSE,
118 GST_AUTOPLUG_SELECT_SKIP
119 } GstAutoplugSelectResult;
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
135 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
136 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
137 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
142 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
143 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
144 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
152 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_release_misc(mm_player_t *player);
154 static void __mmplayer_release_misc_post(mm_player_t *player);
155 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
156 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
159 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
161 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
162 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
163 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
164 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
165 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
166 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
167 static gpointer __mmplayer_gapless_play_thread(gpointer data);
168 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
169 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static void __mmplayer_release_dump_list(GList *dump_list);
171 static int __mmplayer_gst_realize(mm_player_t *player);
172 static int __mmplayer_gst_unrealize(mm_player_t *player);
173 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
174 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
177 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
178 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
179 static void __mmplayer_check_pipeline(mm_player_t *player);
180 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
181 static void __mmplayer_deactivate_old_path(mm_player_t *player);
182 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
183 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
184 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
185 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
186 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
187 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
188 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
189 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
193 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
194 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
195 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
197 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
198 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
199 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
200 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
202 static void __mmplayer_set_pause_state(mm_player_t *player);
203 static void __mmplayer_set_playing_state(mm_player_t *player);
204 /*===========================================================================================
206 | FUNCTION DEFINITIONS |
208 ========================================================================================== */
212 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
216 count = gst_tag_list_get_tag_size(list, tag);
218 LOGD("count = %d", count);
220 for (i = 0; i < count; i++) {
223 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
224 if (!gst_tag_list_get_string_index(list, tag, i, &str))
225 g_assert_not_reached();
227 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
231 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
233 g_print(" : %s", str);
240 /* This function should be called after the pipeline goes PAUSED or higher
243 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
245 static gboolean has_duration = FALSE;
246 static gboolean has_video_attrs = FALSE;
247 static gboolean has_audio_attrs = FALSE;
248 static gboolean has_bitrate = FALSE;
249 gboolean missing_only = FALSE;
250 gboolean all = FALSE;
251 MMHandleType attrs = 0;
255 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
257 /* check player state here */
258 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
259 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
260 /* give warning now only */
261 LOGW("be careful. content attributes may not available in this state ");
264 /* get content attribute first */
265 attrs = MMPLAYER_GET_ATTRS(player);
267 LOGE("cannot get content attribute");
271 /* get update flag */
273 if (flag & ATTR_MISSING_ONLY) {
275 LOGD("updating missed attr only");
278 if (flag & ATTR_ALL) {
280 has_duration = FALSE;
281 has_video_attrs = FALSE;
282 has_audio_attrs = FALSE;
285 LOGD("updating all attrs");
288 if (missing_only && all) {
289 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
290 missing_only = FALSE;
293 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
294 has_duration = __mmplayer_update_duration_value(player);
296 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
297 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
299 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
300 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
302 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
303 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
306 if (mm_attrs_commit_all(attrs)) {
307 LOGE("failed to update attributes");
317 __mmplayer_get_stream_service_type(mm_player_t *player)
319 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
325 player->pipeline->mainbin &&
326 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
327 STREAMING_SERVICE_NONE);
329 /* streaming service type if streaming */
330 if (!MMPLAYER_IS_STREAMING(player))
331 return STREAMING_SERVICE_NONE;
333 streaming_type = (player->duration == 0) ?
334 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
336 switch (streaming_type) {
337 case STREAMING_SERVICE_LIVE:
338 LOGD("it's live streaming");
340 case STREAMING_SERVICE_VOD:
341 LOGD("it's vod streaming");
344 LOGE("should not get here");
350 return streaming_type;
353 /* this function sets the player state and also report
354 * it to applicaton by calling callback function
357 __mmplayer_set_state(mm_player_t *player, int state)
359 MMMessageParamType msg = {0, };
361 MMPLAYER_RETURN_IF_FAIL(player);
363 if (MMPLAYER_CURRENT_STATE(player) == state) {
364 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
365 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
369 /* update player states */
370 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
371 MMPLAYER_CURRENT_STATE(player) = state;
373 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
374 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
377 MMPLAYER_PRINT_STATE(player);
379 switch (MMPLAYER_CURRENT_STATE(player)) {
380 case MM_PLAYER_STATE_NULL:
381 case MM_PLAYER_STATE_READY:
383 case MM_PLAYER_STATE_PAUSED:
384 __mmplayer_set_pause_state(player);
386 case MM_PLAYER_STATE_PLAYING:
387 __mmplayer_set_playing_state(player);
389 case MM_PLAYER_STATE_NONE:
391 LOGW("invalid target state, there is nothing to do.");
396 /* post message to application */
397 if (MMPLAYER_TARGET_STATE(player) == state) {
398 /* fill the message with state of player */
399 msg.union_type = MM_MSG_UNION_STATE;
400 msg.state.previous = MMPLAYER_PREV_STATE(player);
401 msg.state.current = MMPLAYER_CURRENT_STATE(player);
403 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
405 /* state changed by resource callback */
406 if (player->interrupted_by_resource)
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
408 else /* state changed by usecase */
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
412 LOGD("intermediate state, do nothing.");
413 MMPLAYER_PRINT_STATE(player);
417 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
418 && !player->sent_bos) {
419 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
420 player->sent_bos = TRUE;
427 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
429 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
430 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
434 //LOGD("incomming command : %d ", command);
436 current_state = MMPLAYER_CURRENT_STATE(player);
437 pending_state = MMPLAYER_PENDING_STATE(player);
439 MMPLAYER_PRINT_STATE(player);
442 case MMPLAYER_COMMAND_CREATE:
444 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
446 if (current_state == MM_PLAYER_STATE_NULL ||
447 current_state == MM_PLAYER_STATE_READY ||
448 current_state == MM_PLAYER_STATE_PAUSED ||
449 current_state == MM_PLAYER_STATE_PLAYING)
454 case MMPLAYER_COMMAND_DESTROY:
456 /* destroy can called anytime */
458 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
462 case MMPLAYER_COMMAND_REALIZE:
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
466 if (pending_state != MM_PLAYER_STATE_NONE) {
469 /* need ready state to realize */
470 if (current_state == MM_PLAYER_STATE_READY)
473 if (current_state != MM_PLAYER_STATE_NULL)
479 case MMPLAYER_COMMAND_UNREALIZE:
481 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
483 if (current_state == MM_PLAYER_STATE_NULL)
488 case MMPLAYER_COMMAND_START:
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PLAYING)
495 else if (current_state != MM_PLAYER_STATE_READY &&
496 current_state != MM_PLAYER_STATE_PAUSED)
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
501 LOGD("player is going to paused state, just change the pending state as playing");
508 case MMPLAYER_COMMAND_STOP:
510 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
512 if (current_state == MM_PLAYER_STATE_READY)
515 /* need playing/paused state to stop */
516 if (current_state != MM_PLAYER_STATE_PLAYING &&
517 current_state != MM_PLAYER_STATE_PAUSED)
522 case MMPLAYER_COMMAND_PAUSE:
524 if (MMPLAYER_IS_LIVE_STREAMING(player))
527 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
528 goto NOT_COMPLETED_SEEK;
530 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
532 if (pending_state == MM_PLAYER_STATE_NONE) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
535 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
537 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
539 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
540 if (current_state == MM_PLAYER_STATE_PAUSED)
541 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
548 case MMPLAYER_COMMAND_RESUME:
550 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
551 goto NOT_COMPLETED_SEEK;
553 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
555 if (pending_state == MM_PLAYER_STATE_NONE) {
556 if (current_state == MM_PLAYER_STATE_PLAYING)
558 else if (current_state != MM_PLAYER_STATE_PAUSED)
560 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
562 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
563 LOGD("player is going to paused state, just change the pending state as playing");
573 player->cmd = command;
575 return MM_ERROR_NONE;
578 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
579 MMPLAYER_STATE_GET_NAME(current_state), command);
580 return MM_ERROR_PLAYER_INVALID_STATE;
583 LOGW("not completed seek");
584 return MM_ERROR_PLAYER_DOING_SEEK;
587 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
592 return MM_ERROR_PLAYER_NO_OP;
596 __mmplayer_gapless_play_thread(gpointer data)
598 mm_player_t *player = (mm_player_t *)data;
599 MMPlayerGstElement *mainbin = NULL;
601 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
603 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
604 while (!player->gapless_play_thread_exit) {
605 LOGD("gapless play thread started. waiting for signal.");
606 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
608 LOGD("reconfigure pipeline for gapless play.");
610 if (player->gapless_play_thread_exit) {
611 if (player->gapless.reconfigure) {
612 player->gapless.reconfigure = false;
613 MMPLAYER_PLAYBACK_UNLOCK(player);
615 LOGD("exiting gapless play thread");
619 mainbin = player->pipeline->mainbin;
621 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
622 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
627 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
629 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
635 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
637 GSource *source = NULL;
641 source = g_main_context_find_source_by_id(context, source_id);
642 if (source != NULL) {
643 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
644 g_source_destroy(source);
651 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
653 mm_player_t *player = (mm_player_t *)hplayer;
654 GstMessage *msg = NULL;
655 GQueue *queue = NULL;
658 MMPLAYER_RETURN_IF_FAIL(player);
660 /* disconnecting bus watch */
661 if (player->bus_watcher)
662 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
663 player->bus_watcher = 0;
665 /* destroy the gst bus msg thread */
666 if (player->bus_msg_thread) {
667 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
668 player->bus_msg_thread_exit = TRUE;
669 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
670 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
672 LOGD("gst bus msg thread exit.");
673 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
674 player->bus_msg_thread = NULL;
676 g_mutex_clear(&player->bus_msg_thread_mutex);
677 g_cond_clear(&player->bus_msg_thread_cond);
680 g_mutex_lock(&player->bus_msg_q_lock);
681 queue = player->bus_msg_q;
682 while (!g_queue_is_empty(queue)) {
683 msg = (GstMessage *)g_queue_pop_head(queue);
688 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
689 gst_message_unref(msg);
691 g_mutex_unlock(&player->bus_msg_q_lock);
697 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
699 GstElement *parent = NULL;
701 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
703 /* if we have no fakesink. this meas we are using decodebin which doesn'
704 t need to add extra fakesink */
705 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
708 MMPLAYER_FSINK_LOCK(player);
713 /* get parent of fakesink */
714 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
716 LOGD("fakesink already removed");
720 gst_element_set_locked_state(fakesink->gst, TRUE);
722 /* setting the state to NULL never returns async
723 * so no need to wait for completion of state transiton
725 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
726 LOGE("fakesink state change failure!");
727 /* FIXIT : should I return here? or try to proceed to next? */
730 /* remove fakesink from it's parent */
731 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
732 LOGE("failed to remove fakesink");
734 gst_object_unref(parent);
739 gst_object_unref(parent);
741 LOGD("state-holder removed");
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
750 gst_element_set_locked_state(fakesink->gst, FALSE);
752 MMPLAYER_FSINK_UNLOCK(player);
756 static GstPadProbeReturn
757 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
759 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
760 return GST_PAD_PROBE_OK;
764 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
766 gint64 stop_running_time = 0;
767 gint64 position_running_time = 0;
771 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
772 if ((player->gapless.update_segment[idx] == TRUE) ||
773 !(player->selector[idx].event_probe_id)) {
774 /* LOGW("[%d] skip", idx); */
778 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
780 gst_segment_to_running_time(&player->gapless.segment[idx],
781 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
782 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
787 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->duration);
793 position_running_time =
794 gst_segment_to_running_time(&player->gapless.segment[idx],
795 GST_FORMAT_TIME, player->gapless.segment[idx].position);
797 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
798 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
800 GST_TIME_ARGS(stop_running_time),
801 GST_TIME_ARGS(position_running_time),
802 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
803 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
805 position_running_time = MAX(position_running_time, stop_running_time);
806 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
807 GST_FORMAT_TIME, player->gapless.segment[idx].start);
808 position_running_time = MAX(0, position_running_time);
809 position = MAX(position, position_running_time);
813 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
814 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
815 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
817 player->gapless.start_time[stream_type] += position;
823 static GstPadProbeReturn
824 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
826 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
827 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
828 mm_player_t *player = (mm_player_t *)data;
829 GstCaps *caps = NULL;
830 GstStructure *str = NULL;
831 const gchar *name = NULL;
832 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
833 gboolean caps_ret = TRUE;
835 if (GST_EVENT_IS_DOWNSTREAM(event) &&
836 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
837 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
838 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
839 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
841 } else if (GST_EVENT_IS_UPSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
846 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
850 if (strstr(name, "audio")) {
851 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
852 } else if (strstr(name, "video")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
855 /* text track is not supportable */
856 LOGE("invalid name %s", name);
860 switch (GST_EVENT_TYPE(event)) {
863 /* in case of gapless, drop eos event not to send it to sink */
864 if (player->gapless.reconfigure && !player->msg_posted) {
865 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
866 ret = GST_PAD_PROBE_DROP;
870 case GST_EVENT_STREAM_START:
872 __mmplayer_gst_selector_update_start_time(player, stream_type);
875 case GST_EVENT_FLUSH_STOP:
877 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
878 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
879 player->gapless.start_time[stream_type] = 0;
882 case GST_EVENT_SEGMENT:
887 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
888 gst_event_copy_segment(event, &segment);
890 if (segment.format != GST_FORMAT_TIME)
893 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
894 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
895 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
896 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
897 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
898 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
900 /* keep the all the segment ev to cover the seeking */
901 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
902 player->gapless.update_segment[stream_type] = TRUE;
904 if (!player->gapless.running)
907 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
909 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
911 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
912 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
913 gst_event_unref(event);
914 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
920 gdouble proportion = 0.0;
921 GstClockTimeDiff diff = 0;
922 GstClockTime timestamp = 0;
923 gint64 running_time_diff = -1;
925 GstEvent *tmpev = NULL;
927 running_time_diff = player->gapless.segment[stream_type].base;
929 if (running_time_diff <= 0) /* don't need to adjust */
932 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
933 gst_event_unref(event);
935 if (timestamp < running_time_diff) {
936 LOGW("QOS event from previous group");
937 ret = GST_PAD_PROBE_DROP;
941 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
942 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(timestamp),
944 GST_TIME_ARGS(running_time_diff),
945 GST_TIME_ARGS(timestamp - running_time_diff));
947 timestamp -= running_time_diff;
949 /* That case is invalid for QoS events */
950 if (diff < 0 && -diff > timestamp) {
951 LOGW("QOS event from previous group");
952 ret = GST_PAD_PROBE_DROP;
956 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
957 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
967 gst_caps_unref(caps);
971 /* create fakesink for audio or video path witout audiobin or videobin */
973 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
975 GstElement *pipeline = NULL;
976 GstElement *fakesink = NULL;
977 GstPad *sinkpad = NULL;
980 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
982 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
985 fakesink = gst_element_factory_make("fakesink", NULL);
986 if (fakesink == NULL) {
987 LOGE("failed to create fakesink");
991 /* store it as it's sink element */
992 __mmplayer_add_sink(player, fakesink);
994 gst_bin_add(GST_BIN(pipeline), fakesink);
997 sinkpad = gst_element_get_static_pad(fakesink, "sink");
999 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1001 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1002 LOGE("failed to link fakesink");
1003 gst_object_unref(GST_OBJECT(fakesink));
1007 if (strstr(name, "video")) {
1008 if (player->v_stream_caps) {
1009 gst_caps_unref(player->v_stream_caps);
1010 player->v_stream_caps = NULL;
1012 if (player->ini.set_dump_element_flag)
1013 __mmplayer_add_dump_buffer_probe(player, fakesink);
1016 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1017 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1021 gst_object_unref(GST_OBJECT(sinkpad));
1028 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1030 GstElement *pipeline = NULL;
1031 GstElement *selector = NULL;
1032 GstPad *srcpad = NULL;
1035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1037 selector = gst_element_factory_make("input-selector", NULL);
1039 LOGE("failed to create input-selector");
1042 g_object_set(selector, "sync-streams", TRUE, NULL);
1044 player->pipeline->mainbin[elem_idx].id = elem_idx;
1045 player->pipeline->mainbin[elem_idx].gst = selector;
1047 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1049 srcpad = gst_element_get_static_pad(selector, "src");
1051 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1052 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1053 __mmplayer_gst_selector_blocked, NULL, NULL);
1054 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1055 __mmplayer_gst_selector_event_probe, player, NULL);
1057 gst_element_set_state(selector, GST_STATE_PAUSED);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1060 gst_bin_add(GST_BIN(pipeline), selector);
1062 gst_object_unref(GST_OBJECT(srcpad));
1069 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1071 mm_player_t *player = (mm_player_t *)data;
1072 GstElement *selector = NULL;
1073 GstCaps *caps = NULL;
1074 GstStructure *str = NULL;
1075 const gchar *name = NULL;
1076 GstPad *sinkpad = NULL;
1077 gboolean first_track = FALSE;
1078 gboolean caps_ret = TRUE;
1080 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1081 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1084 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1085 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1087 LOGD("pad-added signal handling");
1089 /* get mimetype from caps */
1090 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1094 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1095 /* LOGD("detected mimetype : %s", name); */
1097 if (strstr(name, "video")) {
1099 gchar *caps_str = NULL;
1101 caps_str = gst_caps_to_string(caps);
1102 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1103 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1104 player->set_mode.video_zc = true;
1106 MMPLAYER_FREEIF(caps_str);
1108 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1109 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1111 LOGD("surface type : %d", stype);
1113 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1114 __mmplayer_gst_create_sinkbin(elem, pad, player);
1118 /* in case of exporting video frame, it requires the 360 video filter.
1119 * it will be handled in _no_more_pads(). */
1120 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1121 __mmplayer_gst_make_fakesink(player, pad, name);
1125 LOGD("video selector is required");
1126 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1127 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1128 } else if (strstr(name, "audio")) {
1129 gint samplerate = 0;
1132 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1133 if (player->build_audio_offload)
1134 player->no_more_pad = TRUE; /* remove state holder */
1135 __mmplayer_gst_create_sinkbin(elem, pad, player);
1139 gst_structure_get_int(str, "rate", &samplerate);
1140 gst_structure_get_int(str, "channels", &channels);
1142 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1143 __mmplayer_gst_make_fakesink(player, pad, name);
1147 LOGD("audio selector is required");
1148 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1149 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1151 } else if (strstr(name, "text")) {
1152 LOGD("text selector is required");
1153 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1154 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1156 LOGE("invalid caps info");
1160 /* check selector and create it */
1161 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1162 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1167 LOGD("input-selector is already created.");
1171 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1173 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1175 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1176 LOGE("failed to link selector");
1177 gst_object_unref(GST_OBJECT(selector));
1182 LOGD("this track will be activated");
1183 g_object_set(selector, "active-pad", sinkpad, NULL);
1186 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1192 gst_caps_unref(caps);
1195 gst_object_unref(GST_OBJECT(sinkpad));
1203 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1205 GstPad *srcpad = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1210 LOGD("type %d", type);
1213 LOGD("there is no %d track", type);
1217 srcpad = gst_element_get_static_pad(selector, "src");
1219 LOGE("failed to get srcpad from selector");
1223 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1225 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1227 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1228 if (player->selector[type].block_id) {
1229 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1230 player->selector[type].block_id = 0;
1234 gst_object_unref(GST_OBJECT(srcpad));
1243 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1245 MMHandleType attrs = 0;
1246 gint active_index = 0;
1249 MMPLAYER_RETURN_IF_FAIL(player);
1251 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1253 /* change track to active pad */
1254 active_index = player->selector[type].active_pad_index;
1255 if ((active_index != DEFAULT_TRACK) &&
1256 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1257 LOGW("failed to change %d type track to %d", type, active_index);
1258 player->selector[type].active_pad_index = DEFAULT_TRACK;
1262 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1263 attrs = MMPLAYER_GET_ATTRS(player);
1265 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1266 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1268 if (mm_attrs_commit_all(attrs))
1269 LOGW("failed to commit attrs.");
1271 LOGW("cannot get content attribute");
1280 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1283 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1285 if (!audio_selector) {
1286 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1288 /* in case the source is changed, output can be changed. */
1289 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1290 LOGD("remove previous audiobin if it exist");
1292 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1293 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1295 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1296 MMPLAYER_FREEIF(player->pipeline->audiobin);
1299 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1300 __mmplayer_pipeline_complete(NULL, player);
1305 /* apply the audio track information */
1306 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1308 /* create audio sink path */
1309 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1310 LOGE("failed to create audio sink path");
1319 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1322 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1324 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1325 LOGD("text path is not supproted");
1329 /* apply the text track information */
1330 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1332 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1333 player->has_closed_caption = TRUE;
1335 /* create text decode path */
1336 player->no_more_pad = TRUE;
1338 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1339 LOGE("failed to create text sink path");
1348 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1350 gint64 dur_bytes = 0L;
1353 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1354 player->pipeline->mainbin && player->streamer, FALSE);
1356 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1357 LOGE("fail to get duration.");
1359 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1360 * use file information was already set on Q2 when it was created. */
1361 __mm_player_streaming_set_queue2(player->streamer,
1362 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1363 TRUE, /* use_buffering */
1364 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1365 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1372 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1374 mm_player_t *player = NULL;
1375 GstElement *video_selector = NULL;
1376 GstElement *audio_selector = NULL;
1377 GstElement *text_selector = NULL;
1380 player = (mm_player_t *)data;
1382 LOGD("no-more-pad signal handling");
1384 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1385 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1386 LOGW("player is shutting down");
1390 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1391 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1392 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1393 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1394 LOGE("failed to set queue2 buffering");
1399 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1400 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1401 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1403 if (!video_selector && !audio_selector && !text_selector) {
1404 LOGW("there is no selector");
1405 player->no_more_pad = TRUE;
1409 /* create video path followed by video-select */
1410 if (video_selector && !audio_selector && !text_selector)
1411 player->no_more_pad = TRUE;
1413 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1416 /* create audio path followed by audio-select */
1417 if (audio_selector && !text_selector)
1418 player->no_more_pad = TRUE;
1420 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1423 /* create text path followed by text-select */
1424 __mmplayer_create_text_sink_path(player, text_selector);
1427 if (player->gapless.reconfigure) {
1428 player->gapless.reconfigure = FALSE;
1429 MMPLAYER_PLAYBACK_UNLOCK(player);
1436 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1438 gboolean ret = FALSE;
1439 GstElement *pipeline = NULL;
1440 GstPad *sinkpad = NULL;
1443 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1446 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1448 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1450 LOGE("failed to get pad from sinkbin");
1456 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1457 LOGE("failed to link sinkbin for reusing");
1458 goto EXIT; /* exit either pass or fail */
1462 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1463 LOGE("failed to set state(READY) to sinkbin");
1468 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1469 LOGE("failed to add sinkbin to pipeline");
1474 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1475 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1480 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1481 LOGE("failed to set state(PAUSED) to sinkbin");
1490 gst_object_unref(GST_OBJECT(sinkpad));
1498 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1500 mm_player_t *player = NULL;
1501 GstCaps *caps = NULL;
1502 gchar *caps_str = NULL;
1503 GstStructure *str = NULL;
1504 const gchar *name = NULL;
1505 GstElement *sinkbin = NULL;
1506 gboolean reusing = FALSE;
1507 gboolean caps_ret = TRUE;
1508 gchar *sink_pad_name = "sink";
1511 player = (mm_player_t *)data;
1514 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1517 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1521 caps_str = gst_caps_to_string(caps);
1523 /* LOGD("detected mimetype : %s", name); */
1524 if (strstr(name, "audio")) {
1525 if (player->pipeline->audiobin == NULL) {
1526 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1527 LOGE("failed to create audiobin. continuing without audio");
1531 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1532 LOGD("creating audiobin success");
1535 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1536 LOGD("reusing audiobin");
1537 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1539 } else if (strstr(name, "video")) {
1540 /* 1. zero copy is updated at _decode_pad_added()
1541 * 2. NULL surface type is handled in _decode_pad_added() */
1542 LOGD("zero copy %d", player->set_mode.video_zc);
1543 if (player->pipeline->videobin == NULL) {
1544 int surface_type = 0;
1545 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1546 LOGD("display_surface_type (%d)", surface_type);
1548 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1549 LOGD("mark video overlay for acquire");
1550 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1551 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1552 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1553 &player->video_overlay_resource)
1554 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1555 LOGE("could not mark video_overlay resource for acquire");
1560 player->interrupted_by_resource = FALSE;
1562 if (mm_resource_manager_commit(player->resource_manager) !=
1563 MM_RESOURCE_MANAGER_ERROR_NONE) {
1564 LOGE("could not acquire resources for video playing");
1568 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1569 LOGE("failed to create videobin. continuing without video");
1573 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1574 LOGD("creating videosink bin success");
1577 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1578 LOGD("re-using videobin");
1579 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1581 } else if (strstr(name, "text")) {
1582 if (player->pipeline->textbin == NULL) {
1583 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1584 LOGE("failed to create text sink bin. continuing without text");
1588 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1589 player->textsink_linked = 1;
1590 LOGD("creating textsink bin success");
1592 if (!player->textsink_linked) {
1593 LOGD("re-using textbin");
1595 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1596 player->textsink_linked = 1;
1598 /* linked textbin exist which means that the external subtitle path exist already */
1599 LOGW("ignoring internal subtutle since external subtitle is available");
1602 sink_pad_name = "text_sink";
1604 LOGW("unknown mime type %s, ignoring it", name);
1608 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1611 LOGD("[handle: %p] success to create and link sink bin", player);
1613 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1614 * streaming task. if the task blocked, then buffer will not flow to the next element
1615 *(autoplugging element). so this is special hack for streaming. please try to remove it
1617 /* dec stream count. we can remove fakesink if it's zero */
1618 if (player->num_dynamic_pad)
1619 player->num_dynamic_pad--;
1621 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1623 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1624 __mmplayer_pipeline_complete(NULL, player);
1628 MMPLAYER_FREEIF(caps_str);
1631 gst_caps_unref(caps);
1637 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1639 int required_angle = 0; /* Angle required for straight view */
1640 int rotation_angle = 0;
1642 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1643 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1645 /* Counter clockwise */
1646 switch (orientation) {
1651 required_angle = 270;
1654 required_angle = 180;
1657 required_angle = 90;
1661 rotation_angle = display_angle + required_angle;
1662 if (rotation_angle >= 360)
1663 rotation_angle -= 360;
1665 /* chech if supported or not */
1666 if (rotation_angle % 90) {
1667 LOGD("not supported rotation angle = %d", rotation_angle);
1671 switch (rotation_angle) {
1673 *value = MM_DISPLAY_ROTATION_NONE;
1676 *value = MM_DISPLAY_ROTATION_90;
1679 *value = MM_DISPLAY_ROTATION_180;
1682 *value = MM_DISPLAY_ROTATION_270;
1686 LOGD("setting rotation property value : %d", *value);
1692 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1694 /* check video sinkbin is created */
1695 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1697 player->pipeline->videobin &&
1698 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1699 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1700 MM_ERROR_PLAYER_NOT_INITIALIZED);
1702 return MM_ERROR_NONE;
1706 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1708 int display_rotation = 0;
1709 gchar *org_orient = NULL;
1710 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1713 LOGE("cannot get content attribute");
1714 return MM_ERROR_PLAYER_INTERNAL;
1717 if (display_angle) {
1718 /* update user roation */
1719 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1721 /* Counter clockwise */
1722 switch (display_rotation) {
1723 case MM_DISPLAY_ROTATION_NONE:
1726 case MM_DISPLAY_ROTATION_90:
1727 *display_angle = 90;
1729 case MM_DISPLAY_ROTATION_180:
1730 *display_angle = 180;
1732 case MM_DISPLAY_ROTATION_270:
1733 *display_angle = 270;
1736 LOGW("wrong angle type : %d", display_rotation);
1739 LOGD("check user angle: %d", *display_angle);
1743 /* Counter clockwise */
1744 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1747 if (!strcmp(org_orient, "rotate-90"))
1749 else if (!strcmp(org_orient, "rotate-180"))
1751 else if (!strcmp(org_orient, "rotate-270"))
1754 LOGD("original rotation is %s", org_orient);
1756 LOGD("content_video_orientation get fail");
1759 LOGD("check orientation: %d", *orientation);
1762 return MM_ERROR_NONE;
1766 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1768 int rotation_value = 0;
1769 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1770 int display_angle = 0;
1773 /* check video sinkbin is created */
1774 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1777 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1779 /* get rotation value to set */
1780 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1781 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1782 LOGD("set video param : rotate %d", rotation_value);
1786 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1788 MMHandleType attrs = 0;
1792 /* check video sinkbin is created */
1793 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1796 attrs = MMPLAYER_GET_ATTRS(player);
1797 MMPLAYER_RETURN_IF_FAIL(attrs);
1799 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1800 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1801 LOGD("set video param : visible %d", visible);
1805 __mmplayer_video_param_set_display_method(mm_player_t *player)
1807 MMHandleType attrs = 0;
1808 int display_method = 0;
1811 /* check video sinkbin is created */
1812 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1815 attrs = MMPLAYER_GET_ATTRS(player);
1816 MMPLAYER_RETURN_IF_FAIL(attrs);
1818 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1819 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1820 LOGD("set video param : method %d", display_method);
1824 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1826 MMHandleType attrs = 0;
1827 void *handle = NULL;
1830 /* check video sinkbin is created */
1831 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1832 LOGW("There is no video sink");
1836 attrs = MMPLAYER_GET_ATTRS(player);
1837 MMPLAYER_RETURN_IF_FAIL(attrs);
1838 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1840 gst_video_overlay_set_video_roi_area(
1841 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1842 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1843 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1844 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1849 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1851 MMHandleType attrs = 0;
1852 void *handle = NULL;
1856 int win_roi_width = 0;
1857 int win_roi_height = 0;
1860 /* check video sinkbin is created */
1861 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1862 LOGW("There is no video sink");
1866 attrs = MMPLAYER_GET_ATTRS(player);
1867 MMPLAYER_RETURN_IF_FAIL(attrs);
1869 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1872 /* It should be set after setting window */
1873 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1874 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1875 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1876 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1878 /* After setting window handle, set display roi area */
1879 gst_video_overlay_set_display_roi_area(
1880 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1881 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1882 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1883 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1888 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1890 MMHandleType attrs = 0;
1891 void *handle = NULL;
1893 /* check video sinkbin is created */
1894 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1897 attrs = MMPLAYER_GET_ATTRS(player);
1898 MMPLAYER_RETURN_IF_FAIL(attrs);
1900 /* common case if using overlay surface */
1901 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1904 /* default is using wl_surface_id */
1905 unsigned int wl_surface_id = 0;
1906 wl_surface_id = *(int *)handle;
1907 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1908 gst_video_overlay_set_wl_window_wl_surface_id(
1909 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1912 /* FIXIT : is it error case? */
1913 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1918 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1920 gboolean update_all_param = FALSE;
1923 /* check video sinkbin is created */
1924 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1925 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1927 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1928 LOGE("can not find tizenwlsink");
1929 return MM_ERROR_PLAYER_INTERNAL;
1932 LOGD("param_name : %s", param_name);
1933 if (!g_strcmp0(param_name, "update_all_param"))
1934 update_all_param = TRUE;
1936 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1937 __mmplayer_video_param_set_display_overlay(player);
1938 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1939 __mmplayer_video_param_set_display_method(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1941 __mmplayer_video_param_set_display_visible(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1943 __mmplayer_video_param_set_display_rotation(player);
1944 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1945 __mmplayer_video_param_set_roi_area(player);
1946 if (update_all_param)
1947 __mmplayer_video_param_set_video_roi_area(player);
1949 return MM_ERROR_NONE;
1953 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1955 MMHandleType attrs = 0;
1956 int surface_type = 0;
1957 int ret = MM_ERROR_NONE;
1961 /* check video sinkbin is created */
1962 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1963 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1965 attrs = MMPLAYER_GET_ATTRS(player);
1967 LOGE("cannot get content attribute");
1968 return MM_ERROR_PLAYER_INTERNAL;
1970 LOGD("param_name : %s", param_name);
1972 /* update display surface */
1973 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1974 LOGD("check display surface type attribute: %d", surface_type);
1976 /* configuring display */
1977 switch (surface_type) {
1978 case MM_DISPLAY_SURFACE_OVERLAY:
1980 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1981 if (ret != MM_ERROR_NONE)
1989 return MM_ERROR_NONE;
1993 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1995 gboolean disable_overlay = FALSE;
1996 mm_player_t *player = (mm_player_t *)hplayer;
1997 int ret = MM_ERROR_NONE;
2000 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2001 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2002 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2003 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2005 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2006 LOGW("Display control is not supported");
2007 return MM_ERROR_PLAYER_INTERNAL;
2010 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2012 if (audio_only == (bool)disable_overlay) {
2013 LOGE("It's the same with current setting: (%d)", audio_only);
2014 return MM_ERROR_NONE;
2018 LOGE("disable overlay");
2019 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2021 /* release overlay resource */
2022 if (player->video_overlay_resource != NULL) {
2023 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2024 player->video_overlay_resource);
2025 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2026 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2029 player->video_overlay_resource = NULL;
2032 ret = mm_resource_manager_commit(player->resource_manager);
2033 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2034 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2038 /* mark video overlay for acquire */
2039 if (player->video_overlay_resource == NULL) {
2040 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2041 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2042 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2043 &player->video_overlay_resource);
2044 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2045 LOGE("could not prepare for video_overlay resource");
2050 player->interrupted_by_resource = FALSE;
2051 /* acquire resources for video overlay */
2052 ret = mm_resource_manager_commit(player->resource_manager);
2053 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2054 LOGE("could not acquire resources for video playing");
2058 LOGD("enable overlay");
2059 __mmplayer_video_param_set_display_overlay(player);
2060 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2065 return MM_ERROR_NONE;
2069 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2071 mm_player_t *player = (mm_player_t *)hplayer;
2072 gboolean disable_overlay = FALSE;
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2077 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2078 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2079 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2080 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2082 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2083 LOGW("Display control is not supported");
2084 return MM_ERROR_PLAYER_INTERNAL;
2087 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2089 *paudio_only = (bool)disable_overlay;
2091 LOGD("audio_only : %d", *paudio_only);
2095 return MM_ERROR_NONE;
2099 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2101 GList *bucket = element_bucket;
2102 MMPlayerGstElement *element = NULL;
2103 MMPlayerGstElement *prv_element = NULL;
2104 gint successful_link_count = 0;
2108 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2110 prv_element = (MMPlayerGstElement *)bucket->data;
2111 bucket = bucket->next;
2113 for (; bucket; bucket = bucket->next) {
2114 element = (MMPlayerGstElement *)bucket->data;
2116 if (element && element->gst) {
2117 if (prv_element && prv_element->gst) {
2118 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2119 LOGD("linking [%s] to [%s] success",
2120 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2121 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2122 successful_link_count++;
2124 LOGD("linking [%s] to [%s] failed",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2132 prv_element = element;
2137 return successful_link_count;
2141 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2143 GList *bucket = element_bucket;
2144 MMPlayerGstElement *element = NULL;
2145 int successful_add_count = 0;
2149 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2150 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2152 for (; bucket; bucket = bucket->next) {
2153 element = (MMPlayerGstElement *)bucket->data;
2155 if (element && element->gst) {
2156 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2157 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2158 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2159 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2162 successful_add_count++;
2168 return successful_add_count;
2172 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2174 mm_player_t *player = (mm_player_t *)data;
2175 GstCaps *caps = NULL;
2176 GstStructure *str = NULL;
2178 gboolean caps_ret = TRUE;
2182 MMPLAYER_RETURN_IF_FAIL(pad);
2183 MMPLAYER_RETURN_IF_FAIL(unused);
2184 MMPLAYER_RETURN_IF_FAIL(data);
2186 caps = gst_pad_get_current_caps(pad);
2190 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2194 LOGD("name = %s", name);
2196 if (strstr(name, "audio")) {
2197 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2199 if (player->audio_stream_changed_cb) {
2200 LOGE("call the audio stream changed cb");
2201 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2203 } else if (strstr(name, "video")) {
2204 if ((name = gst_structure_get_string(str, "format")))
2205 player->set_mode.video_zc = name[0] == 'S';
2207 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2209 if (player->video_stream_changed_cb) {
2210 LOGE("call the video stream changed cb");
2211 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2214 LOGW("invalid caps info");
2219 gst_caps_unref(caps);
2227 * This function is to create audio pipeline for playing.
2229 * @param player [in] handle of player
2231 * @return This function returns zero on success.
2233 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2235 /* macro for code readability. just for sinkbin-creation functions */
2236 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2238 x_bin[x_id].id = x_id;\
2239 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2240 if (!x_bin[x_id].gst) {\
2241 LOGE("failed to create %s", x_factory);\
2244 if (x_player->ini.set_dump_element_flag)\
2245 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2248 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2252 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2257 MMPLAYER_RETURN_IF_FAIL(player);
2259 if (player->audio_stream_buff_list) {
2260 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2261 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2264 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2265 __mmplayer_audio_stream_send_data(player, tmp);
2267 MMPLAYER_FREEIF(tmp->pcm_data);
2268 MMPLAYER_FREEIF(tmp);
2271 g_list_free(player->audio_stream_buff_list);
2272 player->audio_stream_buff_list = NULL;
2279 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2281 MMPlayerAudioStreamDataType audio_stream = { 0, };
2284 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2286 audio_stream.bitrate = a_buffer->bitrate;
2287 audio_stream.channel = a_buffer->channel;
2288 audio_stream.depth = a_buffer->depth;
2289 audio_stream.is_little_endian = a_buffer->is_little_endian;
2290 audio_stream.channel_mask = a_buffer->channel_mask;
2291 audio_stream.data_size = a_buffer->data_size;
2292 audio_stream.data = a_buffer->pcm_data;
2294 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2295 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2301 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2303 mm_player_t *player = (mm_player_t *)data;
2307 gint endianness = 0;
2308 guint64 channel_mask = 0;
2309 void *a_data = NULL;
2311 mm_player_audio_stream_buff_t *a_buffer = NULL;
2312 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2316 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2318 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2319 a_data = mapinfo.data;
2320 a_size = mapinfo.size;
2322 GstCaps *caps = gst_pad_get_current_caps(pad);
2323 GstStructure *structure = gst_caps_get_structure(caps, 0);
2325 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2326 gst_structure_get_int(structure, "rate", &rate);
2327 gst_structure_get_int(structure, "channels", &channel);
2328 gst_structure_get_int(structure, "depth", &depth);
2329 gst_structure_get_int(structure, "endianness", &endianness);
2330 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2331 gst_caps_unref(GST_CAPS(caps));
2333 /* In case of the sync is false, use buffer list. *
2334 * The num of buffer list depends on the num of audio channels */
2335 if (player->audio_stream_buff_list) {
2336 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2337 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2339 if (channel_mask == tmp->channel_mask) {
2340 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2341 if (tmp->data_size + a_size < tmp->buff_size) {
2342 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2343 tmp->data_size += a_size;
2345 /* send data to client */
2346 __mmplayer_audio_stream_send_data(player, tmp);
2348 if (a_size > tmp->buff_size) {
2349 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2350 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2351 if (tmp->pcm_data == NULL) {
2352 LOGE("failed to realloc data.");
2355 tmp->buff_size = a_size;
2357 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2358 memcpy(tmp->pcm_data, a_data, a_size);
2359 tmp->data_size = a_size;
2364 LOGE("data is empty in list.");
2370 /* create new audio stream data */
2371 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2372 if (a_buffer == NULL) {
2373 LOGE("failed to alloc data.");
2376 a_buffer->bitrate = rate;
2377 a_buffer->channel = channel;
2378 a_buffer->depth = depth;
2379 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2380 a_buffer->channel_mask = channel_mask;
2381 a_buffer->data_size = a_size;
2383 if (!player->audio_stream_sink_sync) {
2384 /* If sync is FALSE, use buffer list to reduce the IPC. */
2385 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2386 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2387 if (a_buffer->pcm_data == NULL) {
2388 LOGE("failed to alloc data.");
2389 MMPLAYER_FREEIF(a_buffer);
2392 memcpy(a_buffer->pcm_data, a_data, a_size);
2393 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2394 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2396 /* If sync is TRUE, send data directly. */
2397 a_buffer->pcm_data = a_data;
2398 __mmplayer_audio_stream_send_data(player, a_buffer);
2399 MMPLAYER_FREEIF(a_buffer);
2403 gst_buffer_unmap(buffer, &mapinfo);
2408 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2410 mm_player_t *player = (mm_player_t *)data;
2411 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2412 GstPad *sinkpad = NULL;
2413 GstElement *queue = NULL, *sink = NULL;
2416 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2418 queue = gst_element_factory_make("queue", NULL);
2419 if (queue == NULL) {
2420 LOGD("fail make queue");
2424 sink = gst_element_factory_make("fakesink", NULL);
2426 LOGD("fail make fakesink");
2430 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2432 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2433 LOGW("failed to link queue & sink");
2437 sinkpad = gst_element_get_static_pad(queue, "sink");
2439 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2440 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2444 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2446 gst_object_unref(sinkpad);
2447 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2448 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2450 gst_element_set_state(sink, GST_STATE_PAUSED);
2451 gst_element_set_state(queue, GST_STATE_PAUSED);
2453 __mmplayer_add_signal_connection(player,
2455 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2457 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2464 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2466 gst_object_unref(GST_OBJECT(queue));
2470 gst_object_unref(GST_OBJECT(sink));
2474 gst_object_unref(GST_OBJECT(sinkpad));
2482 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2484 #define MAX_PROPS_LEN 128
2485 gint latency_mode = 0;
2486 gchar *stream_type = NULL;
2487 gchar *latency = NULL;
2489 gchar stream_props[MAX_PROPS_LEN] = {0,};
2490 GstStructure *props = NULL;
2493 * It should be set after player creation through attribute.
2494 * But, it can not be changed during playing.
2497 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2499 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2500 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2503 LOGE("stream_type is null.");
2505 if (player->sound.focus_id)
2506 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2507 stream_type, stream_id, player->sound.focus_id);
2509 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2510 stream_type, stream_id);
2511 props = gst_structure_from_string(stream_props, NULL);
2512 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2513 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2514 stream_type, stream_id, player->sound.focus_id, stream_props);
2515 gst_structure_free(props);
2518 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2520 switch (latency_mode) {
2521 case AUDIO_LATENCY_MODE_LOW:
2522 latency = g_strndup("low", 3);
2524 case AUDIO_LATENCY_MODE_MID:
2525 latency = g_strndup("mid", 3);
2527 case AUDIO_LATENCY_MODE_HIGH:
2528 latency = g_strndup("high", 4);
2532 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2536 LOGD("audiosink property - latency=%s", latency);
2538 MMPLAYER_FREEIF(latency);
2544 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2546 MMPlayerGstElement *audiobin = NULL;
2549 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2551 audiobin = player->pipeline->audiobin;
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2554 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2555 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2557 if (player->video360_yaw_radians <= M_PI &&
2558 player->video360_yaw_radians >= -M_PI &&
2559 player->video360_pitch_radians <= M_PI_2 &&
2560 player->video360_pitch_radians >= -M_PI_2) {
2561 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2562 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2563 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2564 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2565 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2566 "source-orientation-y", player->video360_metadata.init_view_heading,
2567 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2574 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2576 MMPlayerGstElement *audiobin = NULL;
2577 MMHandleType attrs = 0;
2578 GList *element_bucket = NULL;
2579 GstCaps *acaps = NULL;
2580 GstPad *sink_pad = NULL;
2581 int pitch_control = 0;
2582 double pitch_value = 1.0;
2585 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2586 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2588 audiobin = player->pipeline->audiobin;
2589 attrs = MMPLAYER_GET_ATTRS(player);
2591 if (player->build_audio_offload) { /* skip all the audio filters */
2592 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2593 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2594 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2595 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2600 mm_attrs_multiple_get(player->attrs, NULL,
2601 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2602 MM_PLAYER_PITCH_VALUE, &pitch_value,
2605 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2606 if (pitch_control && (player->videodec_linked == 0)) {
2607 GstElementFactory *factory;
2609 factory = gst_element_factory_find("pitch");
2611 gst_object_unref(factory);
2614 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2617 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2618 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2620 LOGW("there is no pitch element");
2625 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2627 /* replaygain volume */
2628 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2629 if (player->sound.rg_enable)
2630 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2632 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2635 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2637 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2638 gchar *dst_format = NULL;
2640 int dst_samplerate = 0;
2641 int dst_channels = 0;
2642 GstCaps *caps = NULL;
2643 char *caps_str = NULL;
2645 /* get conf. values */
2646 mm_attrs_multiple_get(player->attrs, NULL,
2647 "pcm_audioformat", &dst_format, &dst_len,
2648 "pcm_extraction_samplerate", &dst_samplerate,
2649 "pcm_extraction_channels", &dst_channels,
2652 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2655 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2656 caps = gst_caps_new_simple("audio/x-raw",
2657 "format", G_TYPE_STRING, dst_format,
2658 "rate", G_TYPE_INT, dst_samplerate,
2659 "channels", G_TYPE_INT, dst_channels,
2662 caps_str = gst_caps_to_string(caps);
2663 LOGD("new caps : %s", caps_str);
2665 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2668 gst_caps_unref(caps);
2669 MMPLAYER_FREEIF(caps_str);
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2673 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2675 /* raw pad handling signal, audiosink will be added after getting signal */
2676 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2677 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2681 /* normal playback */
2684 /* for logical volume control */
2685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2686 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2688 if (player->sound.mute) {
2689 LOGD("mute enabled");
2690 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2693 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2695 /* audio effect element. if audio effect is enabled */
2696 if ((strcmp(player->ini.audioeffect_element, ""))
2698 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2699 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2701 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2703 if ((!player->bypass_audio_effect)
2704 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2705 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2706 if (!_mmplayer_audio_effect_custom_apply(player))
2707 LOGI("apply audio effect(custom) setting success");
2711 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2712 && (player->set_mode.rich_audio))
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2716 /* create audio sink */
2717 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2718 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2719 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2721 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2722 if (player->is_360_feature_enabled &&
2723 player->is_content_spherical &&
2725 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2726 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2727 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2729 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2734 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2736 gst_caps_unref(acaps);
2738 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2740 player->is_openal_plugin_used = TRUE;
2742 if (player->is_360_feature_enabled && player->is_content_spherical)
2743 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2744 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2747 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2748 (player->videodec_linked && player->ini.use_system_clock)) {
2749 LOGD("system clock will be used.");
2750 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2753 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2754 __mmplayer_gst_set_pulsesink_property(player, attrs);
2755 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2756 __mmplayer_gst_set_openalsink_property(player);
2759 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2760 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2762 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2763 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2764 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2765 gst_object_unref(GST_OBJECT(sink_pad));
2767 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2771 *bucket = element_bucket;
2774 return MM_ERROR_NONE;
2777 g_list_free(element_bucket);
2781 return MM_ERROR_PLAYER_INTERNAL;
2785 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2787 MMPlayerGstElement *first_element = NULL;
2788 MMPlayerGstElement *audiobin = NULL;
2790 GstPad *ghostpad = NULL;
2791 GList *element_bucket = NULL;
2795 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2798 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2800 LOGE("failed to allocate memory for audiobin");
2801 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2805 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2806 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2807 if (!audiobin[MMPLAYER_A_BIN].gst) {
2808 LOGE("failed to create audiobin");
2813 player->pipeline->audiobin = audiobin;
2815 /* create audio filters and audiosink */
2816 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2819 /* adding created elements to bin */
2820 LOGD("adding created elements to bin");
2821 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2824 /* linking elements in the bucket by added order. */
2825 LOGD("Linking elements in the bucket by added order.");
2826 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2829 /* get first element's sinkpad for creating ghostpad */
2830 first_element = (MMPlayerGstElement *)element_bucket->data;
2831 if (!first_element) {
2832 LOGE("failed to get first elem");
2836 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2838 LOGE("failed to get pad from first element of audiobin");
2842 ghostpad = gst_ghost_pad_new("sink", pad);
2844 LOGE("failed to create ghostpad");
2848 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2849 LOGE("failed to add ghostpad to audiobin");
2853 gst_object_unref(pad);
2855 g_list_free(element_bucket);
2858 return MM_ERROR_NONE;
2861 LOGD("ERROR : releasing audiobin");
2864 gst_object_unref(GST_OBJECT(pad));
2867 gst_object_unref(GST_OBJECT(ghostpad));
2870 g_list_free(element_bucket);
2872 /* release element which are not added to bin */
2873 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2874 /* NOTE : skip bin */
2875 if (audiobin[i].gst) {
2876 GstObject *parent = NULL;
2877 parent = gst_element_get_parent(audiobin[i].gst);
2880 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2881 audiobin[i].gst = NULL;
2883 gst_object_unref(GST_OBJECT(parent));
2887 /* release audiobin with it's childs */
2888 if (audiobin[MMPLAYER_A_BIN].gst)
2889 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2891 MMPLAYER_FREEIF(audiobin);
2893 player->pipeline->audiobin = NULL;
2895 return MM_ERROR_PLAYER_INTERNAL;
2899 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2901 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2905 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2907 int ret = MM_ERROR_NONE;
2909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2910 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2912 MMPLAYER_VIDEO_BO_LOCK(player);
2914 if (player->video_bo_list) {
2915 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2916 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2917 if (tmp && tmp->bo == bo) {
2919 LOGD("release bo %p", bo);
2920 tbm_bo_unref(tmp->bo);
2921 MMPLAYER_VIDEO_BO_UNLOCK(player);
2922 MMPLAYER_VIDEO_BO_SIGNAL(player);
2927 /* hw codec is running or the list was reset for DRC. */
2928 LOGW("there is no bo list.");
2930 MMPLAYER_VIDEO_BO_UNLOCK(player);
2932 LOGW("failed to find bo %p", bo);
2937 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2942 MMPLAYER_RETURN_IF_FAIL(player);
2944 MMPLAYER_VIDEO_BO_LOCK(player);
2945 if (player->video_bo_list) {
2946 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2947 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2948 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2951 tbm_bo_unref(tmp->bo);
2955 g_list_free(player->video_bo_list);
2956 player->video_bo_list = NULL;
2958 player->video_bo_size = 0;
2959 MMPLAYER_VIDEO_BO_UNLOCK(player);
2966 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2969 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2970 gboolean ret = TRUE;
2972 /* check DRC, if it is, destroy the prev bo list to create again */
2973 if (player->video_bo_size != size) {
2974 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2975 __mmplayer_video_stream_destroy_bo_list(player);
2976 player->video_bo_size = size;
2979 MMPLAYER_VIDEO_BO_LOCK(player);
2981 if ((!player->video_bo_list) ||
2982 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2984 /* create bo list */
2986 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2988 if (player->video_bo_list) {
2989 /* if bo list did not created all, try it again. */
2990 idx = g_list_length(player->video_bo_list);
2991 LOGD("bo list exist(len: %d)", idx);
2994 for (; idx < player->ini.num_of_video_bo; idx++) {
2995 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2997 LOGE("Fail to alloc bo_info.");
3000 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3002 LOGE("Fail to tbm_bo_alloc.");
3003 MMPLAYER_FREEIF(bo_info);
3006 bo_info->used = FALSE;
3007 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3010 /* update video num buffers */
3011 player->video_num_buffers = idx;
3012 if (idx == player->ini.num_of_video_bo)
3013 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3016 MMPLAYER_VIDEO_BO_UNLOCK(player);
3020 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3024 /* get bo from list*/
3025 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3026 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3027 if (tmp && (tmp->used == FALSE)) {
3028 LOGD("found bo %p to use", tmp->bo);
3030 MMPLAYER_VIDEO_BO_UNLOCK(player);
3031 return tbm_bo_ref(tmp->bo);
3035 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3036 MMPLAYER_VIDEO_BO_UNLOCK(player);
3040 if (player->ini.video_bo_timeout <= 0) {
3041 MMPLAYER_VIDEO_BO_WAIT(player);
3043 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3044 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3051 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3053 mm_player_t *player = (mm_player_t *)data;
3055 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3057 /* send prerolled pkt */
3058 player->video_stream_prerolled = false;
3060 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3062 /* not to send prerolled pkt again */
3063 player->video_stream_prerolled = true;
3067 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3069 mm_player_t *player = (mm_player_t *)data;
3070 MMPlayerVideoStreamDataType *stream = NULL;
3071 GstMemory *mem = NULL;
3074 MMPLAYER_RETURN_IF_FAIL(player);
3075 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3077 if (player->video_stream_prerolled) {
3078 player->video_stream_prerolled = false;
3079 LOGD("skip the prerolled pkt not to send it again");
3083 /* clear stream data structure */
3084 stream = __mmplayer_create_stream_from_pad(pad);
3086 LOGE("failed to alloc stream");
3090 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3092 /* set size and timestamp */
3093 mem = gst_buffer_peek_memory(buffer, 0);
3094 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3095 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3097 /* check zero-copy */
3098 if (player->set_mode.video_zc &&
3099 player->set_mode.media_packet_video_stream &&
3100 gst_is_tizen_memory(mem)) {
3101 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3102 stream->internal_buffer = gst_buffer_ref(buffer);
3103 } else { /* sw codec */
3104 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3107 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3111 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3112 LOGE("failed to send video stream data.");
3119 LOGE("release video stream resource.");
3120 if (gst_is_tizen_memory(mem)) {
3122 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3124 tbm_bo_unref(stream->bo[i]);
3127 /* unref gst buffer */
3128 if (stream->internal_buffer)
3129 gst_buffer_unref(stream->internal_buffer);
3132 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3134 MMPLAYER_FREEIF(stream);
3139 __mmplayer_gst_set_video360_property(mm_player_t *player)
3141 MMPlayerGstElement *videobin = NULL;
3144 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3146 videobin = player->pipeline->videobin;
3148 /* Set spatial media metadata and/or user settings to the element.
3150 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3151 "projection-type", player->video360_metadata.projection_type, NULL);
3153 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3154 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3156 if (player->video360_metadata.full_pano_width_pixels &&
3157 player->video360_metadata.full_pano_height_pixels &&
3158 player->video360_metadata.cropped_area_image_width &&
3159 player->video360_metadata.cropped_area_image_height) {
3160 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3161 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3162 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3163 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3164 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3165 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3166 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3170 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3171 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3172 "horizontal-fov", player->video360_horizontal_fov,
3173 "vertical-fov", player->video360_vertical_fov, NULL);
3176 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3177 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3178 "zoom", 1.0f / player->video360_zoom, NULL);
3181 if (player->video360_yaw_radians <= M_PI &&
3182 player->video360_yaw_radians >= -M_PI &&
3183 player->video360_pitch_radians <= M_PI_2 &&
3184 player->video360_pitch_radians >= -M_PI_2) {
3185 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3186 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3187 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3188 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3189 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3190 "pose-yaw", player->video360_metadata.init_view_heading,
3191 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3194 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3195 "passthrough", !player->is_video360_enabled, NULL);
3202 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3204 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3205 GList *element_bucket = NULL;
3208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3210 /* create video360 filter */
3211 if (player->is_360_feature_enabled && player->is_content_spherical) {
3212 LOGD("create video360 element");
3213 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3214 __mmplayer_gst_set_video360_property(player);
3218 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3219 LOGD("skip creating the videoconv and rotator");
3220 return MM_ERROR_NONE;
3223 /* in case of sw codec & overlay surface type, except 360 playback.
3224 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3225 LOGD("create video converter: %s", video_csc);
3226 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3228 /* set video rotator */
3229 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3232 *bucket = element_bucket;
3234 return MM_ERROR_NONE;
3236 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3237 g_list_free(element_bucket);
3241 return MM_ERROR_PLAYER_INTERNAL;
3245 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3247 gchar *factory_name = NULL;
3249 switch (surface_type) {
3250 case MM_DISPLAY_SURFACE_OVERLAY:
3251 if (strlen(player->ini.videosink_element_overlay) > 0)
3252 factory_name = player->ini.videosink_element_overlay;
3254 case MM_DISPLAY_SURFACE_REMOTE:
3255 case MM_DISPLAY_SURFACE_NULL:
3256 if (strlen(player->ini.videosink_element_fake) > 0)
3257 factory_name = player->ini.videosink_element_fake;
3260 LOGE("unidentified surface type");
3264 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3265 return factory_name;
3269 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3271 gchar *factory_name = NULL;
3272 MMPlayerGstElement *videobin = NULL;
3277 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3279 videobin = player->pipeline->videobin;
3280 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3282 attrs = MMPLAYER_GET_ATTRS(player);
3284 LOGE("cannot get content attribute");
3285 return MM_ERROR_PLAYER_INTERNAL;
3288 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3289 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3290 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3292 /* support shard memory with S/W codec on HawkP */
3293 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3294 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3295 "use-tbm", use_tbm, NULL);
3299 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3300 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3303 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3305 LOGD("disable last-sample");
3306 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3309 if (player->set_mode.media_packet_video_stream) {
3311 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3312 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3313 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3315 __mmplayer_add_signal_connection(player,
3316 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3317 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3319 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3322 __mmplayer_add_signal_connection(player,
3323 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3324 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3326 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3330 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3331 return MM_ERROR_PLAYER_INTERNAL;
3333 if (videobin[MMPLAYER_V_SINK].gst) {
3334 GstPad *sink_pad = NULL;
3335 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3337 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3338 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3339 gst_object_unref(GST_OBJECT(sink_pad));
3341 LOGE("failed to get sink pad from videosink");
3345 return MM_ERROR_NONE;
3350 * - video overlay surface(arm/x86) : tizenwlsink
3353 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3356 GList *element_bucket = NULL;
3357 MMPlayerGstElement *first_element = NULL;
3358 MMPlayerGstElement *videobin = NULL;
3359 gchar *videosink_factory_name = NULL;
3362 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3365 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3367 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3369 player->pipeline->videobin = videobin;
3372 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3373 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3374 if (!videobin[MMPLAYER_V_BIN].gst) {
3375 LOGE("failed to create videobin");
3379 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3382 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3383 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3385 /* additional setting for sink plug-in */
3386 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3387 LOGE("failed to set video property");
3391 /* store it as it's sink element */
3392 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3394 /* adding created elements to bin */
3395 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3396 LOGE("failed to add elements");
3400 /* Linking elements in the bucket by added order */
3401 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3402 LOGE("failed to link elements");
3406 /* get first element's sinkpad for creating ghostpad */
3407 first_element = (MMPlayerGstElement *)element_bucket->data;
3408 if (!first_element) {
3409 LOGE("failed to get first element from bucket");
3413 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3415 LOGE("failed to get pad from first element");
3419 /* create ghostpad */
3420 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3421 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3422 LOGE("failed to add ghostpad to videobin");
3425 gst_object_unref(pad);
3427 /* done. free allocated variables */
3428 g_list_free(element_bucket);
3432 return MM_ERROR_NONE;
3435 LOGE("ERROR : releasing videobin");
3436 g_list_free(element_bucket);
3439 gst_object_unref(GST_OBJECT(pad));
3441 /* release videobin with it's childs */
3442 if (videobin[MMPLAYER_V_BIN].gst)
3443 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3445 MMPLAYER_FREEIF(videobin);
3446 player->pipeline->videobin = NULL;
3448 return MM_ERROR_PLAYER_INTERNAL;
3452 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3454 GList *element_bucket = NULL;
3455 MMPlayerGstElement *textbin = player->pipeline->textbin;
3457 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3458 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3459 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3460 "signal-handoffs", FALSE,
3463 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3464 __mmplayer_add_signal_connection(player,
3465 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3466 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3468 G_CALLBACK(__mmplayer_update_subtitle),
3471 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3472 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3474 if (!player->play_subtitle) {
3475 LOGD("add textbin sink as sink element of whole pipeline.");
3476 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3479 /* adding created elements to bin */
3480 LOGD("adding created elements to bin");
3481 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3482 LOGE("failed to add elements");
3486 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3487 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3488 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3490 /* linking elements in the bucket by added order. */
3491 LOGD("Linking elements in the bucket by added order.");
3492 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3493 LOGE("failed to link elements");
3497 /* done. free allocated variables */
3498 g_list_free(element_bucket);
3500 if (textbin[MMPLAYER_T_QUEUE].gst) {
3502 GstPad *ghostpad = NULL;
3504 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3506 LOGE("failed to get sink pad of text queue");
3510 ghostpad = gst_ghost_pad_new("text_sink", pad);
3511 gst_object_unref(pad);
3514 LOGE("failed to create ghostpad of textbin");
3518 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3519 LOGE("failed to add ghostpad to textbin");
3520 gst_object_unref(ghostpad);
3525 return MM_ERROR_NONE;
3528 g_list_free(element_bucket);
3530 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3531 LOGE("remove textbin sink from sink list");
3532 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3535 /* release element at __mmplayer_gst_create_text_sink_bin */
3536 return MM_ERROR_PLAYER_INTERNAL;
3540 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3542 MMPlayerGstElement *textbin = NULL;
3543 GList *element_bucket = NULL;
3544 int surface_type = 0;
3549 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3552 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3554 LOGE("failed to allocate memory for textbin");
3555 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3559 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3560 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3561 if (!textbin[MMPLAYER_T_BIN].gst) {
3562 LOGE("failed to create textbin");
3567 player->pipeline->textbin = textbin;
3570 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3571 LOGD("surface type for subtitle : %d", surface_type);
3572 switch (surface_type) {
3573 case MM_DISPLAY_SURFACE_OVERLAY:
3574 case MM_DISPLAY_SURFACE_NULL:
3575 case MM_DISPLAY_SURFACE_REMOTE:
3576 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3577 LOGE("failed to make plain text elements");
3588 return MM_ERROR_NONE;
3592 LOGD("ERROR : releasing textbin");
3594 g_list_free(element_bucket);
3596 /* release signal */
3597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3599 /* release element which are not added to bin */
3600 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3601 /* NOTE : skip bin */
3602 if (textbin[i].gst) {
3603 GstObject *parent = NULL;
3604 parent = gst_element_get_parent(textbin[i].gst);
3607 gst_object_unref(GST_OBJECT(textbin[i].gst));
3608 textbin[i].gst = NULL;
3610 gst_object_unref(GST_OBJECT(parent));
3615 /* release textbin with it's childs */
3616 if (textbin[MMPLAYER_T_BIN].gst)
3617 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3619 MMPLAYER_FREEIF(player->pipeline->textbin);
3620 player->pipeline->textbin = NULL;
3623 return MM_ERROR_PLAYER_INTERNAL;
3627 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3629 MMPlayerGstElement *mainbin = NULL;
3630 MMPlayerGstElement *textbin = NULL;
3631 MMHandleType attrs = 0;
3632 GstElement *subsrc = NULL;
3633 GstElement *subparse = NULL;
3634 gchar *subtitle_uri = NULL;
3635 const gchar *charset = NULL;
3641 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3643 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3645 mainbin = player->pipeline->mainbin;
3647 attrs = MMPLAYER_GET_ATTRS(player);
3649 LOGE("cannot get content attribute");
3650 return MM_ERROR_PLAYER_INTERNAL;
3653 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3654 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3655 LOGE("subtitle uri is not proper filepath.");
3656 return MM_ERROR_PLAYER_INVALID_URI;
3659 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3660 LOGE("failed to get storage info of subtitle path");
3661 return MM_ERROR_PLAYER_INVALID_URI;
3664 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3666 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3667 player->subtitle_language_list = NULL;
3668 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3670 /* create the subtitle source */
3671 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3673 LOGE("failed to create filesrc element");
3676 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3678 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3679 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3681 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3682 LOGW("failed to add queue");
3683 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3684 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3685 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3690 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3692 LOGE("failed to create subparse element");
3696 charset = util_get_charset(subtitle_uri);
3698 LOGD("detected charset is %s", charset);
3699 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3702 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3703 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3705 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3706 LOGW("failed to add subparse");
3707 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3708 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3709 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3713 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3714 LOGW("failed to link subsrc and subparse");
3718 player->play_subtitle = TRUE;
3719 player->adjust_subtitle_pos = 0;
3721 LOGD("play subtitle using subtitle file");
3723 if (player->pipeline->textbin == NULL) {
3724 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3725 LOGE("failed to create text sink bin. continuing without text");
3729 textbin = player->pipeline->textbin;
3731 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3732 LOGW("failed to add textbin");
3734 /* release signal */
3735 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3737 /* release textbin with it's childs */
3738 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3739 MMPLAYER_FREEIF(player->pipeline->textbin);
3740 player->pipeline->textbin = textbin = NULL;
3744 LOGD("link text input selector and textbin ghost pad");
3746 player->textsink_linked = 1;
3747 player->external_text_idx = 0;
3748 LOGI("textsink is linked");
3750 textbin = player->pipeline->textbin;
3751 LOGD("text bin has been created. reuse it.");
3752 player->external_text_idx = 1;
3755 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3756 LOGW("failed to link subparse and textbin");
3760 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3762 LOGE("failed to get sink pad from textsink to probe data");
3766 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3767 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3769 gst_object_unref(pad);
3772 /* create dot. for debugging */
3773 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3776 return MM_ERROR_NONE;
3779 /* release text pipeline resource */
3780 player->textsink_linked = 0;
3782 /* release signal */
3783 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3785 if (player->pipeline->textbin) {
3786 LOGE("remove textbin");
3788 /* release textbin with it's childs */
3789 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3790 MMPLAYER_FREEIF(player->pipeline->textbin);
3791 player->pipeline->textbin = NULL;
3795 /* release subtitle elem */
3796 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3797 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3799 return MM_ERROR_PLAYER_INTERNAL;
3803 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3805 mm_player_t *player = (mm_player_t *)data;
3806 MMMessageParamType msg = {0, };
3807 GstClockTime duration = 0;
3808 gpointer text = NULL;
3809 guint text_size = 0;
3810 gboolean ret = TRUE;
3811 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3815 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3816 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3818 if (player->is_subtitle_force_drop) {
3819 LOGW("subtitle is dropped forcedly.");
3823 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3824 text = mapinfo.data;
3825 text_size = mapinfo.size;
3826 duration = GST_BUFFER_DURATION(buffer);
3828 if (player->set_mode.subtitle_off) {
3829 LOGD("subtitle is OFF.");
3833 if (!text || (text_size == 0)) {
3834 LOGD("There is no subtitle to be displayed.");
3838 msg.data = (void *)text;
3839 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3841 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3843 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3844 gst_buffer_unmap(buffer, &mapinfo);
3851 static GstPadProbeReturn
3852 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3854 mm_player_t *player = (mm_player_t *)u_data;
3855 GstClockTime cur_timestamp = 0;
3856 gint64 adjusted_timestamp = 0;
3857 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3859 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3861 if (player->set_mode.subtitle_off) {
3862 LOGD("subtitle is OFF.");
3866 if (player->adjust_subtitle_pos == 0) {
3867 LOGD("nothing to do");
3871 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3872 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3874 if (adjusted_timestamp < 0) {
3875 LOGD("adjusted_timestamp under zero");
3880 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3881 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3882 GST_TIME_ARGS(cur_timestamp),
3883 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3885 return GST_PAD_PROBE_OK;
3889 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3893 /* check player and subtitlebin are created */
3894 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3895 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3897 if (position == 0) {
3898 LOGD("nothing to do");
3900 return MM_ERROR_NONE;
3904 case MM_PLAYER_POS_FORMAT_TIME:
3906 /* check current postion */
3907 player->adjust_subtitle_pos = position;
3909 LOGD("save adjust_subtitle_pos in player") ;
3915 LOGW("invalid format.");
3917 return MM_ERROR_INVALID_ARGUMENT;
3923 return MM_ERROR_NONE;
3927 * This function is to create audio or video pipeline for playing.
3929 * @param player [in] handle of player
3931 * @return This function returns zero on success.
3936 __mmplayer_gst_create_pipeline(mm_player_t *player)
3938 int ret = MM_ERROR_NONE;
3939 MMPlayerGstElement *mainbin = NULL;
3940 MMHandleType attrs = 0;
3943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3945 /* get profile attribute */
3946 attrs = MMPLAYER_GET_ATTRS(player);
3948 LOGE("failed to get content attribute");
3952 /* create pipeline handles */
3953 if (player->pipeline) {
3954 LOGE("pipeline should be released before create new one");
3958 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3959 if (player->pipeline == NULL)
3962 /* create mainbin */
3963 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3964 if (mainbin == NULL)
3967 /* create pipeline */
3968 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3969 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3970 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3971 LOGE("failed to create pipeline");
3976 player->pipeline->mainbin = mainbin;
3978 /* create the source and decoder elements */
3979 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3980 ret = __mmplayer_gst_build_es_pipeline(player);
3982 ret = __mmplayer_gst_build_pipeline(player);
3984 if (ret != MM_ERROR_NONE) {
3985 LOGE("failed to create some elements");
3989 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3990 if (__mmplayer_check_subtitle(player)
3991 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3992 LOGE("failed to create text pipeline");
3995 ret = __mmplayer_gst_add_bus_watch(player);
3996 if (ret != MM_ERROR_NONE) {
3997 LOGE("failed to add bus watch");
4002 return MM_ERROR_NONE;
4005 __mmplayer_gst_destroy_pipeline(player);
4006 return MM_ERROR_PLAYER_INTERNAL;
4010 __mmplayer_reset_gapless_state(mm_player_t *player)
4013 MMPLAYER_RETURN_IF_FAIL(player
4015 && player->pipeline->audiobin
4016 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4018 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4025 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4028 int ret = MM_ERROR_NONE;
4032 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4034 /* cleanup stuffs */
4035 MMPLAYER_FREEIF(player->type);
4036 player->no_more_pad = FALSE;
4037 player->num_dynamic_pad = 0;
4038 player->demux_pad_index = 0;
4040 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4041 player->subtitle_language_list = NULL;
4042 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4044 __mmplayer_reset_gapless_state(player);
4046 if (player->streamer) {
4047 __mm_player_streaming_initialize(player->streamer, FALSE);
4048 __mm_player_streaming_destroy(player->streamer);
4049 player->streamer = NULL;
4052 /* cleanup unlinked mime type */
4053 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4054 MMPLAYER_FREEIF(player->unlinked_video_mime);
4055 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4057 /* cleanup running stuffs */
4058 __mmplayer_cancel_eos_timer(player);
4060 /* cleanup gst stuffs */
4061 if (player->pipeline) {
4062 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4063 GstTagList *tag_list = player->pipeline->tag_list;
4065 /* first we need to disconnect all signal hander */
4066 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4069 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4070 MMPlayerGstElement *videobin = player->pipeline->videobin;
4071 MMPlayerGstElement *textbin = player->pipeline->textbin;
4072 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4073 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4074 gst_object_unref(bus);
4076 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4077 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4078 if (ret != MM_ERROR_NONE) {
4079 LOGE("fail to change state to NULL");
4080 return MM_ERROR_PLAYER_INTERNAL;
4083 LOGW("succeeded in changing state to NULL");
4085 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4088 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4089 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4091 /* free avsysaudiosink
4092 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4093 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4095 MMPLAYER_FREEIF(audiobin);
4096 MMPLAYER_FREEIF(videobin);
4097 MMPLAYER_FREEIF(textbin);
4098 MMPLAYER_FREEIF(mainbin);
4102 gst_tag_list_unref(tag_list);
4104 MMPLAYER_FREEIF(player->pipeline);
4106 MMPLAYER_FREEIF(player->album_art);
4108 if (player->v_stream_caps) {
4109 gst_caps_unref(player->v_stream_caps);
4110 player->v_stream_caps = NULL;
4113 if (player->a_stream_caps) {
4114 gst_caps_unref(player->a_stream_caps);
4115 player->a_stream_caps = NULL;
4118 if (player->s_stream_caps) {
4119 gst_caps_unref(player->s_stream_caps);
4120 player->s_stream_caps = NULL;
4122 __mmplayer_track_destroy(player);
4124 if (player->sink_elements)
4125 g_list_free(player->sink_elements);
4126 player->sink_elements = NULL;
4128 if (player->bufmgr) {
4129 tbm_bufmgr_deinit(player->bufmgr);
4130 player->bufmgr = NULL;
4133 LOGW("finished destroy pipeline");
4141 __mmplayer_gst_realize(mm_player_t *player)
4144 int ret = MM_ERROR_NONE;
4148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4150 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4152 ret = __mmplayer_gst_create_pipeline(player);
4154 LOGE("failed to create pipeline");
4158 /* set pipeline state to READY */
4159 /* NOTE : state change to READY must be performed sync. */
4160 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4161 ret = __mmplayer_gst_set_state(player,
4162 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4164 if (ret != MM_ERROR_NONE) {
4165 /* return error if failed to set state */
4166 LOGE("failed to set READY state");
4170 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4172 /* create dot before error-return. for debugging */
4173 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4181 __mmplayer_gst_unrealize(mm_player_t *player)
4183 int ret = MM_ERROR_NONE;
4187 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4189 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4190 MMPLAYER_PRINT_STATE(player);
4192 /* release miscellaneous information */
4193 __mmplayer_release_misc(player);
4195 /* destroy pipeline */
4196 ret = __mmplayer_gst_destroy_pipeline(player);
4197 if (ret != MM_ERROR_NONE) {
4198 LOGE("failed to destory pipeline");
4202 /* release miscellaneous information.
4203 these info needs to be released after pipeline is destroyed. */
4204 __mmplayer_release_misc_post(player);
4206 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4214 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4219 LOGW("set_message_callback is called with invalid player handle");
4220 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4223 player->msg_cb = callback;
4224 player->msg_cb_param = user_param;
4226 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4230 return MM_ERROR_NONE;
4234 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4236 int ret = MM_ERROR_NONE;
4241 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4242 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4243 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4245 memset(data, 0, sizeof(MMPlayerParseProfile));
4247 if (strstr(uri, "es_buff://")) {
4248 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4249 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4250 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4251 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4253 tmp = g_ascii_strdown(uri, strlen(uri));
4254 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4255 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4257 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4259 } else if (strstr(uri, "mms://")) {
4260 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4261 } else if ((path = strstr(uri, "mem://"))) {
4262 ret = __mmplayer_set_mem_uri(data, path, param);
4264 ret = __mmplayer_set_file_uri(data, uri);
4267 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4268 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4269 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4270 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4272 /* dump parse result */
4273 SECURE_LOGW("incoming uri : %s", uri);
4274 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4275 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4283 __mmplayer_can_do_interrupt(mm_player_t *player)
4285 if (!player || !player->pipeline || !player->attrs) {
4286 LOGW("not initialized");
4290 if (player->audio_stream_render_cb) {
4291 LOGW("not support in pcm extraction mode");
4295 /* check if seeking */
4296 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4297 MMMessageParamType msg_param;
4298 memset(&msg_param, 0, sizeof(MMMessageParamType));
4299 msg_param.code = MM_ERROR_PLAYER_SEEK;
4300 player->seek_state = MMPLAYER_SEEK_NONE;
4301 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4305 /* check other thread */
4306 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4307 LOGW("locked already, cmd state : %d", player->cmd);
4309 /* check application command */
4310 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4311 LOGW("playing.. should wait cmd lock then, will be interrupted");
4313 /* lock will be released at mrp_resource_release_cb() */
4314 MMPLAYER_CMD_LOCK(player);
4317 LOGW("nothing to do");
4320 LOGW("can interrupt immediately");
4324 FAILED: /* with CMD UNLOCKED */
4327 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4332 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4335 mm_player_t *player = NULL;
4339 if (user_data == NULL) {
4340 LOGE("- user_data is null");
4343 player = (mm_player_t *)user_data;
4345 /* do something to release resource here.
4346 * player stop and interrupt forwarding */
4347 if (!__mmplayer_can_do_interrupt(player)) {
4348 LOGW("no need to interrupt, so leave");
4350 MMMessageParamType msg = {0, };
4353 player->interrupted_by_resource = TRUE;
4355 /* get last play position */
4356 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4357 LOGW("failed to get play position.");
4359 msg.union_type = MM_MSG_UNION_TIME;
4360 msg.time.elapsed = pos;
4361 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4363 LOGD("video resource conflict so, resource will be freed by unrealizing");
4364 if (_mmplayer_unrealize((MMHandleType)player))
4365 LOGW("failed to unrealize");
4367 /* lock is called in __mmplayer_can_do_interrupt() */
4368 MMPLAYER_CMD_UNLOCK(player);
4371 if (res == player->video_overlay_resource)
4372 player->video_overlay_resource = FALSE;
4374 player->video_decoder_resource = FALSE;
4382 __mmplayer_initialize_video_roi(mm_player_t *player)
4384 player->video_roi.scale_x = 0.0;
4385 player->video_roi.scale_y = 0.0;
4386 player->video_roi.scale_width = 1.0;
4387 player->video_roi.scale_height = 1.0;
4391 _mmplayer_create_player(MMHandleType handle)
4393 int ret = MM_ERROR_PLAYER_INTERNAL;
4394 bool enabled = false;
4396 mm_player_t *player = MM_PLAYER_CAST(handle);
4400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4402 /* initialize player state */
4403 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4404 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4405 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4406 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4408 /* check current state */
4409 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4411 /* construct attributes */
4412 player->attrs = _mmplayer_construct_attribute(handle);
4414 if (!player->attrs) {
4415 LOGE("Failed to construct attributes");
4419 /* initialize gstreamer with configured parameter */
4420 if (!__mmplayer_init_gstreamer(player)) {
4421 LOGE("Initializing gstreamer failed");
4422 _mmplayer_deconstruct_attribute(handle);
4426 /* create lock. note that g_tread_init() has already called in gst_init() */
4427 g_mutex_init(&player->fsink_lock);
4429 /* create update tag lock */
4430 g_mutex_init(&player->update_tag_lock);
4432 /* create gapless play mutex */
4433 g_mutex_init(&player->gapless_play_thread_mutex);
4435 /* create gapless play cond */
4436 g_cond_init(&player->gapless_play_thread_cond);
4438 /* create gapless play thread */
4439 player->gapless_play_thread =
4440 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4441 if (!player->gapless_play_thread) {
4442 LOGE("failed to create gapless play thread");
4443 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4444 g_mutex_clear(&player->gapless_play_thread_mutex);
4445 g_cond_clear(&player->gapless_play_thread_cond);
4449 player->bus_msg_q = g_queue_new();
4450 if (!player->bus_msg_q) {
4451 LOGE("failed to create queue for bus_msg");
4452 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4456 ret = _mmplayer_initialize_video_capture(player);
4457 if (ret != MM_ERROR_NONE) {
4458 LOGE("failed to initialize video capture");
4462 /* initialize resource manager */
4463 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4464 __resource_release_cb, player, &player->resource_manager)
4465 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4466 LOGE("failed to initialize resource manager");
4467 ret = MM_ERROR_PLAYER_INTERNAL;
4471 /* create video bo lock and cond */
4472 g_mutex_init(&player->video_bo_mutex);
4473 g_cond_init(&player->video_bo_cond);
4475 /* create media stream callback mutex */
4476 g_mutex_init(&player->media_stream_cb_lock);
4478 /* create subtitle info lock and cond */
4479 g_mutex_init(&player->subtitle_info_mutex);
4480 g_cond_init(&player->subtitle_info_cond);
4482 player->streaming_type = STREAMING_SERVICE_NONE;
4484 /* give default value of audio effect setting */
4485 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4486 player->sound.rg_enable = false;
4487 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4489 player->play_subtitle = FALSE;
4490 player->has_closed_caption = FALSE;
4491 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4492 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4493 player->pending_resume = FALSE;
4494 if (player->ini.dump_element_keyword[0][0] == '\0')
4495 player->ini.set_dump_element_flag = FALSE;
4497 player->ini.set_dump_element_flag = TRUE;
4499 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4500 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4501 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4503 /* Set video360 settings to their defaults for just-created player.
4506 player->is_360_feature_enabled = FALSE;
4507 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4508 LOGI("spherical feature info: %d", enabled);
4510 player->is_360_feature_enabled = TRUE;
4512 LOGE("failed to get spherical feature info");
4515 player->is_content_spherical = FALSE;
4516 player->is_video360_enabled = TRUE;
4517 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4518 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4519 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4520 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4521 player->video360_zoom = 1.0f;
4522 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4523 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4525 __mmplayer_initialize_video_roi(player);
4527 /* set player state to null */
4528 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4529 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4533 return MM_ERROR_NONE;
4537 g_mutex_clear(&player->fsink_lock);
4538 /* free update tag lock */
4539 g_mutex_clear(&player->update_tag_lock);
4540 g_queue_free(player->bus_msg_q);
4541 /* free gapless play thread */
4542 if (player->gapless_play_thread) {
4543 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4544 player->gapless_play_thread_exit = TRUE;
4545 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4546 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4548 g_thread_join(player->gapless_play_thread);
4549 player->gapless_play_thread = NULL;
4551 g_mutex_clear(&player->gapless_play_thread_mutex);
4552 g_cond_clear(&player->gapless_play_thread_cond);
4555 /* release attributes */
4556 _mmplayer_deconstruct_attribute(handle);
4564 __mmplayer_init_gstreamer(mm_player_t *player)
4566 static gboolean initialized = FALSE;
4567 static const int max_argc = 50;
4569 gchar **argv = NULL;
4570 gchar **argv2 = NULL;
4576 LOGD("gstreamer already initialized.");
4581 argc = malloc(sizeof(int));
4582 argv = malloc(sizeof(gchar *) * max_argc);
4583 argv2 = malloc(sizeof(gchar *) * max_argc);
4585 if (!argc || !argv || !argv2)
4588 memset(argv, 0, sizeof(gchar *) * max_argc);
4589 memset(argv2, 0, sizeof(gchar *) * max_argc);
4593 argv[0] = g_strdup("mmplayer");
4596 for (i = 0; i < 5; i++) {
4597 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4598 if (strlen(player->ini.gst_param[i]) > 0) {
4599 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4604 /* we would not do fork for scanning plugins */
4605 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4608 /* check disable registry scan */
4609 if (player->ini.skip_rescan) {
4610 argv[*argc] = g_strdup("--gst-disable-registry-update");
4614 /* check disable segtrap */
4615 if (player->ini.disable_segtrap) {
4616 argv[*argc] = g_strdup("--gst-disable-segtrap");
4620 LOGD("initializing gstreamer with following parameter");
4621 LOGD("argc : %d", *argc);
4624 for (i = 0; i < arg_count; i++) {
4626 LOGD("argv[%d] : %s", i, argv2[i]);
4629 /* initializing gstreamer */
4630 if (!gst_init_check(argc, &argv, &err)) {
4631 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4638 for (i = 0; i < arg_count; i++) {
4639 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4640 MMPLAYER_FREEIF(argv2[i]);
4643 MMPLAYER_FREEIF(argv);
4644 MMPLAYER_FREEIF(argv2);
4645 MMPLAYER_FREEIF(argc);
4655 for (i = 0; i < arg_count; i++) {
4656 LOGD("free[%d] : %s", i, argv2[i]);
4657 MMPLAYER_FREEIF(argv2[i]);
4660 MMPLAYER_FREEIF(argv);
4661 MMPLAYER_FREEIF(argv2);
4662 MMPLAYER_FREEIF(argc);
4668 __mmplayer_check_async_state_transition(mm_player_t *player)
4670 GstState element_state = GST_STATE_VOID_PENDING;
4671 GstState element_pending_state = GST_STATE_VOID_PENDING;
4672 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4673 GstElement *element = NULL;
4674 gboolean async = FALSE;
4676 /* check player handle */
4677 MMPLAYER_RETURN_IF_FAIL(player &&
4679 player->pipeline->mainbin &&
4680 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4683 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4685 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4686 LOGD("don't need to check the pipeline state");
4690 MMPLAYER_PRINT_STATE(player);
4692 /* wait for state transition */
4693 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4694 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4696 if (ret == GST_STATE_CHANGE_FAILURE) {
4697 LOGE(" [%s] state : %s pending : %s",
4698 GST_ELEMENT_NAME(element),
4699 gst_element_state_get_name(element_state),
4700 gst_element_state_get_name(element_pending_state));
4702 /* dump state of all element */
4703 __mmplayer_dump_pipeline_state(player);
4708 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4713 _mmplayer_destroy(MMHandleType handle)
4715 mm_player_t *player = MM_PLAYER_CAST(handle);
4719 /* check player handle */
4720 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4722 /* destroy can called at anytime */
4723 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4725 /* check async state transition */
4726 __mmplayer_check_async_state_transition(player);
4728 /* release gapless play thread */
4729 if (player->gapless_play_thread) {
4730 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4731 player->gapless_play_thread_exit = TRUE;
4732 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4733 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4735 LOGD("waitting for gapless play thread exit");
4736 g_thread_join(player->gapless_play_thread);
4737 g_mutex_clear(&player->gapless_play_thread_mutex);
4738 g_cond_clear(&player->gapless_play_thread_cond);
4739 LOGD("gapless play thread released");
4742 _mmplayer_release_video_capture(player);
4744 /* de-initialize resource manager */
4745 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4746 player->resource_manager))
4747 LOGE("failed to deinitialize resource manager");
4749 /* release pipeline */
4750 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4751 LOGE("failed to destory pipeline");
4752 return MM_ERROR_PLAYER_INTERNAL;
4755 g_queue_free(player->bus_msg_q);
4757 /* release subtitle info lock and cond */
4758 g_mutex_clear(&player->subtitle_info_mutex);
4759 g_cond_clear(&player->subtitle_info_cond);
4761 __mmplayer_release_dump_list(player->dump_list);
4763 /* release miscellaneous information */
4764 __mmplayer_release_misc(player);
4766 /* release miscellaneous information.
4767 these info needs to be released after pipeline is destroyed. */
4768 __mmplayer_release_misc_post(player);
4770 /* release attributes */
4771 _mmplayer_deconstruct_attribute(handle);
4774 g_mutex_clear(&player->fsink_lock);
4777 g_mutex_clear(&player->update_tag_lock);
4779 /* release video bo lock and cond */
4780 g_mutex_clear(&player->video_bo_mutex);
4781 g_cond_clear(&player->video_bo_cond);
4783 /* release media stream callback lock */
4784 g_mutex_clear(&player->media_stream_cb_lock);
4788 return MM_ERROR_NONE;
4792 _mmplayer_realize(MMHandleType hplayer)
4794 mm_player_t *player = (mm_player_t *)hplayer;
4797 MMHandleType attrs = 0;
4798 int ret = MM_ERROR_NONE;
4802 /* check player handle */
4803 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4805 /* check current state */
4806 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4808 attrs = MMPLAYER_GET_ATTRS(player);
4810 LOGE("fail to get attributes.");
4811 return MM_ERROR_PLAYER_INTERNAL;
4813 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4814 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4816 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4817 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4819 if (ret != MM_ERROR_NONE) {
4820 LOGE("failed to parse profile");
4825 if (uri && (strstr(uri, "es_buff://"))) {
4826 if (strstr(uri, "es_buff://push_mode"))
4827 player->es_player_push_mode = TRUE;
4829 player->es_player_push_mode = FALSE;
4832 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4833 LOGW("mms protocol is not supported format.");
4834 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4837 if (MMPLAYER_IS_STREAMING(player))
4838 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4840 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4842 player->smooth_streaming = FALSE;
4843 player->videodec_linked = 0;
4844 player->audiodec_linked = 0;
4845 player->textsink_linked = 0;
4846 player->is_external_subtitle_present = FALSE;
4847 player->is_external_subtitle_added_now = FALSE;
4848 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4849 player->video360_metadata.is_spherical = -1;
4850 player->is_openal_plugin_used = FALSE;
4851 player->demux_pad_index = 0;
4852 player->subtitle_language_list = NULL;
4853 player->is_subtitle_force_drop = FALSE;
4854 player->last_multiwin_status = FALSE;
4856 __mmplayer_track_initialize(player);
4857 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4859 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4860 gint prebuffer_ms = 0, rebuffer_ms = 0;
4862 player->streamer = __mm_player_streaming_create();
4863 __mm_player_streaming_initialize(player->streamer, TRUE);
4865 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4866 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4868 if (prebuffer_ms > 0) {
4869 prebuffer_ms = MAX(prebuffer_ms, 1000);
4870 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4873 if (rebuffer_ms > 0) {
4874 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4875 rebuffer_ms = MAX(rebuffer_ms, 1000);
4876 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4879 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4880 player->streamer->buffering_req.rebuffer_time);
4883 /* realize pipeline */
4884 ret = __mmplayer_gst_realize(player);
4885 if (ret != MM_ERROR_NONE)
4886 LOGE("fail to realize the player.");
4888 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4896 _mmplayer_unrealize(MMHandleType hplayer)
4898 mm_player_t *player = (mm_player_t *)hplayer;
4899 int ret = MM_ERROR_NONE;
4903 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4905 MMPLAYER_CMD_UNLOCK(player);
4906 /* destroy the gst bus msg thread which is created during realize.
4907 this funct have to be called before getting cmd lock. */
4908 __mmplayer_bus_msg_thread_destroy(player);
4909 MMPLAYER_CMD_LOCK(player);
4911 /* check current state */
4912 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4914 /* check async state transition */
4915 __mmplayer_check_async_state_transition(player);
4917 /* unrealize pipeline */
4918 ret = __mmplayer_gst_unrealize(player);
4920 /* set asm stop if success */
4921 if (MM_ERROR_NONE == ret) {
4922 if (!player->interrupted_by_resource) {
4923 if (player->video_decoder_resource != NULL) {
4924 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4925 player->video_decoder_resource);
4926 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4927 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4929 player->video_decoder_resource = NULL;
4932 if (player->video_overlay_resource != NULL) {
4933 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4934 player->video_overlay_resource);
4935 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4936 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4938 player->video_overlay_resource = NULL;
4941 ret = mm_resource_manager_commit(player->resource_manager);
4942 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4943 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4946 LOGE("failed and don't change asm state to stop");
4954 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4956 mm_player_t *player = (mm_player_t *)hplayer;
4958 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4960 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4964 _mmplayer_get_state(MMHandleType hplayer, int *state)
4966 mm_player_t *player = (mm_player_t *)hplayer;
4968 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4970 *state = MMPLAYER_CURRENT_STATE(player);
4972 return MM_ERROR_NONE;
4977 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4979 mm_player_t *player = (mm_player_t *)hplayer;
4980 GstElement *vol_element = NULL;
4985 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4987 LOGD("volume [L]=%f:[R]=%f",
4988 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4990 /* invalid factor range or not */
4991 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4992 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4993 LOGE("Invalid factor!(valid factor:0~1.0)");
4994 return MM_ERROR_INVALID_ARGUMENT;
4998 /* not support to set other value into each channel */
4999 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5000 return MM_ERROR_INVALID_ARGUMENT;
5002 /* Save volume to handle. Currently the first array element will be saved. */
5003 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5005 /* check pipeline handle */
5006 if (!player->pipeline || !player->pipeline->audiobin) {
5007 LOGD("audiobin is not created yet");
5008 LOGD("but, current stored volume will be set when it's created.");
5010 /* NOTE : stored volume will be used in create_audiobin
5011 * returning MM_ERROR_NONE here makes application to able to
5012 * set volume at anytime.
5014 return MM_ERROR_NONE;
5017 /* setting volume to volume element */
5018 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5021 LOGD("volume is set [%f]", player->sound.volume);
5022 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5027 return MM_ERROR_NONE;
5031 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5033 mm_player_t *player = (mm_player_t *)hplayer;
5038 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5039 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5041 /* returning stored volume */
5042 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5043 volume->level[i] = player->sound.volume;
5047 return MM_ERROR_NONE;
5051 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5053 mm_player_t *player = (mm_player_t *)hplayer;
5054 GstElement *vol_element = NULL;
5058 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5060 /* mute value shoud 0 or 1 */
5061 if (mute != 0 && mute != 1) {
5062 LOGE("bad mute value");
5064 /* FIXIT : definitly, we need _BAD_PARAM error code */
5065 return MM_ERROR_INVALID_ARGUMENT;
5068 player->sound.mute = mute;
5070 /* just hold mute value if pipeline is not ready */
5071 if (!player->pipeline || !player->pipeline->audiobin) {
5072 LOGD("pipeline is not ready. holding mute value");
5073 return MM_ERROR_NONE;
5076 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5078 /* NOTE : volume will only created when the bt is enabled */
5080 LOGD("mute : %d", mute);
5081 g_object_set(vol_element, "mute", mute, NULL);
5083 LOGD("volume elemnet is not created. using volume in audiosink");
5087 return MM_ERROR_NONE;
5091 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5093 mm_player_t *player = (mm_player_t *)hplayer;
5097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5098 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5100 /* just hold mute value if pipeline is not ready */
5101 if (!player->pipeline || !player->pipeline->audiobin) {
5102 LOGD("pipeline is not ready. returning stored value");
5103 *pmute = player->sound.mute;
5104 return MM_ERROR_NONE;
5107 *pmute = player->sound.mute;
5111 return MM_ERROR_NONE;
5115 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5117 mm_player_t *player = (mm_player_t *)hplayer;
5121 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5123 player->video_stream_changed_cb = callback;
5124 player->video_stream_changed_cb_user_param = user_param;
5125 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5129 return MM_ERROR_NONE;
5133 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5135 mm_player_t *player = (mm_player_t *)hplayer;
5139 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5141 player->audio_stream_changed_cb = callback;
5142 player->audio_stream_changed_cb_user_param = user_param;
5143 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5147 return MM_ERROR_NONE;
5151 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5153 mm_player_t *player = (mm_player_t *)hplayer;
5157 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5159 player->audio_stream_render_cb = callback;
5160 player->audio_stream_cb_user_param = user_param;
5161 player->audio_stream_sink_sync = sync;
5162 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5166 return MM_ERROR_NONE;
5170 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5172 mm_player_t *player = (mm_player_t *)hplayer;
5176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5178 if (callback && !player->bufmgr)
5179 player->bufmgr = tbm_bufmgr_init(-1);
5181 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5182 player->video_stream_cb = callback;
5183 player->video_stream_cb_user_param = user_param;
5185 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5189 return MM_ERROR_NONE;
5193 _mmplayer_start(MMHandleType hplayer)
5195 mm_player_t *player = (mm_player_t *)hplayer;
5196 gint ret = MM_ERROR_NONE;
5200 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5202 /* check current state */
5203 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5205 /* start pipeline */
5206 ret = __mmplayer_gst_start(player);
5207 if (ret != MM_ERROR_NONE)
5208 LOGE("failed to start player.");
5210 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5211 LOGD("force playing start even during buffering");
5212 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5220 /* NOTE: post "not supported codec message" to application
5221 * when one codec is not found during AUTOPLUGGING in MSL.
5222 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5223 * And, if any codec is not found, don't send message here.
5224 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5227 __mmplayer_handle_missed_plugin(mm_player_t *player)
5229 MMMessageParamType msg_param;
5230 memset(&msg_param, 0, sizeof(MMMessageParamType));
5231 gboolean post_msg_direct = FALSE;
5235 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5237 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5238 player->not_supported_codec, player->can_support_codec);
5240 if (player->not_found_demuxer) {
5241 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5242 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5244 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5245 MMPLAYER_FREEIF(msg_param.data);
5247 return MM_ERROR_NONE;
5250 if (player->not_supported_codec) {
5251 if (player->can_support_codec) {
5252 // There is one codec to play
5253 post_msg_direct = TRUE;
5255 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5256 post_msg_direct = TRUE;
5259 if (post_msg_direct) {
5260 MMMessageParamType msg_param;
5261 memset(&msg_param, 0, sizeof(MMMessageParamType));
5263 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5264 LOGW("not found AUDIO codec, posting error code to application.");
5266 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5267 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5268 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5269 LOGW("not found VIDEO codec, posting error code to application.");
5271 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5272 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5275 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5277 MMPLAYER_FREEIF(msg_param.data);
5279 return MM_ERROR_NONE;
5281 // no any supported codec case
5282 LOGW("not found any codec, posting error code to application.");
5284 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5285 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5286 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5288 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5289 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5292 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5294 MMPLAYER_FREEIF(msg_param.data);
5300 return MM_ERROR_NONE;
5304 __mmplayer_check_pipeline(mm_player_t *player)
5306 GstState element_state = GST_STATE_VOID_PENDING;
5307 GstState element_pending_state = GST_STATE_VOID_PENDING;
5309 int ret = MM_ERROR_NONE;
5311 if (!player->gapless.reconfigure)
5314 LOGW("pipeline is under construction.");
5316 MMPLAYER_PLAYBACK_LOCK(player);
5317 MMPLAYER_PLAYBACK_UNLOCK(player);
5319 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5321 /* wait for state transition */
5322 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5323 if (ret == GST_STATE_CHANGE_FAILURE)
5324 LOGE("failed to change pipeline state within %d sec", timeout);
5327 /* NOTE : it should be able to call 'stop' anytime*/
5329 _mmplayer_stop(MMHandleType hplayer)
5331 mm_player_t *player = (mm_player_t *)hplayer;
5332 int ret = MM_ERROR_NONE;
5336 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5338 /* check current state */
5339 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5341 /* check pipline building state */
5342 __mmplayer_check_pipeline(player);
5343 __mmplayer_reset_gapless_state(player);
5345 /* NOTE : application should not wait for EOS after calling STOP */
5346 __mmplayer_cancel_eos_timer(player);
5349 player->seek_state = MMPLAYER_SEEK_NONE;
5352 ret = __mmplayer_gst_stop(player);
5354 if (ret != MM_ERROR_NONE)
5355 LOGE("failed to stop player.");
5363 _mmplayer_pause(MMHandleType hplayer)
5365 mm_player_t *player = (mm_player_t *)hplayer;
5366 gint64 pos_nsec = 0;
5367 gboolean async = FALSE;
5368 gint ret = MM_ERROR_NONE;
5372 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5374 /* check current state */
5375 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5377 /* check pipline building state */
5378 __mmplayer_check_pipeline(player);
5380 switch (MMPLAYER_CURRENT_STATE(player)) {
5381 case MM_PLAYER_STATE_READY:
5383 /* check prepare async or not.
5384 * In the case of streaming playback, it's recommned to avoid blocking wait.
5386 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5387 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5389 /* Changing back sync of rtspsrc to async */
5390 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5391 LOGD("async prepare working mode for rtsp");
5397 case MM_PLAYER_STATE_PLAYING:
5399 /* NOTE : store current point to overcome some bad operation
5400 *(returning zero when getting current position in paused state) of some
5403 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5404 LOGW("getting current position failed in paused");
5406 player->last_position = pos_nsec;
5408 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5409 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5410 This causes problem is position calculation during normal pause resume scenarios also.
5411 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5412 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5413 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5414 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5420 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5421 LOGD("doing async pause in case of ms buff src");
5425 /* pause pipeline */
5426 ret = __mmplayer_gst_pause(player, async);
5428 if (ret != MM_ERROR_NONE)
5429 LOGE("failed to pause player. ret : 0x%x", ret);
5431 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5432 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5433 LOGE("failed to update display_rotation");
5441 /* in case of streaming, pause could take long time.*/
5443 _mmplayer_abort_pause(MMHandleType hplayer)
5445 mm_player_t *player = (mm_player_t *)hplayer;
5446 int ret = MM_ERROR_NONE;
5450 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5452 player->pipeline->mainbin,
5453 MM_ERROR_PLAYER_NOT_INITIALIZED);
5455 LOGD("set the pipeline state to READY");
5457 /* set state to READY */
5458 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5459 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5460 if (ret != MM_ERROR_NONE) {
5461 LOGE("fail to change state to READY");
5462 return MM_ERROR_PLAYER_INTERNAL;
5465 LOGD("succeeded in changing state to READY");
5470 _mmplayer_resume(MMHandleType hplayer)
5472 mm_player_t *player = (mm_player_t *)hplayer;
5473 int ret = MM_ERROR_NONE;
5474 gboolean async = FALSE;
5478 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5480 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5481 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5482 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5486 /* Changing back sync mode rtspsrc to async */
5487 LOGD("async resume for rtsp case");
5491 /* check current state */
5492 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5494 ret = __mmplayer_gst_resume(player, async);
5495 if (ret != MM_ERROR_NONE)
5496 LOGE("failed to resume player.");
5498 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5499 LOGD("force resume even during buffering");
5500 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5509 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5511 mm_player_t *player = (mm_player_t *)hplayer;
5512 gint64 pos_nsec = 0;
5513 int ret = MM_ERROR_NONE;
5515 signed long long start = 0, stop = 0;
5516 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5519 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5520 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5522 /* The sound of video is not supported under 0.0 and over 2.0. */
5523 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5524 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5527 _mmplayer_set_mute(hplayer, mute);
5529 if (player->playback_rate == rate)
5530 return MM_ERROR_NONE;
5532 /* If the position is reached at start potion during fast backward, EOS is posted.
5533 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5535 player->playback_rate = rate;
5537 current_state = MMPLAYER_CURRENT_STATE(player);
5539 if (current_state != MM_PLAYER_STATE_PAUSED)
5540 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5542 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5544 if ((current_state == MM_PLAYER_STATE_PAUSED)
5545 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5546 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5547 pos_nsec = player->last_position;
5552 stop = GST_CLOCK_TIME_NONE;
5554 start = GST_CLOCK_TIME_NONE;
5558 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5559 player->playback_rate,
5561 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5562 GST_SEEK_TYPE_SET, start,
5563 GST_SEEK_TYPE_SET, stop)) {
5564 LOGE("failed to set speed playback");
5565 return MM_ERROR_PLAYER_SEEK;
5568 LOGD("succeeded to set speed playback as %0.1f", rate);
5572 return MM_ERROR_NONE;;
5576 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5578 mm_player_t *player = (mm_player_t *)hplayer;
5579 int ret = MM_ERROR_NONE;
5583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5585 /* check pipline building state */
5586 __mmplayer_check_pipeline(player);
5588 ret = __mmplayer_gst_set_position(player, position, FALSE);
5596 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5598 mm_player_t *player = (mm_player_t *)hplayer;
5599 int ret = MM_ERROR_NONE;
5601 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5603 ret = __mmplayer_gst_get_position(player, position);
5609 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5611 mm_player_t *player = (mm_player_t *)hplayer;
5612 int ret = MM_ERROR_NONE;
5614 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5615 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5617 if (g_strrstr(player->type, "video/mpegts"))
5618 __mmplayer_update_duration_value(player);
5620 *duration = player->duration;
5625 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5627 mm_player_t *player = (mm_player_t *)hplayer;
5628 int ret = MM_ERROR_NONE;
5630 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5632 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5638 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5640 mm_player_t *player = (mm_player_t *)hplayer;
5641 int ret = MM_ERROR_NONE;
5645 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5647 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5655 __mmplayer_is_midi_type(gchar *str_caps)
5657 if ((g_strrstr(str_caps, "audio/midi")) ||
5658 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5659 (g_strrstr(str_caps, "application/x-smaf")) ||
5660 (g_strrstr(str_caps, "audio/x-imelody")) ||
5661 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5662 (g_strrstr(str_caps, "audio/xmf")) ||
5663 (g_strrstr(str_caps, "audio/mxmf"))) {
5672 __mmplayer_is_only_mp3_type(gchar *str_caps)
5674 if (g_strrstr(str_caps, "application/x-id3") ||
5675 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5681 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5683 GstStructure *caps_structure = NULL;
5684 gint samplerate = 0;
5688 MMPLAYER_RETURN_IF_FAIL(player && caps);
5690 caps_structure = gst_caps_get_structure(caps, 0);
5692 /* set stream information */
5693 gst_structure_get_int(caps_structure, "rate", &samplerate);
5694 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5696 gst_structure_get_int(caps_structure, "channels", &channels);
5697 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5699 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5703 __mmplayer_update_content_type_info(mm_player_t *player)
5706 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5708 if (__mmplayer_is_midi_type(player->type)) {
5709 player->bypass_audio_effect = TRUE;
5713 if (!player->streamer) {
5714 LOGD("no need to check streaming type");
5718 if (g_strrstr(player->type, "application/x-hls")) {
5719 /* If it can't know exact type when it parses uri because of redirection case,
5720 * it will be fixed by typefinder or when doing autoplugging.
5722 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5723 player->streamer->is_adaptive_streaming = TRUE;
5724 } else if (g_strrstr(player->type, "application/dash+xml")) {
5725 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5726 player->streamer->is_adaptive_streaming = TRUE;
5729 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5730 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5731 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5733 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5734 if (player->streamer->is_adaptive_streaming)
5735 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5737 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5741 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5746 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5747 GstCaps *caps, gpointer data)
5749 mm_player_t *player = (mm_player_t *)data;
5754 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5756 /* store type string */
5757 MMPLAYER_FREEIF(player->type);
5758 player->type = gst_caps_to_string(caps);
5760 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5761 player, player->type, probability, gst_caps_get_size(caps));
5763 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5764 (g_strrstr(player->type, "audio/x-raw-int"))) {
5765 LOGE("not support media format");
5767 if (player->msg_posted == FALSE) {
5768 MMMessageParamType msg_param;
5769 memset(&msg_param, 0, sizeof(MMMessageParamType));
5771 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5772 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5774 /* don't post more if one was sent already */
5775 player->msg_posted = TRUE;
5780 __mmplayer_update_content_type_info(player);
5782 pad = gst_element_get_static_pad(tf, "src");
5784 LOGE("fail to get typefind src pad.");
5788 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5789 gboolean async = FALSE;
5790 LOGE("failed to autoplug %s", player->type);
5792 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5794 if (async && player->msg_posted == FALSE)
5795 __mmplayer_handle_missed_plugin(player);
5799 gst_object_unref(GST_OBJECT(pad));
5807 __mmplayer_gst_make_decodebin(mm_player_t *player)
5809 GstElement *decodebin = NULL;
5813 /* create decodebin */
5814 decodebin = gst_element_factory_make("decodebin", NULL);
5817 LOGE("fail to create decodebin");
5821 /* raw pad handling signal */
5822 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5823 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5825 /* no-more-pad pad handling signal */
5826 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5827 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5829 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5830 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5832 /* This signal is emitted when a pad for which there is no further possible
5833 decoding is added to the decodebin.*/
5834 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5835 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5837 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5838 before looking for any elements that can handle that stream.*/
5839 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5840 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5842 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5843 before looking for any elements that can handle that stream.*/
5844 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5845 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5847 /* This signal is emitted once decodebin has finished decoding all the data.*/
5848 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5849 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5851 /* This signal is emitted when a element is added to the bin.*/
5852 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5853 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5860 __mmplayer_gst_make_queue2(mm_player_t *player)
5862 GstElement *queue2 = NULL;
5863 gint64 dur_bytes = 0L;
5864 MMPlayerGstElement *mainbin = NULL;
5865 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5868 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5870 mainbin = player->pipeline->mainbin;
5872 queue2 = gst_element_factory_make("queue2", "queue2");
5874 LOGE("failed to create buffering queue element");
5878 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5879 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5881 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5883 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5884 * skip the pull mode(file or ring buffering) setting. */
5885 if (dur_bytes > 0) {
5886 if (!g_strrstr(player->type, "video/mpegts")) {
5887 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5888 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5894 __mm_player_streaming_set_queue2(player->streamer,
5898 (guint64)dur_bytes); /* no meaning at the moment */
5904 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5906 MMPlayerGstElement *mainbin = NULL;
5907 GstElement *decodebin = NULL;
5908 GstElement *queue2 = NULL;
5909 GstPad *sinkpad = NULL;
5910 GstPad *qsrcpad = NULL;
5913 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5915 mainbin = player->pipeline->mainbin;
5917 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5919 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5920 LOGW("need to check: muxed buffer is not null");
5923 queue2 = __mmplayer_gst_make_queue2(player);
5925 LOGE("failed to make queue2");
5929 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5930 LOGE("failed to add buffering queue");
5934 sinkpad = gst_element_get_static_pad(queue2, "sink");
5935 qsrcpad = gst_element_get_static_pad(queue2, "src");
5937 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5938 LOGE("failed to link [%s:%s]-[%s:%s]",
5939 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5943 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5944 LOGE("failed to sync queue2 state with parent");
5948 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5949 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5953 gst_object_unref(GST_OBJECT(sinkpad));
5957 /* create decodebin */
5958 decodebin = __mmplayer_gst_make_decodebin(player);
5960 LOGE("failed to make decodebin");
5964 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5965 LOGE("failed to add decodebin");
5969 /* to force caps on the decodebin element and avoid reparsing stuff by
5970 * typefind. It also avoids a deadlock in the way typefind activates pads in
5971 * the state change */
5972 g_object_set(decodebin, "sink-caps", caps, NULL);
5974 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5976 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5977 LOGE("failed to link [%s:%s]-[%s:%s]",
5978 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5982 gst_object_unref(GST_OBJECT(sinkpad));
5984 gst_object_unref(GST_OBJECT(qsrcpad));
5987 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5988 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5990 /* set decodebin property about buffer in streaming playback. *
5991 * in case of HLS/DASH, it does not need to have big buffer *
5992 * because it is kind of adaptive streaming. */
5993 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5994 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5995 gint high_percent = 0;
5997 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5998 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6000 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6002 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6004 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6005 "high-percent", high_percent,
6006 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6007 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6008 "max-size-buffers", 0, NULL); // disable or automatic
6011 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6012 LOGE("failed to sync decodebin state with parent");
6023 gst_object_unref(GST_OBJECT(sinkpad));
6026 gst_object_unref(GST_OBJECT(qsrcpad));
6029 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6030 * You need to explicitly set elements to the NULL state before
6031 * dropping the final reference, to allow them to clean up.
6033 gst_element_set_state(queue2, GST_STATE_NULL);
6035 /* And, it still has a parent "player".
6036 * You need to let the parent manage the object instead of unreffing the object directly.
6038 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6039 gst_object_unref(queue2);
6044 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6045 * You need to explicitly set elements to the NULL state before
6046 * dropping the final reference, to allow them to clean up.
6048 gst_element_set_state(decodebin, GST_STATE_NULL);
6050 /* And, it still has a parent "player".
6051 * You need to let the parent manage the object instead of unreffing the object directly.
6054 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6055 gst_object_unref(decodebin);
6063 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6067 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6068 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6070 LOGD("class : %s, mime : %s", factory_class, mime);
6072 /* add missing plugin */
6073 /* NOTE : msl should check missing plugin for image mime type.
6074 * Some motion jpeg clips can have playable audio track.
6075 * So, msl have to play audio after displaying popup written video format not supported.
6077 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6078 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6079 LOGD("not found demuxer");
6080 player->not_found_demuxer = TRUE;
6081 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6087 if (!g_strrstr(factory_class, "Demuxer")) {
6088 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6089 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6090 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6092 /* check that clip have multi tracks or not */
6093 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6094 LOGD("video plugin is already linked");
6096 LOGW("add VIDEO to missing plugin");
6097 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6098 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6100 } else if (g_str_has_prefix(mime, "audio")) {
6101 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6102 LOGD("audio plugin is already linked");
6104 LOGW("add AUDIO to missing plugin");
6105 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6106 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6114 return MM_ERROR_NONE;
6118 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6120 mm_player_t *player = (mm_player_t *)data;
6124 MMPLAYER_RETURN_IF_FAIL(player);
6126 /* remove fakesink. */
6127 if (!__mmplayer_gst_remove_fakesink(player,
6128 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6129 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6130 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6131 * source element are not same. To overcome this situation, this function will called
6132 * several places and several times. Therefore, this is not an error case.
6137 LOGD("[handle: %p] pipeline has completely constructed", player);
6139 if ((player->ini.async_start) &&
6140 (player->msg_posted == FALSE) &&
6141 (player->cmd >= MMPLAYER_COMMAND_START))
6142 __mmplayer_handle_missed_plugin(player);
6144 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6148 __mmplayer_check_profile(void)
6151 static int profile_tv = -1;
6153 if (__builtin_expect(profile_tv != -1, 1))
6156 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6157 switch (*profileName) {
6172 __mmplayer_get_next_uri(mm_player_t *player)
6174 MMPlayerParseProfile profile;
6176 guint num_of_list = 0;
6179 num_of_list = g_list_length(player->uri_info.uri_list);
6180 uri_idx = player->uri_info.uri_idx;
6182 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6183 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6184 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6186 LOGW("next uri does not exist");
6190 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6191 LOGE("failed to parse profile");
6195 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6196 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6197 LOGW("uri type is not supported(%d)", profile.uri_type);
6201 LOGD("success to find next uri %d", uri_idx);
6205 if (uri_idx == num_of_list) {
6206 LOGE("failed to find next uri");
6210 player->uri_info.uri_idx = uri_idx;
6211 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6213 if (mm_attrs_commit_all(player->attrs)) {
6214 LOGE("failed to commit");
6218 SECURE_LOGD("next playback uri: %s", uri);
6223 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6225 #define REPEAT_COUNT_INFINITELY -1
6226 #define REPEAT_COUNT_MIN 2
6228 MMHandleType attrs = 0;
6232 guint num_of_list = 0;
6233 int profile_tv = -1;
6237 LOGD("checking for gapless play option");
6239 if (player->pipeline->textbin) {
6240 LOGE("subtitle path is enabled. gapless play is not supported.");
6244 attrs = MMPLAYER_GET_ATTRS(player);
6246 LOGE("fail to get attributes.");
6250 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6252 /* gapless playback is not supported in case of video at TV profile. */
6253 profile_tv = __mmplayer_check_profile();
6254 if (profile_tv && video) {
6255 LOGW("not support video gapless playback");
6259 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6260 LOGE("failed to get play count");
6262 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6263 LOGE("failed to get gapless mode");
6265 /* check repeat count in case of audio */
6267 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6268 LOGW("gapless is disabled");
6272 num_of_list = g_list_length(player->uri_info.uri_list);
6274 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6276 if (num_of_list == 0) {
6277 /* audio looping path */
6278 if (count >= REPEAT_COUNT_MIN) {
6279 /* decrease play count */
6280 /* we succeeded to rewind. update play count and then wait for next EOS */
6282 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6283 /* commit attribute */
6284 if (mm_attrs_commit_all(attrs))
6285 LOGE("failed to commit attribute");
6287 } else if (count != REPEAT_COUNT_INFINITELY) {
6288 LOGD("there is no next uri and no repeat");
6291 LOGD("looping cnt %d", count);
6293 /* gapless playback path */
6294 if (!__mmplayer_get_next_uri(player)) {
6295 LOGE("failed to get next uri");
6302 LOGE("unable to play gapless path. EOS will be posted soon");
6307 __mmplayer_initialize_gapless_play(mm_player_t *player)
6313 player->smooth_streaming = FALSE;
6314 player->videodec_linked = 0;
6315 player->audiodec_linked = 0;
6316 player->textsink_linked = 0;
6317 player->is_external_subtitle_present = FALSE;
6318 player->is_external_subtitle_added_now = FALSE;
6319 player->not_supported_codec = MISSING_PLUGIN_NONE;
6320 player->can_support_codec = FOUND_PLUGIN_NONE;
6321 player->pending_seek.is_pending = false;
6322 player->pending_seek.pos = 0;
6323 player->msg_posted = FALSE;
6324 player->has_many_types = FALSE;
6325 player->no_more_pad = FALSE;
6326 player->not_found_demuxer = 0;
6327 player->seek_state = MMPLAYER_SEEK_NONE;
6328 player->is_subtitle_force_drop = FALSE;
6329 player->play_subtitle = FALSE;
6330 player->adjust_subtitle_pos = 0;
6332 player->total_bitrate = 0;
6333 player->total_maximum_bitrate = 0;
6335 __mmplayer_track_initialize(player);
6336 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6338 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6339 player->bitrate[i] = 0;
6340 player->maximum_bitrate[i] = 0;
6343 if (player->v_stream_caps) {
6344 gst_caps_unref(player->v_stream_caps);
6345 player->v_stream_caps = NULL;
6348 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6350 /* clean found parsers */
6351 if (player->parsers) {
6352 GList *parsers = player->parsers;
6353 for (; parsers; parsers = g_list_next(parsers)) {
6354 gchar *name = parsers->data;
6355 MMPLAYER_FREEIF(name);
6357 g_list_free(player->parsers);
6358 player->parsers = NULL;
6361 /* clean found audio decoders */
6362 if (player->audio_decoders) {
6363 GList *a_dec = player->audio_decoders;
6364 for (; a_dec; a_dec = g_list_next(a_dec)) {
6365 gchar *name = a_dec->data;
6366 MMPLAYER_FREEIF(name);
6368 g_list_free(player->audio_decoders);
6369 player->audio_decoders = NULL;
6376 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6378 MMPlayerGstElement *mainbin = NULL;
6379 MMMessageParamType msg_param = {0,};
6380 GstElement *element = NULL;
6381 MMHandleType attrs = 0;
6383 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6387 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6388 LOGE("player is not initialized");
6392 mainbin = player->pipeline->mainbin;
6393 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6395 attrs = MMPLAYER_GET_ATTRS(player);
6397 LOGE("fail to get attributes");
6401 /* Initialize Player values */
6402 __mmplayer_initialize_gapless_play(player);
6404 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6406 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6407 LOGE("failed to parse profile");
6408 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6412 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6413 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6414 LOGE("dash or hls is not supportable");
6415 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6419 element = __mmplayer_gst_create_source(player);
6421 LOGE("no source element was created");
6425 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6426 LOGE("failed to add source element to pipeline");
6427 gst_object_unref(GST_OBJECT(element));
6432 /* take source element */
6433 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6434 mainbin[MMPLAYER_M_SRC].gst = element;
6438 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6439 if (player->streamer == NULL) {
6440 player->streamer = __mm_player_streaming_create();
6441 __mm_player_streaming_initialize(player->streamer, TRUE);
6444 elem_idx = MMPLAYER_M_TYPEFIND;
6445 element = gst_element_factory_make("typefind", "typefinder");
6446 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6447 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6449 elem_idx = MMPLAYER_M_AUTOPLUG;
6450 element = __mmplayer_gst_make_decodebin(player);
6453 /* check autoplug element is OK */
6455 LOGE("can not create element(%d)", elem_idx);
6459 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6460 LOGE("failed to add sinkbin to pipeline");
6461 gst_object_unref(GST_OBJECT(element));
6466 mainbin[elem_idx].id = elem_idx;
6467 mainbin[elem_idx].gst = element;
6469 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6470 LOGE("Failed to link src - autoplug(or typefind)");
6474 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6475 LOGE("Failed to change state of src element");
6479 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6480 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6481 LOGE("Failed to change state of decodebin");
6485 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6486 LOGE("Failed to change state of src element");
6491 player->gapless.stream_changed = TRUE;
6492 player->gapless.running = TRUE;
6498 MMPLAYER_PLAYBACK_UNLOCK(player);
6500 if (!player->msg_posted) {
6501 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6502 player->msg_posted = TRUE;
6509 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6511 mm_player_selector_t *selector = &player->selector[type];
6512 MMPlayerGstElement *sinkbin = NULL;
6513 enum MainElementID selectorId = MMPLAYER_M_NUM;
6514 enum MainElementID sinkId = MMPLAYER_M_NUM;
6515 GstPad *srcpad = NULL;
6516 GstPad *sinkpad = NULL;
6517 gboolean send_notice = FALSE;
6520 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6522 LOGD("type %d", type);
6525 case MM_PLAYER_TRACK_TYPE_AUDIO:
6526 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6527 sinkId = MMPLAYER_A_BIN;
6528 sinkbin = player->pipeline->audiobin;
6530 case MM_PLAYER_TRACK_TYPE_VIDEO:
6531 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6532 sinkId = MMPLAYER_V_BIN;
6533 sinkbin = player->pipeline->videobin;
6536 case MM_PLAYER_TRACK_TYPE_TEXT:
6537 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6538 sinkId = MMPLAYER_T_BIN;
6539 sinkbin = player->pipeline->textbin;
6542 LOGE("requested type is not supportable");
6547 if (player->pipeline->mainbin[selectorId].gst) {
6550 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6552 if (selector->event_probe_id != 0)
6553 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6554 selector->event_probe_id = 0;
6556 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6557 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6559 if (srcpad && sinkpad) {
6560 /* after getting drained signal there is no data flows, so no need to do pad_block */
6561 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6562 gst_pad_unlink(srcpad, sinkpad);
6564 /* send custom event to sink pad to handle it at video sink */
6566 LOGD("send custom event to sinkpad");
6567 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6568 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6569 gst_pad_send_event(sinkpad, event);
6573 gst_object_unref(sinkpad);
6576 gst_object_unref(srcpad);
6579 LOGD("selector release");
6581 /* release and unref requests pad from the selector */
6582 for (n = 0; n < selector->channels->len; n++) {
6583 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6584 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6586 g_ptr_array_set_size(selector->channels, 0);
6588 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6589 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6591 player->pipeline->mainbin[selectorId].gst = NULL;
6599 __mmplayer_deactivate_old_path(mm_player_t *player)
6602 MMPLAYER_RETURN_IF_FAIL(player);
6604 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6605 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6606 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6607 LOGE("deactivate selector error");
6611 __mmplayer_track_destroy(player);
6612 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6614 if (player->streamer) {
6615 __mm_player_streaming_initialize(player->streamer, FALSE);
6616 __mm_player_streaming_destroy(player->streamer);
6617 player->streamer = NULL;
6620 MMPLAYER_PLAYBACK_LOCK(player);
6621 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6628 if (!player->msg_posted) {
6629 MMMessageParamType msg = {0,};
6632 msg.code = MM_ERROR_PLAYER_INTERNAL;
6633 LOGE("gapless_uri_play> deactivate error");
6635 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6636 player->msg_posted = TRUE;
6642 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6644 int result = MM_ERROR_NONE;
6645 mm_player_t *player = (mm_player_t *)hplayer;
6648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6650 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6651 if (mm_attrs_commit_all(player->attrs)) {
6652 LOGE("failed to commit the original uri.");
6653 result = MM_ERROR_PLAYER_INTERNAL;
6655 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6656 LOGE("failed to add the original uri in the uri list.");
6664 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6666 mm_player_t *player = (mm_player_t *)hplayer;
6667 guint num_of_list = 0;
6671 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6672 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6674 if (player->pipeline && player->pipeline->textbin) {
6675 LOGE("subtitle path is enabled.");
6676 return MM_ERROR_PLAYER_INVALID_STATE;
6679 num_of_list = g_list_length(player->uri_info.uri_list);
6681 if (is_first_path) {
6682 if (num_of_list == 0) {
6683 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6684 LOGD("add original path : %s", uri);
6686 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6687 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6689 LOGD("change original path : %s", uri);
6692 MMHandleType attrs = 0;
6693 attrs = MMPLAYER_GET_ATTRS(player);
6695 if (num_of_list == 0) {
6696 char *original_uri = NULL;
6699 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6701 if (!original_uri) {
6702 LOGE("there is no original uri.");
6703 return MM_ERROR_PLAYER_INVALID_STATE;
6706 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6707 player->uri_info.uri_idx = 0;
6709 LOGD("add original path at first : %s", original_uri);
6713 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6714 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6718 return MM_ERROR_NONE;
6722 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6724 mm_player_t *player = (mm_player_t *)hplayer;
6725 char *next_uri = NULL;
6726 guint num_of_list = 0;
6729 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6731 num_of_list = g_list_length(player->uri_info.uri_list);
6733 if (num_of_list > 0) {
6734 gint uri_idx = player->uri_info.uri_idx;
6736 if (uri_idx < num_of_list-1)
6741 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6742 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6744 *uri = g_strdup(next_uri);
6748 return MM_ERROR_NONE;
6752 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6753 GstCaps *caps, gpointer data)
6755 mm_player_t *player = (mm_player_t *)data;
6756 const gchar *klass = NULL;
6757 const gchar *mime = NULL;
6758 gchar *caps_str = NULL;
6760 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6761 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6762 caps_str = gst_caps_to_string(caps);
6764 LOGW("unknown type of caps : %s from %s",
6765 caps_str, GST_ELEMENT_NAME(elem));
6767 MMPLAYER_FREEIF(caps_str);
6769 /* There is no available codec. */
6770 __mmplayer_check_not_supported_codec(player, klass, mime);
6774 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6775 GstCaps *caps, gpointer data)
6777 mm_player_t *player = (mm_player_t *)data;
6778 const char *mime = NULL;
6779 gboolean ret = TRUE;
6781 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6782 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6784 if (g_str_has_prefix(mime, "audio")) {
6785 GstStructure *caps_structure = NULL;
6786 gint samplerate = 0;
6788 gchar *caps_str = NULL;
6790 caps_structure = gst_caps_get_structure(caps, 0);
6791 gst_structure_get_int(caps_structure, "rate", &samplerate);
6792 gst_structure_get_int(caps_structure, "channels", &channels);
6794 if ((channels > 0 && samplerate == 0)) {
6795 LOGD("exclude audio...");
6799 caps_str = gst_caps_to_string(caps);
6800 /* set it directly because not sent by TAG */
6801 if (g_strrstr(caps_str, "mobile-xmf"))
6802 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6803 MMPLAYER_FREEIF(caps_str);
6804 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6805 MMMessageParamType msg_param;
6806 memset(&msg_param, 0, sizeof(MMMessageParamType));
6807 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6808 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6809 LOGD("video file is not supported on this device");
6811 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6812 LOGD("already video linked");
6815 LOGD("found new stream");
6822 __mmplayer_check_offload_path(mm_player_t *player)
6824 gboolean ret = FALSE;
6825 GstElementFactory *factory = NULL;
6828 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6830 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6831 /* FIXME : 1. need to consider the current audio output path and
6832 player have to know whether it support offload or not.
6833 2. could be added new condition about content length */
6834 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6835 if (!__mmplayer_is_only_mp3_type(player->type))
6838 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6842 LOGD("can setup the audio offload path");
6843 gst_object_unref(factory);
6852 static GstAutoplugSelectResult
6853 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6855 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6857 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6858 int audio_offload = 0;
6860 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6861 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6863 if (audio_offload && __mmplayer_check_offload_path(player)) {
6864 LOGD("expose audio path to build offload path");
6865 player->build_audio_offload = TRUE;
6866 /* update codec info */
6867 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6868 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6869 player->audiodec_linked = 1;
6871 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6875 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6877 LOGD("audio codec type: %d", codec_type);
6878 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6879 /* sw codec will be skipped */
6880 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6881 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6882 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6883 ret = GST_AUTOPLUG_SELECT_SKIP;
6887 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6888 /* hw codec will be skipped */
6889 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6890 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6891 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6892 ret = GST_AUTOPLUG_SELECT_SKIP;
6897 /* set stream information */
6898 if (!player->audiodec_linked)
6899 __mmplayer_set_audio_attrs(player, caps);
6901 /* update codec info */
6902 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6903 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6904 player->audiodec_linked = 1;
6906 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6908 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6910 LOGD("video codec type: %d", codec_type);
6911 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6912 /* sw codec is skipped */
6913 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6914 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6915 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6916 ret = GST_AUTOPLUG_SELECT_SKIP;
6920 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6921 /* hw codec is skipped */
6922 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6923 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6924 ret = GST_AUTOPLUG_SELECT_SKIP;
6929 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6930 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6932 /* mark video decoder for acquire */
6933 if (player->video_decoder_resource == NULL) {
6934 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6935 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6936 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6937 &player->video_decoder_resource)
6938 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6939 LOGE("could not mark video_decoder resource for acquire");
6940 ret = GST_AUTOPLUG_SELECT_SKIP;
6944 LOGW("video decoder resource is already acquired, skip it.");
6945 ret = GST_AUTOPLUG_SELECT_SKIP;
6949 player->interrupted_by_resource = FALSE;
6950 /* acquire resources for video playing */
6951 if (mm_resource_manager_commit(player->resource_manager)
6952 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6953 LOGE("could not acquire resources for video decoding");
6954 ret = GST_AUTOPLUG_SELECT_SKIP;
6959 /* update codec info */
6960 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6961 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6962 player->videodec_linked = 1;
6970 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6971 GstCaps *caps, GstElementFactory *factory, gpointer data)
6973 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6974 mm_player_t *player = (mm_player_t *)data;
6976 gchar *factory_name = NULL;
6977 gchar *caps_str = NULL;
6978 const gchar *klass = NULL;
6981 factory_name = GST_OBJECT_NAME(factory);
6982 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6983 caps_str = gst_caps_to_string(caps);
6985 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6987 /* store type string */
6988 if (player->type == NULL) {
6989 player->type = gst_caps_to_string(caps);
6990 __mmplayer_update_content_type_info(player);
6993 /* filtering exclude keyword */
6994 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6995 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6996 LOGW("skipping [%s] by exculde keyword [%s]",
6997 factory_name, player->ini.exclude_element_keyword[idx]);
6999 result = GST_AUTOPLUG_SELECT_SKIP;
7004 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7005 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7006 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7007 factory_name, player->ini.unsupported_codec_keyword[idx]);
7008 result = GST_AUTOPLUG_SELECT_SKIP;
7013 /* exclude webm format */
7014 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7015 * because webm format is not supportable.
7016 * If webm is disabled in "autoplug-continue", there is no state change
7017 * failure or error because the decodebin will expose the pad directly.
7018 * It make MSL invoke _prepare_async_callback.
7019 * So, we need to disable webm format in "autoplug-select" */
7020 if (caps_str && strstr(caps_str, "webm")) {
7021 LOGW("webm is not supported");
7022 result = GST_AUTOPLUG_SELECT_SKIP;
7026 /* check factory class for filtering */
7027 /* NOTE : msl don't need to use image plugins.
7028 * So, those plugins should be skipped for error handling.
7030 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7031 LOGD("skipping [%s] by not required", factory_name);
7032 result = GST_AUTOPLUG_SELECT_SKIP;
7036 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7037 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7038 // TO CHECK : subtitle if needed, add subparse exception.
7039 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7040 result = GST_AUTOPLUG_SELECT_SKIP;
7044 if (g_strrstr(factory_name, "mpegpsdemux")) {
7045 LOGD("skipping PS container - not support");
7046 result = GST_AUTOPLUG_SELECT_SKIP;
7050 if (g_strrstr(factory_name, "mssdemux"))
7051 player->smooth_streaming = TRUE;
7053 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7054 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7057 GstStructure *str = NULL;
7058 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7060 /* don't make video because of not required */
7061 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7062 (!player->set_mode.media_packet_video_stream)) {
7063 LOGD("no need video decoding, expose pad");
7064 result = GST_AUTOPLUG_SELECT_EXPOSE;
7068 /* get w/h for omx state-tune */
7069 /* FIXME: deprecated? */
7070 str = gst_caps_get_structure(caps, 0);
7071 gst_structure_get_int(str, "width", &width);
7074 if (player->v_stream_caps) {
7075 gst_caps_unref(player->v_stream_caps);
7076 player->v_stream_caps = NULL;
7079 player->v_stream_caps = gst_caps_copy(caps);
7080 LOGD("take caps for video state tune");
7081 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7085 if (g_strrstr(klass, "Codec/Decoder")) {
7086 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7087 if (result != GST_AUTOPLUG_SELECT_TRY) {
7088 LOGW("skip add decoder");
7094 MMPLAYER_FREEIF(caps_str);
7100 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7103 //mm_player_t *player = (mm_player_t *)data;
7104 GstCaps *caps = NULL;
7106 LOGD("[Decodebin2] pad-removed signal");
7108 caps = gst_pad_query_caps(new_pad, NULL);
7110 LOGW("query caps is NULL");
7114 gchar *caps_str = NULL;
7115 caps_str = gst_caps_to_string(caps);
7117 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7119 MMPLAYER_FREEIF(caps_str);
7120 gst_caps_unref(caps);
7124 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7126 mm_player_t *player = (mm_player_t *)data;
7127 GstIterator *iter = NULL;
7128 GValue item = { 0, };
7130 gboolean done = FALSE;
7131 gboolean is_all_drained = TRUE;
7134 MMPLAYER_RETURN_IF_FAIL(player);
7136 LOGD("__mmplayer_gst_decode_drained");
7138 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7139 LOGW("Fail to get cmd lock");
7143 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7144 !__mmplayer_verify_gapless_play_path(player)) {
7145 LOGD("decoding is finished.");
7146 __mmplayer_reset_gapless_state(player);
7147 MMPLAYER_CMD_UNLOCK(player);
7151 player->gapless.reconfigure = TRUE;
7153 /* check decodebin src pads whether they received EOS or not */
7154 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7157 switch (gst_iterator_next(iter, &item)) {
7158 case GST_ITERATOR_OK:
7159 pad = g_value_get_object(&item);
7160 if (pad && !GST_PAD_IS_EOS(pad)) {
7161 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7162 is_all_drained = FALSE;
7165 g_value_reset(&item);
7167 case GST_ITERATOR_RESYNC:
7168 gst_iterator_resync(iter);
7170 case GST_ITERATOR_ERROR:
7171 case GST_ITERATOR_DONE:
7176 g_value_unset(&item);
7177 gst_iterator_free(iter);
7179 if (!is_all_drained) {
7180 LOGD("Wait util the all pads get EOS.");
7181 MMPLAYER_CMD_UNLOCK(player);
7186 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7187 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7189 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7190 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7191 __mmplayer_deactivate_old_path(player);
7192 MMPLAYER_CMD_UNLOCK(player);
7198 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7200 mm_player_t *player = (mm_player_t *)data;
7201 const gchar *klass = NULL;
7202 gchar *factory_name = NULL;
7204 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7205 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7207 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7209 if (__mmplayer_add_dump_buffer_probe(player, element))
7210 LOGD("add buffer probe");
7213 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7214 gchar *selected = NULL;
7215 selected = g_strdup(GST_ELEMENT_NAME(element));
7216 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7220 if (g_strrstr(klass, "Parser")) {
7221 gchar *selected = NULL;
7223 selected = g_strdup(factory_name);
7224 player->parsers = g_list_append(player->parsers, selected);
7227 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7228 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7229 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7231 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7232 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7234 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7235 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7236 "max-video-width", player->adaptive_info.limit.width,
7237 "max-video-height", player->adaptive_info.limit.height, NULL);
7239 } else if (g_strrstr(klass, "Demuxer")) {
7240 //LOGD("plugged element is demuxer. take it");
7241 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7242 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7245 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7246 int surface_type = 0;
7248 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7251 // to support trust-zone only
7252 if (g_strrstr(factory_name, "asfdemux")) {
7253 LOGD("set file-location %s", player->profile.uri);
7254 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7255 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7256 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7257 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7258 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7259 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7260 (__mmplayer_is_only_mp3_type(player->type))) {
7261 LOGD("[mpegaudioparse] set streaming pull mode.");
7262 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7264 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7265 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7268 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7269 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7270 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7272 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7273 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7275 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7276 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7277 (MMPLAYER_IS_DASH_STREAMING(player))) {
7278 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7279 __mm_player_streaming_set_multiqueue(player->streamer, element);
7280 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7289 __mmplayer_release_misc(mm_player_t *player)
7292 bool cur_mode = player->set_mode.rich_audio;
7295 MMPLAYER_RETURN_IF_FAIL(player);
7297 player->video_stream_cb = NULL;
7298 player->video_stream_cb_user_param = NULL;
7299 player->video_stream_prerolled = false;
7301 player->audio_stream_render_cb = NULL;
7302 player->audio_stream_cb_user_param = NULL;
7303 player->audio_stream_sink_sync = false;
7305 player->video_stream_changed_cb = NULL;
7306 player->video_stream_changed_cb_user_param = NULL;
7308 player->audio_stream_changed_cb = NULL;
7309 player->audio_stream_changed_cb_user_param = NULL;
7311 player->sent_bos = FALSE;
7312 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7314 player->seek_state = MMPLAYER_SEEK_NONE;
7316 player->total_bitrate = 0;
7317 player->total_maximum_bitrate = 0;
7319 player->not_found_demuxer = 0;
7321 player->last_position = 0;
7322 player->duration = 0;
7323 player->http_content_size = 0;
7324 player->not_supported_codec = MISSING_PLUGIN_NONE;
7325 player->can_support_codec = FOUND_PLUGIN_NONE;
7326 player->pending_seek.is_pending = false;
7327 player->pending_seek.pos = 0;
7328 player->msg_posted = FALSE;
7329 player->has_many_types = FALSE;
7330 player->is_subtitle_force_drop = FALSE;
7331 player->play_subtitle = FALSE;
7332 player->adjust_subtitle_pos = 0;
7333 player->last_multiwin_status = FALSE;
7334 player->has_closed_caption = FALSE;
7335 player->set_mode.media_packet_video_stream = false;
7336 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7337 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7339 player->set_mode.rich_audio = cur_mode;
7341 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7342 player->bitrate[i] = 0;
7343 player->maximum_bitrate[i] = 0;
7346 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7348 /* remove media stream cb(appsrc cb) */
7349 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7350 player->media_stream_buffer_status_cb[i] = NULL;
7351 player->media_stream_seek_data_cb[i] = NULL;
7352 player->buffer_cb_user_param[i] = NULL;
7353 player->seek_cb_user_param[i] = NULL;
7355 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7357 /* free memory related to audio effect */
7358 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7360 if (player->adaptive_info.var_list) {
7361 g_list_free_full(player->adaptive_info.var_list, g_free);
7362 player->adaptive_info.var_list = NULL;
7365 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7366 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7367 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7369 /* Reset video360 settings to their defaults in case if the pipeline is to be
7372 player->video360_metadata.is_spherical = -1;
7373 player->is_openal_plugin_used = FALSE;
7375 player->is_content_spherical = FALSE;
7376 player->is_video360_enabled = TRUE;
7377 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7378 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7379 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7380 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7381 player->video360_zoom = 1.0f;
7382 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7383 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7385 player->sound.rg_enable = false;
7387 __mmplayer_initialize_video_roi(player);
7392 __mmplayer_release_misc_post(mm_player_t *player)
7394 char *original_uri = NULL;
7397 /* player->pipeline is already released before. */
7399 MMPLAYER_RETURN_IF_FAIL(player);
7401 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7403 /* clean found parsers */
7404 if (player->parsers) {
7405 GList *parsers = player->parsers;
7406 for (; parsers; parsers = g_list_next(parsers)) {
7407 gchar *name = parsers->data;
7408 MMPLAYER_FREEIF(name);
7410 g_list_free(player->parsers);
7411 player->parsers = NULL;
7414 /* clean found audio decoders */
7415 if (player->audio_decoders) {
7416 GList *a_dec = player->audio_decoders;
7417 for (; a_dec; a_dec = g_list_next(a_dec)) {
7418 gchar *name = a_dec->data;
7419 MMPLAYER_FREEIF(name);
7421 g_list_free(player->audio_decoders);
7422 player->audio_decoders = NULL;
7425 /* clean the uri list except original uri */
7426 if (player->uri_info.uri_list) {
7427 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7429 if (player->attrs) {
7430 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7431 LOGD("restore original uri = %s", original_uri);
7433 if (mm_attrs_commit_all(player->attrs))
7434 LOGE("failed to commit the original uri.");
7437 GList *uri_list = player->uri_info.uri_list;
7438 for (; uri_list; uri_list = g_list_next(uri_list)) {
7439 gchar *uri = uri_list->data;
7440 MMPLAYER_FREEIF(uri);
7442 g_list_free(player->uri_info.uri_list);
7443 player->uri_info.uri_list = NULL;
7446 /* clear the audio stream buffer list */
7447 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7449 /* clear the video stream bo list */
7450 __mmplayer_video_stream_destroy_bo_list(player);
7451 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7453 if (player->profile.input_mem.buf) {
7454 free(player->profile.input_mem.buf);
7455 player->profile.input_mem.buf = NULL;
7457 player->profile.input_mem.len = 0;
7458 player->profile.input_mem.offset = 0;
7460 player->uri_info.uri_idx = 0;
7465 __mmplayer_check_subtitle(mm_player_t *player)
7467 MMHandleType attrs = 0;
7468 char *subtitle_uri = NULL;
7472 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7474 /* get subtitle attribute */
7475 attrs = MMPLAYER_GET_ATTRS(player);
7479 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7480 if (!subtitle_uri || !strlen(subtitle_uri))
7483 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7484 player->is_external_subtitle_present = TRUE;
7492 __mmplayer_cancel_eos_timer(mm_player_t *player)
7494 MMPLAYER_RETURN_IF_FAIL(player);
7496 if (player->eos_timer) {
7497 LOGD("cancel eos timer");
7498 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7499 player->eos_timer = 0;
7506 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7510 MMPLAYER_RETURN_IF_FAIL(player);
7511 MMPLAYER_RETURN_IF_FAIL(sink);
7513 player->sink_elements = g_list_append(player->sink_elements, sink);
7519 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7523 MMPLAYER_RETURN_IF_FAIL(player);
7524 MMPLAYER_RETURN_IF_FAIL(sink);
7526 player->sink_elements = g_list_remove(player->sink_elements, sink);
7532 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7533 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7535 MMPlayerSignalItem *item = NULL;
7538 MMPLAYER_RETURN_IF_FAIL(player);
7540 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7541 LOGE("invalid signal type [%d]", type);
7545 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7547 LOGE("cannot connect signal [%s]", signal);
7552 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7553 player->signals[type] = g_list_append(player->signals[type], item);
7559 /* NOTE : be careful with calling this api. please refer to below glib comment
7560 * glib comment : Note that there is a bug in GObject that makes this function much
7561 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7562 * will no longer be called, but, the signal handler is not currently disconnected.
7563 * If the instance is itself being freed at the same time than this doesn't matter,
7564 * since the signal will automatically be removed, but if instance persists,
7565 * then the signal handler will leak. You should not remove the signal yourself
7566 * because in a future versions of GObject, the handler will automatically be
7569 * It's possible to work around this problem in a way that will continue to work
7570 * with future versions of GObject by checking that the signal handler is still
7571 * connected before disconnected it:
7573 * if (g_signal_handler_is_connected(instance, id))
7574 * g_signal_handler_disconnect(instance, id);
7577 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7579 GList *sig_list = NULL;
7580 MMPlayerSignalItem *item = NULL;
7584 MMPLAYER_RETURN_IF_FAIL(player);
7586 LOGD("release signals type : %d", type);
7588 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7589 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7590 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7591 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7592 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7593 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7597 sig_list = player->signals[type];
7599 for (; sig_list; sig_list = sig_list->next) {
7600 item = sig_list->data;
7602 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7603 if (g_signal_handler_is_connected(item->obj, item->sig))
7604 g_signal_handler_disconnect(item->obj, item->sig);
7607 MMPLAYER_FREEIF(item);
7610 g_list_free(player->signals[type]);
7611 player->signals[type] = NULL;
7619 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7621 mm_player_t *player = 0;
7622 int prev_display_surface_type = 0;
7623 void *prev_display_overlay = NULL;
7627 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7628 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7630 player = MM_PLAYER_CAST(handle);
7632 /* check video sinkbin is created */
7633 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7634 LOGE("Videosink is already created");
7635 return MM_ERROR_NONE;
7638 LOGD("videosink element is not yet ready");
7640 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7641 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7643 return MM_ERROR_INVALID_ARGUMENT;
7646 /* load previous attributes */
7647 if (player->attrs) {
7648 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7649 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7650 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7651 if (prev_display_surface_type == surface_type) {
7652 LOGD("incoming display surface type is same as previous one, do nothing..");
7654 return MM_ERROR_NONE;
7657 LOGE("failed to load attributes");
7659 return MM_ERROR_PLAYER_INTERNAL;
7662 /* videobin is not created yet, so we just set attributes related to display surface */
7663 LOGD("store display attribute for given surface type(%d)", surface_type);
7664 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7665 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7666 if (mm_attrs_commit_all(player->attrs)) {
7667 LOGE("failed to commit attribute");
7669 return MM_ERROR_PLAYER_INTERNAL;
7673 return MM_ERROR_NONE;
7676 /* Note : if silent is true, then subtitle would not be displayed. :*/
7678 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7680 mm_player_t *player = (mm_player_t *)hplayer;
7684 /* check player handle */
7685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7687 player->set_mode.subtitle_off = silent;
7689 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7693 return MM_ERROR_NONE;
7697 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7699 MMPlayerGstElement *mainbin = NULL;
7700 MMPlayerGstElement *textbin = NULL;
7701 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7702 GstState current_state = GST_STATE_VOID_PENDING;
7703 GstState element_state = GST_STATE_VOID_PENDING;
7704 GstState element_pending_state = GST_STATE_VOID_PENDING;
7706 GstEvent *event = NULL;
7707 int result = MM_ERROR_NONE;
7709 GstClock *curr_clock = NULL;
7710 GstClockTime base_time, start_time, curr_time;
7715 /* check player handle */
7716 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7718 player->pipeline->mainbin &&
7719 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7721 mainbin = player->pipeline->mainbin;
7722 textbin = player->pipeline->textbin;
7724 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7726 // sync clock with current pipeline
7727 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7728 curr_time = gst_clock_get_time(curr_clock);
7730 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7731 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7733 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7734 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7736 if (current_state > GST_STATE_READY) {
7737 // sync state with current pipeline
7738 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7739 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7740 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7742 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7743 if (GST_STATE_CHANGE_FAILURE == ret) {
7744 LOGE("fail to state change.");
7745 result = MM_ERROR_PLAYER_INTERNAL;
7749 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7750 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7753 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7754 gst_object_unref(curr_clock);
7757 // seek to current position
7758 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7759 result = MM_ERROR_PLAYER_INVALID_STATE;
7760 LOGE("gst_element_query_position failed, invalid state");
7764 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7765 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);
7767 __mmplayer_gst_send_event_to_sink(player, event);
7769 result = MM_ERROR_PLAYER_INTERNAL;
7770 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7774 /* sync state with current pipeline */
7775 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7776 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7777 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7779 return MM_ERROR_NONE;
7782 /* release text pipeline resource */
7783 player->textsink_linked = 0;
7785 /* release signal */
7786 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7788 /* release textbin with it's childs */
7789 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7790 MMPLAYER_FREEIF(player->pipeline->textbin);
7791 player->pipeline->textbin = NULL;
7793 /* release subtitle elem */
7794 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7795 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7801 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7803 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7804 GstState current_state = GST_STATE_VOID_PENDING;
7806 MMHandleType attrs = 0;
7807 MMPlayerGstElement *mainbin = NULL;
7808 MMPlayerGstElement *textbin = NULL;
7810 gchar *subtitle_uri = NULL;
7811 int result = MM_ERROR_NONE;
7812 const gchar *charset = NULL;
7816 /* check player handle */
7817 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7819 player->pipeline->mainbin &&
7820 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7821 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7823 mainbin = player->pipeline->mainbin;
7824 textbin = player->pipeline->textbin;
7826 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7827 if (current_state < GST_STATE_READY) {
7828 result = MM_ERROR_PLAYER_INVALID_STATE;
7829 LOGE("Pipeline is not in proper state");
7833 attrs = MMPLAYER_GET_ATTRS(player);
7835 LOGE("cannot get content attribute");
7836 result = MM_ERROR_PLAYER_INTERNAL;
7840 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7841 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7842 LOGE("subtitle uri is not proper filepath");
7843 result = MM_ERROR_PLAYER_INVALID_URI;
7847 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7848 LOGE("failed to get storage info of subtitle path");
7849 result = MM_ERROR_PLAYER_INVALID_URI;
7853 LOGD("old subtitle file path is [%s]", subtitle_uri);
7854 LOGD("new subtitle file path is [%s]", filepath);
7856 if (!strcmp(filepath, subtitle_uri)) {
7857 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7860 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7861 if (mm_attrs_commit_all(player->attrs)) {
7862 LOGE("failed to commit.");
7867 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7868 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7869 player->subtitle_language_list = NULL;
7870 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7872 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7873 if (ret != GST_STATE_CHANGE_SUCCESS) {
7874 LOGE("failed to change state of textbin to READY");
7875 result = MM_ERROR_PLAYER_INTERNAL;
7879 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7880 if (ret != GST_STATE_CHANGE_SUCCESS) {
7881 LOGE("failed to change state of subparse to READY");
7882 result = MM_ERROR_PLAYER_INTERNAL;
7886 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7887 if (ret != GST_STATE_CHANGE_SUCCESS) {
7888 LOGE("failed to change state of filesrc to READY");
7889 result = MM_ERROR_PLAYER_INTERNAL;
7893 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7895 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7897 charset = util_get_charset(filepath);
7899 LOGD("detected charset is %s", charset);
7900 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7903 result = _mmplayer_sync_subtitle_pipeline(player);
7910 /* API to switch between external subtitles */
7912 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7914 int result = MM_ERROR_NONE;
7915 mm_player_t *player = (mm_player_t *)hplayer;
7920 /* check player handle */
7921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7923 /* filepath can be null in idle state */
7925 /* check file path */
7926 if ((path = strstr(filepath, "file://")))
7927 result = util_exist_file_path(path + 7);
7929 result = util_exist_file_path(filepath);
7931 if (result != MM_ERROR_NONE) {
7932 LOGE("invalid subtitle path 0x%X", result);
7933 return result; /* file not found or permission denied */
7937 if (!player->pipeline) {
7939 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7940 if (mm_attrs_commit_all(player->attrs)) {
7941 LOGE("failed to commit"); /* subtitle path will not be created */
7942 return MM_ERROR_PLAYER_INTERNAL;
7945 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7946 /* check filepath */
7947 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7949 if (!__mmplayer_check_subtitle(player)) {
7950 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7951 if (mm_attrs_commit_all(player->attrs)) {
7952 LOGE("failed to commit");
7953 return MM_ERROR_PLAYER_INTERNAL;
7956 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7957 LOGE("fail to create text pipeline");
7958 return MM_ERROR_PLAYER_INTERNAL;
7961 result = _mmplayer_sync_subtitle_pipeline(player);
7963 result = __mmplayer_change_external_subtitle_language(player, filepath);
7966 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7967 player->is_external_subtitle_added_now = TRUE;
7969 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7970 if (!player->subtitle_language_list) {
7971 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7972 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7973 LOGW("subtitle language list is not updated yet");
7975 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7983 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7985 int result = MM_ERROR_NONE;
7986 gchar *change_pad_name = NULL;
7987 GstPad *sinkpad = NULL;
7988 MMPlayerGstElement *mainbin = NULL;
7989 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7990 GstCaps *caps = NULL;
7991 gint total_track_num = 0;
7995 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7996 MM_ERROR_PLAYER_NOT_INITIALIZED);
7998 LOGD("Change Track(%d) to %d", type, index);
8000 mainbin = player->pipeline->mainbin;
8002 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8003 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8004 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8005 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8007 /* Changing Video Track is not supported. */
8008 LOGE("Track Type Error");
8012 if (mainbin[elem_idx].gst == NULL) {
8013 result = MM_ERROR_PLAYER_NO_OP;
8014 LOGD("Req track doesn't exist");
8018 total_track_num = player->selector[type].total_track_num;
8019 if (total_track_num <= 0) {
8020 result = MM_ERROR_PLAYER_NO_OP;
8021 LOGD("Language list is not available");
8025 if ((index < 0) || (index >= total_track_num)) {
8026 result = MM_ERROR_INVALID_ARGUMENT;
8027 LOGD("Not a proper index : %d", index);
8031 /*To get the new pad from the selector*/
8032 change_pad_name = g_strdup_printf("sink_%u", index);
8033 if (change_pad_name == NULL) {
8034 result = MM_ERROR_PLAYER_INTERNAL;
8035 LOGD("Pad does not exists");
8039 LOGD("new active pad name: %s", change_pad_name);
8041 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8042 if (sinkpad == NULL) {
8043 LOGD("sinkpad is NULL");
8044 result = MM_ERROR_PLAYER_INTERNAL;
8048 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8049 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8051 caps = gst_pad_get_current_caps(sinkpad);
8052 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8055 gst_object_unref(sinkpad);
8057 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8058 __mmplayer_set_audio_attrs(player, caps);
8061 MMPLAYER_FREEIF(change_pad_name);
8066 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8068 int result = MM_ERROR_NONE;
8069 mm_player_t *player = NULL;
8070 MMPlayerGstElement *mainbin = NULL;
8072 gint current_active_index = 0;
8074 GstState current_state = GST_STATE_VOID_PENDING;
8075 GstEvent *event = NULL;
8080 player = (mm_player_t *)hplayer;
8081 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8083 if (!player->pipeline) {
8084 LOGE("Track %d pre setting -> %d", type, index);
8086 player->selector[type].active_pad_index = index;
8090 mainbin = player->pipeline->mainbin;
8092 current_active_index = player->selector[type].active_pad_index;
8094 /*If index is same as running index no need to change the pad*/
8095 if (current_active_index == index)
8098 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8099 result = MM_ERROR_PLAYER_INVALID_STATE;
8103 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8104 if (current_state < GST_STATE_PAUSED) {
8105 result = MM_ERROR_PLAYER_INVALID_STATE;
8106 LOGW("Pipeline not in porper state");
8110 result = __mmplayer_change_selector_pad(player, type, index);
8111 if (result != MM_ERROR_NONE) {
8112 LOGE("change selector pad error");
8116 player->selector[type].active_pad_index = index;
8118 if (current_state == GST_STATE_PLAYING) {
8119 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8120 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8121 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8123 __mmplayer_gst_send_event_to_sink(player, event);
8125 result = MM_ERROR_PLAYER_INTERNAL;
8135 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8137 mm_player_t *player = (mm_player_t *)hplayer;
8141 /* check player handle */
8142 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8144 *silent = player->set_mode.subtitle_off;
8146 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8150 return MM_ERROR_NONE;
8154 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8156 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8157 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8159 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8160 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8164 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8165 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8166 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8167 mm_player_dump_t *dump_s;
8168 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8169 if (dump_s == NULL) {
8170 LOGE("malloc fail");
8174 dump_s->dump_element_file = NULL;
8175 dump_s->dump_pad = NULL;
8176 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8178 if (dump_s->dump_pad) {
8179 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8180 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]);
8181 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8182 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);
8183 /* add list for removed buffer probe and close FILE */
8184 player->dump_list = g_list_append(player->dump_list, dump_s);
8185 LOGD("%s sink pad added buffer probe for dump", factory_name);
8188 MMPLAYER_FREEIF(dump_s);
8189 LOGE("failed to get %s sink pad added", factory_name);
8196 static GstPadProbeReturn
8197 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8199 FILE *dump_data = (FILE *)u_data;
8201 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8202 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8204 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8206 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8208 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8210 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8212 return GST_PAD_PROBE_OK;
8216 __mmplayer_release_dump_list(GList *dump_list)
8218 GList *d_list = dump_list;
8223 for (; d_list; d_list = g_list_next(d_list)) {
8224 mm_player_dump_t *dump_s = d_list->data;
8225 if (dump_s->dump_pad) {
8226 if (dump_s->probe_handle_id)
8227 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8228 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8230 if (dump_s->dump_element_file) {
8231 fclose(dump_s->dump_element_file);
8232 dump_s->dump_element_file = NULL;
8234 MMPLAYER_FREEIF(dump_s);
8236 g_list_free(dump_list);
8241 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8243 mm_player_t *player = (mm_player_t *)hplayer;
8247 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8248 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8250 *exist = (bool)player->has_closed_caption;
8254 return MM_ERROR_NONE;
8258 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8262 // LOGD("unref internal gst buffer %p", buffer);
8263 gst_buffer_unref((GstBuffer *)buffer);
8270 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8272 mm_player_t *player = (mm_player_t *)hplayer;
8276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8277 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8279 if (MMPLAYER_IS_STREAMING(player))
8280 *timeout = (int)player->ini.live_state_change_timeout;
8282 *timeout = (int)player->ini.localplayback_state_change_timeout;
8284 LOGD("timeout = %d", *timeout);
8287 return MM_ERROR_NONE;
8291 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8293 mm_player_t *player = (mm_player_t *)hplayer;
8297 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8298 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8300 *num = player->video_num_buffers;
8301 *extra_num = player->video_extra_num_buffers;
8303 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8306 return MM_ERROR_NONE;
8310 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8314 MMPLAYER_RETURN_IF_FAIL(player);
8316 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8318 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8319 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8320 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8321 player->storage_info[i].id = -1;
8322 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8324 if (path_type != MMPLAYER_PATH_MAX)
8333 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8335 int ret = MM_ERROR_NONE;
8336 mm_player_t *player = (mm_player_t *)hplayer;
8337 MMMessageParamType msg_param = {0, };
8340 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8342 LOGW("state changed storage %d:%d", id, state);
8344 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8345 return MM_ERROR_NONE;
8347 /* FIXME: text path should be handled seperately. */
8348 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8349 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8350 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8351 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8352 LOGW("external storage is removed");
8354 if (player->msg_posted == FALSE) {
8355 memset(&msg_param, 0, sizeof(MMMessageParamType));
8356 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8357 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8358 player->msg_posted = TRUE;
8361 /* unrealize the player */
8362 ret = _mmplayer_unrealize(hplayer);
8363 if (ret != MM_ERROR_NONE)
8364 LOGE("failed to unrealize");
8372 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8374 int ret = MM_ERROR_NONE;
8375 mm_player_t *player = (mm_player_t *)hplayer;
8376 int idx = 0, total = 0;
8377 gchar *result = NULL, *tmp = NULL;
8380 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8381 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8383 total = *num = g_list_length(player->adaptive_info.var_list);
8385 LOGW("There is no stream variant info.");
8389 result = g_strdup("");
8390 for (idx = 0 ; idx < total ; idx++) {
8391 VariantData *v_data = NULL;
8392 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8395 gchar data[64] = {0};
8396 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8398 tmp = g_strconcat(result, data, NULL);
8402 LOGW("There is no variant data in %d", idx);
8407 *var_info = (char *)result;
8409 LOGD("variant info %d:%s", *num, *var_info);
8415 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8417 int ret = MM_ERROR_NONE;
8418 mm_player_t *player = (mm_player_t *)hplayer;
8421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8423 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8425 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8426 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8427 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8429 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8430 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8431 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8432 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8434 /* FIXME: seek to current position for applying new variant limitation */
8443 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8445 int ret = MM_ERROR_NONE;
8446 mm_player_t *player = (mm_player_t *)hplayer;
8449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8450 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8452 *bandwidth = player->adaptive_info.limit.bandwidth;
8453 *width = player->adaptive_info.limit.width;
8454 *height = player->adaptive_info.limit.height;
8456 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8463 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8465 int ret = MM_ERROR_NONE;
8466 mm_player_t *player = (mm_player_t *)hplayer;
8469 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8470 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8471 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8473 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8475 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8476 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8477 else /* live case */
8478 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8480 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8487 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8489 #define IDX_FIRST_SW_CODEC 0
8490 mm_player_t *player = (mm_player_t *)hplayer;
8491 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8492 MMHandleType attrs = 0;
8495 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8497 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8498 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8499 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8501 switch (stream_type) {
8502 case MM_PLAYER_STREAM_TYPE_AUDIO:
8503 /* to support audio codec selection, codec info have to be added in ini file as below.
8504 audio codec element hw = xxxx
8505 audio codec element sw = avdec */
8506 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8507 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8508 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8509 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8510 LOGE("There is no audio codec info for codec_type %d", codec_type);
8511 return MM_ERROR_PLAYER_NO_OP;
8514 case MM_PLAYER_STREAM_TYPE_VIDEO:
8515 /* to support video codec selection, codec info have to be added in ini file as below.
8516 video codec element hw = omx
8517 video codec element sw = avdec */
8518 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8519 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8520 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8521 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8522 LOGE("There is no video codec info for codec_type %d", codec_type);
8523 return MM_ERROR_PLAYER_NO_OP;
8527 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8528 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8532 LOGD("update %s codec_type to %d", attr_name, codec_type);
8534 attrs = MMPLAYER_GET_ATTRS(player);
8535 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8537 if (mm_attrs_commit_all(player->attrs)) {
8538 LOGE("failed to commit codec_type attributes");
8539 return MM_ERROR_PLAYER_INTERNAL;
8543 return MM_ERROR_NONE;
8547 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8549 mm_player_t *player = (mm_player_t *)hplayer;
8550 GstElement *rg_vol_element = NULL;
8554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556 player->sound.rg_enable = enabled;
8558 /* just hold rgvolume enable value if pipeline is not ready */
8559 if (!player->pipeline || !player->pipeline->audiobin) {
8560 LOGD("pipeline is not ready. holding rgvolume enable value");
8561 return MM_ERROR_NONE;
8564 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8566 if (!rg_vol_element) {
8567 LOGD("rgvolume element is not created");
8568 return MM_ERROR_PLAYER_INTERNAL;
8572 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8574 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8578 return MM_ERROR_NONE;
8582 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8584 mm_player_t *player = (mm_player_t *)hplayer;
8585 GstElement *rg_vol_element = NULL;
8586 gboolean enable = FALSE;
8590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8591 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8593 /* just hold enable_rg value if pipeline is not ready */
8594 if (!player->pipeline || !player->pipeline->audiobin) {
8595 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8596 *enabled = player->sound.rg_enable;
8597 return MM_ERROR_NONE;
8600 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8602 if (!rg_vol_element) {
8603 LOGD("rgvolume element is not created");
8604 return MM_ERROR_PLAYER_INTERNAL;
8607 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8608 *enabled = (bool)enable;
8612 return MM_ERROR_NONE;
8616 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8618 mm_player_t *player = (mm_player_t *)hplayer;
8619 MMHandleType attrs = 0;
8620 void *handle = NULL;
8621 int ret = MM_ERROR_NONE;
8625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8627 attrs = MMPLAYER_GET_ATTRS(player);
8628 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8630 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8632 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8633 return MM_ERROR_PLAYER_INTERNAL;
8636 player->video_roi.scale_x = scale_x;
8637 player->video_roi.scale_y = scale_y;
8638 player->video_roi.scale_width = scale_width;
8639 player->video_roi.scale_height = scale_height;
8641 /* check video sinkbin is created */
8642 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8643 return MM_ERROR_NONE;
8645 if (!gst_video_overlay_set_video_roi_area(
8646 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8647 scale_x, scale_y, scale_width, scale_height))
8648 ret = MM_ERROR_PLAYER_INTERNAL;
8650 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8651 scale_x, scale_y, scale_width, scale_height);
8659 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8661 mm_player_t *player = (mm_player_t *)hplayer;
8662 int ret = MM_ERROR_NONE;
8666 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8667 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8669 *scale_x = player->video_roi.scale_x;
8670 *scale_y = player->video_roi.scale_y;
8671 *scale_width = player->video_roi.scale_width;
8672 *scale_height = player->video_roi.scale_height;
8674 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8675 *scale_x, *scale_y, *scale_width, *scale_height);
8681 __mmplayer_update_duration_value(mm_player_t *player)
8683 gboolean ret = FALSE;
8684 gint64 dur_nsec = 0;
8685 LOGD("try to update duration");
8687 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8688 player->duration = dur_nsec;
8689 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8693 if (player->duration < 0) {
8694 LOGW("duration is Non-Initialized !!!");
8695 player->duration = 0;
8698 /* update streaming service type */
8699 player->streaming_type = __mmplayer_get_stream_service_type(player);
8701 /* check duration is OK */
8702 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8703 /* FIXIT : find another way to get duration here. */
8704 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8710 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8712 /* update audio params
8713 NOTE : We need original audio params and it can be only obtained from src pad of audio
8714 decoder. Below code only valid when we are not using 'resampler' just before
8715 'audioconverter'. */
8716 GstCaps *caps_a = NULL;
8718 gint samplerate = 0, channels = 0;
8719 GstStructure *p = NULL;
8721 LOGD("try to update audio attrs");
8723 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8724 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8726 pad = gst_element_get_static_pad(
8727 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8730 LOGW("failed to get pad from audiosink");
8734 caps_a = gst_pad_get_current_caps(pad);
8736 LOGW("not ready to get audio caps");
8737 gst_object_unref(pad);
8741 p = gst_caps_get_structure(caps_a, 0);
8743 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8745 gst_structure_get_int(p, "rate", &samplerate);
8746 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8748 gst_structure_get_int(p, "channels", &channels);
8749 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8751 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8753 gst_caps_unref(caps_a);
8754 gst_object_unref(pad);
8760 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8762 LOGD("try to update video attrs");
8764 GstCaps *caps_v = NULL;
8768 GstStructure *p = NULL;
8770 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8771 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8773 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8775 LOGD("no videosink sink pad");
8779 caps_v = gst_pad_get_current_caps(pad);
8780 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8781 if (!caps_v && player->v_stream_caps) {
8782 caps_v = player->v_stream_caps;
8783 gst_caps_ref(caps_v);
8787 LOGD("no negitiated caps from videosink");
8788 gst_object_unref(pad);
8792 p = gst_caps_get_structure(caps_v, 0);
8793 gst_structure_get_int(p, "width", &width);
8794 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8796 gst_structure_get_int(p, "height", &height);
8797 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8799 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8801 SECURE_LOGD("width : %d height : %d", width, height);
8803 gst_caps_unref(caps_v);
8804 gst_object_unref(pad);
8807 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8808 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8815 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8817 gboolean ret = FALSE;
8818 guint64 data_size = 0;
8822 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8823 if (!player->duration)
8826 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8827 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8828 if (stat(path, &sb) == 0)
8829 data_size = (guint64)sb.st_size;
8831 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8832 data_size = player->http_content_size;
8835 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8838 guint64 bitrate = 0;
8839 guint64 msec_dur = 0;
8841 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8843 bitrate = data_size * 8 * 1000 / msec_dur;
8844 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8845 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8849 LOGD("player duration is less than 0");
8853 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8854 if (player->total_bitrate) {
8855 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8864 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8866 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8867 data->uri_type = uri_type;
8871 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8873 int ret = MM_ERROR_PLAYER_INVALID_URI;
8875 char *buffer = NULL;
8876 char *seperator = strchr(path, ',');
8877 char ext[100] = {0,}, size[100] = {0,};
8880 if ((buffer = strstr(path, "ext="))) {
8881 buffer += strlen("ext=");
8883 if (strlen(buffer)) {
8884 strncpy(ext, buffer, 99);
8886 if ((seperator = strchr(ext, ','))
8887 || (seperator = strchr(ext, ' '))
8888 || (seperator = strchr(ext, '\0'))) {
8889 seperator[0] = '\0';
8894 if ((buffer = strstr(path, "size="))) {
8895 buffer += strlen("size=");
8897 if (strlen(buffer) > 0) {
8898 strncpy(size, buffer, 99);
8900 if ((seperator = strchr(size, ','))
8901 || (seperator = strchr(size, ' '))
8902 || (seperator = strchr(size, '\0'))) {
8903 seperator[0] = '\0';
8906 mem_size = atoi(size);
8911 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8913 if (mem_size && param) {
8914 if (data->input_mem.buf)
8915 free(data->input_mem.buf);
8916 data->input_mem.buf = malloc(mem_size);
8918 if (data->input_mem.buf) {
8919 memcpy(data->input_mem.buf, param, mem_size);
8920 data->input_mem.len = mem_size;
8921 ret = MM_ERROR_NONE;
8923 LOGE("failed to alloc mem %d", mem_size);
8924 ret = MM_ERROR_PLAYER_INTERNAL;
8927 data->input_mem.offset = 0;
8928 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8935 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8937 gchar *location = NULL;
8940 int ret = MM_ERROR_NONE;
8942 if ((path = strstr(uri, "file://"))) {
8943 location = g_filename_from_uri(uri, NULL, &err);
8944 if (!location || (err != NULL)) {
8945 LOGE("Invalid URI '%s' for filesrc: %s", path,
8946 (err != NULL) ? err->message : "unknown error");
8950 MMPLAYER_FREEIF(location);
8952 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8953 return MM_ERROR_PLAYER_INVALID_URI;
8955 LOGD("path from uri: %s", location);
8958 path = (location != NULL) ? (location) : ((char *)uri);
8961 ret = util_exist_file_path(path);
8963 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8964 if (ret == MM_ERROR_NONE) {
8965 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8966 if (util_is_sdp_file(path)) {
8967 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8968 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8970 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8972 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8973 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8975 LOGE("invalid uri, could not play..");
8976 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8979 MMPLAYER_FREEIF(location);
8984 static MMPlayerVideoStreamDataType *
8985 __mmplayer_create_stream_from_pad(GstPad *pad)
8987 GstCaps *caps = NULL;
8988 GstStructure *structure = NULL;
8989 unsigned int fourcc = 0;
8990 const gchar *string_format = NULL;
8991 MMPlayerVideoStreamDataType *stream = NULL;
8993 MMPixelFormatType format;
8995 caps = gst_pad_get_current_caps(pad);
8997 LOGE("Caps is NULL.");
9001 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9002 structure = gst_caps_get_structure(caps, 0);
9003 gst_structure_get_int(structure, "width", &width);
9004 gst_structure_get_int(structure, "height", &height);
9005 string_format = gst_structure_get_string(structure, "format");
9007 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9008 format = util_get_pixtype(fourcc);
9009 gst_caps_unref(caps);
9012 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9013 LOGE("Wrong condition!!");
9017 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9019 LOGE("failed to alloc mem for video data");
9023 stream->width = width;
9024 stream->height = height;
9025 stream->format = format;
9031 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9033 unsigned int pitch = 0;
9035 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9037 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9038 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9039 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9040 stream->stride[index] = pitch;
9041 stream->elevation[index] = stream->height;
9046 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9048 if (stream->format == MM_PIXEL_FORMAT_I420) {
9049 int ret = TBM_SURFACE_ERROR_NONE;
9050 tbm_surface_h surface;
9051 tbm_surface_info_s info;
9053 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9055 ret = tbm_surface_get_info(surface, &info);
9056 if (ret != TBM_SURFACE_ERROR_NONE) {
9057 tbm_surface_destroy(surface);
9061 tbm_surface_destroy(surface);
9062 stream->stride[0] = info.planes[0].stride;
9063 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9064 stream->stride[1] = info.planes[1].stride;
9065 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9066 stream->stride[2] = info.planes[2].stride;
9067 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9068 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9069 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9070 stream->stride[0] = stream->width * 4;
9071 stream->elevation[0] = stream->height;
9072 stream->bo_size = stream->stride[0] * stream->height;
9074 LOGE("Not support format %d", stream->format);
9082 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9084 tbm_bo_handle thandle;
9086 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9087 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9088 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9092 unsigned char *src = NULL;
9093 unsigned char *dest = NULL;
9094 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9096 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9098 LOGE("fail to gst_memory_map");
9102 if (!mapinfo.data) {
9103 LOGE("data pointer is wrong");
9107 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9108 if (!stream->bo[0]) {
9109 LOGE("Fail to tbm_bo_alloc!!");
9113 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9115 LOGE("thandle pointer is wrong");
9119 if (stream->format == MM_PIXEL_FORMAT_I420) {
9120 src_stride[0] = GST_ROUND_UP_4(stream->width);
9121 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9122 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9123 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9126 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9127 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9129 for (i = 0; i < 3; i++) {
9130 src = mapinfo.data + src_offset[i];
9131 dest = thandle.ptr + dest_offset[i];
9136 for (j = 0; j < stream->height >> k; j++) {
9137 memcpy(dest, src, stream->width>>k);
9138 src += src_stride[i];
9139 dest += stream->stride[i];
9142 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9143 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9145 LOGE("Not support format %d", stream->format);
9149 tbm_bo_unmap(stream->bo[0]);
9150 gst_memory_unmap(mem, &mapinfo);
9156 tbm_bo_unmap(stream->bo[0]);
9159 gst_memory_unmap(mem, &mapinfo);
9165 __mmplayer_set_pause_state(mm_player_t *player)
9167 if (player->sent_bos)
9170 /* rtsp case, get content attrs by GstMessage */
9171 if (MMPLAYER_IS_RTSP_STREAMING(player))
9174 /* it's first time to update all content attrs. */
9175 __mmplayer_update_content_attrs(player, ATTR_ALL);
9179 __mmplayer_set_playing_state(mm_player_t *player)
9181 gchar *audio_codec = NULL;
9183 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9184 /* initialize because auto resume is done well. */
9185 player->resumed_by_rewind = FALSE;
9186 player->playback_rate = 1.0;
9189 if (player->sent_bos)
9192 /* try to get content metadata */
9194 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9195 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9196 * legacy mmfw-player api
9198 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9200 if ((player->cmd == MMPLAYER_COMMAND_START)
9201 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9202 __mmplayer_handle_missed_plugin(player);
9205 /* check audio codec field is set or not
9206 * we can get it from typefinder or codec's caps.
9208 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9210 /* The codec format can't be sent for audio only case like amr, mid etc.
9211 * Because, parser don't make related TAG.
9212 * So, if it's not set yet, fill it with found data.
9215 if (g_strrstr(player->type, "audio/midi"))
9216 audio_codec = "MIDI";
9217 else if (g_strrstr(player->type, "audio/x-amr"))
9218 audio_codec = "AMR";
9219 else if (g_strrstr(player->type, "audio/mpeg")
9220 && !g_strrstr(player->type, "mpegversion= (int)1"))
9221 audio_codec = "AAC";
9223 audio_codec = "unknown";
9225 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9227 if (mm_attrs_commit_all(player->attrs))
9228 LOGE("failed to update attributes");
9230 LOGD("set audio codec type with caps");