4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
113 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
114 We are defining our own and will be removed when it actually exposed */
116 GST_AUTOPLUG_SELECT_TRY,
117 GST_AUTOPLUG_SELECT_EXPOSE,
118 GST_AUTOPLUG_SELECT_SKIP
119 } GstAutoplugSelectResult;
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
135 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
136 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
137 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
142 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
143 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
144 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
152 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_release_misc(mm_player_t *player);
154 static void __mmplayer_release_misc_post(mm_player_t *player);
155 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
156 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
159 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
161 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
162 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
163 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
164 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
165 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
166 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
167 static gpointer __mmplayer_gapless_play_thread(gpointer data);
168 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
169 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static void __mmplayer_release_dump_list(GList *dump_list);
171 static int __mmplayer_gst_realize(mm_player_t *player);
172 static int __mmplayer_gst_unrealize(mm_player_t *player);
173 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
174 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
177 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
178 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
179 static void __mmplayer_check_pipeline(mm_player_t *player);
180 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
181 static void __mmplayer_deactivate_old_path(mm_player_t *player);
182 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
183 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
184 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
185 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
186 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
187 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
188 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
189 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
193 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
194 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
195 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
197 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
198 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
199 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
200 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
202 static void __mmplayer_set_pause_state(mm_player_t *player);
203 static void __mmplayer_set_playing_state(mm_player_t *player);
204 /*===========================================================================================
206 | FUNCTION DEFINITIONS |
208 ========================================================================================== */
212 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
216 count = gst_tag_list_get_tag_size(list, tag);
218 LOGD("count = %d", count);
220 for (i = 0; i < count; i++) {
223 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
224 if (!gst_tag_list_get_string_index(list, tag, i, &str))
225 g_assert_not_reached();
227 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
231 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
233 g_print(" : %s", str);
240 /* This function should be called after the pipeline goes PAUSED or higher
243 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
245 static gboolean has_duration = FALSE;
246 static gboolean has_video_attrs = FALSE;
247 static gboolean has_audio_attrs = FALSE;
248 static gboolean has_bitrate = FALSE;
249 gboolean missing_only = FALSE;
250 gboolean all = FALSE;
251 MMHandleType attrs = 0;
255 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
257 /* check player state here */
258 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
259 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
260 /* give warning now only */
261 LOGW("be careful. content attributes may not available in this state ");
264 /* get content attribute first */
265 attrs = MMPLAYER_GET_ATTRS(player);
267 LOGE("cannot get content attribute");
271 /* get update flag */
273 if (flag & ATTR_MISSING_ONLY) {
275 LOGD("updating missed attr only");
278 if (flag & ATTR_ALL) {
280 has_duration = FALSE;
281 has_video_attrs = FALSE;
282 has_audio_attrs = FALSE;
285 LOGD("updating all attrs");
288 if (missing_only && all) {
289 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
290 missing_only = FALSE;
293 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
294 has_duration = __mmplayer_update_duration_value(player);
296 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
297 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
299 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
300 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
302 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
303 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
306 if (mm_attrs_commit_all(attrs)) {
307 LOGE("failed to update attributes");
317 __mmplayer_get_stream_service_type(mm_player_t *player)
319 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
325 player->pipeline->mainbin &&
326 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
327 STREAMING_SERVICE_NONE);
329 /* streaming service type if streaming */
330 if (!MMPLAYER_IS_STREAMING(player))
331 return STREAMING_SERVICE_NONE;
333 streaming_type = (player->duration == 0) ?
334 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
336 switch (streaming_type) {
337 case STREAMING_SERVICE_LIVE:
338 LOGD("it's live streaming");
340 case STREAMING_SERVICE_VOD:
341 LOGD("it's vod streaming");
344 LOGE("should not get here");
350 return streaming_type;
353 /* this function sets the player state and also report
354 * it to applicaton by calling callback function
357 __mmplayer_set_state(mm_player_t *player, int state)
359 MMMessageParamType msg = {0, };
361 MMPLAYER_RETURN_IF_FAIL(player);
363 if (MMPLAYER_CURRENT_STATE(player) == state) {
364 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
365 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
369 /* update player states */
370 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
371 MMPLAYER_CURRENT_STATE(player) = state;
373 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
374 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
377 MMPLAYER_PRINT_STATE(player);
379 switch (MMPLAYER_CURRENT_STATE(player)) {
380 case MM_PLAYER_STATE_NULL:
381 case MM_PLAYER_STATE_READY:
383 case MM_PLAYER_STATE_PAUSED:
384 __mmplayer_set_pause_state(player);
386 case MM_PLAYER_STATE_PLAYING:
387 __mmplayer_set_playing_state(player);
389 case MM_PLAYER_STATE_NONE:
391 LOGW("invalid target state, there is nothing to do.");
396 /* post message to application */
397 if (MMPLAYER_TARGET_STATE(player) == state) {
398 /* fill the message with state of player */
399 msg.union_type = MM_MSG_UNION_STATE;
400 msg.state.previous = MMPLAYER_PREV_STATE(player);
401 msg.state.current = MMPLAYER_CURRENT_STATE(player);
403 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
405 /* state changed by resource callback */
406 if (player->interrupted_by_resource)
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
408 else /* state changed by usecase */
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
412 LOGD("intermediate state, do nothing.");
413 MMPLAYER_PRINT_STATE(player);
417 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
418 && !player->sent_bos) {
419 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
420 player->sent_bos = TRUE;
427 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
429 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
430 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
434 //LOGD("incomming command : %d ", command);
436 current_state = MMPLAYER_CURRENT_STATE(player);
437 pending_state = MMPLAYER_PENDING_STATE(player);
439 MMPLAYER_PRINT_STATE(player);
442 case MMPLAYER_COMMAND_CREATE:
444 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
446 if (current_state == MM_PLAYER_STATE_NULL ||
447 current_state == MM_PLAYER_STATE_READY ||
448 current_state == MM_PLAYER_STATE_PAUSED ||
449 current_state == MM_PLAYER_STATE_PLAYING)
454 case MMPLAYER_COMMAND_DESTROY:
456 /* destroy can called anytime */
458 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
462 case MMPLAYER_COMMAND_REALIZE:
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
466 if (pending_state != MM_PLAYER_STATE_NONE) {
469 /* need ready state to realize */
470 if (current_state == MM_PLAYER_STATE_READY)
473 if (current_state != MM_PLAYER_STATE_NULL)
479 case MMPLAYER_COMMAND_UNREALIZE:
481 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
483 if (current_state == MM_PLAYER_STATE_NULL)
488 case MMPLAYER_COMMAND_START:
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PLAYING)
495 else if (current_state != MM_PLAYER_STATE_READY &&
496 current_state != MM_PLAYER_STATE_PAUSED)
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
501 LOGD("player is going to paused state, just change the pending state as playing");
508 case MMPLAYER_COMMAND_STOP:
510 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
512 if (current_state == MM_PLAYER_STATE_READY)
515 /* need playing/paused state to stop */
516 if (current_state != MM_PLAYER_STATE_PLAYING &&
517 current_state != MM_PLAYER_STATE_PAUSED)
522 case MMPLAYER_COMMAND_PAUSE:
524 if (MMPLAYER_IS_LIVE_STREAMING(player))
527 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
528 goto NOT_COMPLETED_SEEK;
530 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
532 if (pending_state == MM_PLAYER_STATE_NONE) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
535 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
537 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
539 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
540 if (current_state == MM_PLAYER_STATE_PAUSED)
541 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
548 case MMPLAYER_COMMAND_RESUME:
550 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
551 goto NOT_COMPLETED_SEEK;
553 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
555 if (pending_state == MM_PLAYER_STATE_NONE) {
556 if (current_state == MM_PLAYER_STATE_PLAYING)
558 else if (current_state != MM_PLAYER_STATE_PAUSED)
560 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
562 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
563 LOGD("player is going to paused state, just change the pending state as playing");
573 player->cmd = command;
575 return MM_ERROR_NONE;
578 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
579 MMPLAYER_STATE_GET_NAME(current_state), command);
580 return MM_ERROR_PLAYER_INVALID_STATE;
583 LOGW("not completed seek");
584 return MM_ERROR_PLAYER_DOING_SEEK;
587 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
592 return MM_ERROR_PLAYER_NO_OP;
596 __mmplayer_gapless_play_thread(gpointer data)
598 mm_player_t *player = (mm_player_t *)data;
599 MMPlayerGstElement *mainbin = NULL;
601 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
603 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
604 while (!player->gapless_play_thread_exit) {
605 LOGD("gapless play thread started. waiting for signal.");
606 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
608 LOGD("reconfigure pipeline for gapless play.");
610 if (player->gapless_play_thread_exit) {
611 if (player->gapless.reconfigure) {
612 player->gapless.reconfigure = false;
613 MMPLAYER_PLAYBACK_UNLOCK(player);
615 LOGD("exiting gapless play thread");
619 mainbin = player->pipeline->mainbin;
621 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
622 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
627 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
629 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
635 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
637 GSource *source = NULL;
641 source = g_main_context_find_source_by_id(context, source_id);
642 if (source != NULL) {
643 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
644 g_source_destroy(source);
651 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
653 mm_player_t *player = (mm_player_t *)hplayer;
654 GstMessage *msg = NULL;
655 GQueue *queue = NULL;
658 MMPLAYER_RETURN_IF_FAIL(player);
660 /* disconnecting bus watch */
661 if (player->bus_watcher)
662 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
663 player->bus_watcher = 0;
665 /* destroy the gst bus msg thread */
666 if (player->bus_msg_thread) {
667 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
668 player->bus_msg_thread_exit = TRUE;
669 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
670 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
672 LOGD("gst bus msg thread exit.");
673 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
674 player->bus_msg_thread = NULL;
676 g_mutex_clear(&player->bus_msg_thread_mutex);
677 g_cond_clear(&player->bus_msg_thread_cond);
680 g_mutex_lock(&player->bus_msg_q_lock);
681 queue = player->bus_msg_q;
682 while (!g_queue_is_empty(queue)) {
683 msg = (GstMessage *)g_queue_pop_head(queue);
688 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
689 gst_message_unref(msg);
691 g_mutex_unlock(&player->bus_msg_q_lock);
697 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
699 GstElement *parent = NULL;
701 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
703 /* if we have no fakesink. this meas we are using decodebin which doesn'
704 t need to add extra fakesink */
705 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
708 MMPLAYER_FSINK_LOCK(player);
713 /* get parent of fakesink */
714 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
716 LOGD("fakesink already removed");
720 gst_element_set_locked_state(fakesink->gst, TRUE);
722 /* setting the state to NULL never returns async
723 * so no need to wait for completion of state transiton
725 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
726 LOGE("fakesink state change failure!");
727 /* FIXIT : should I return here? or try to proceed to next? */
730 /* remove fakesink from it's parent */
731 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
732 LOGE("failed to remove fakesink");
734 gst_object_unref(parent);
739 gst_object_unref(parent);
741 LOGD("state-holder removed");
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
750 gst_element_set_locked_state(fakesink->gst, FALSE);
752 MMPLAYER_FSINK_UNLOCK(player);
756 static GstPadProbeReturn
757 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
759 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
760 return GST_PAD_PROBE_OK;
764 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
766 gint64 stop_running_time = 0;
767 gint64 position_running_time = 0;
771 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
772 if ((player->gapless.update_segment[idx] == TRUE) ||
773 !(player->selector[idx].event_probe_id)) {
774 /* LOGW("[%d] skip", idx); */
778 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
780 gst_segment_to_running_time(&player->gapless.segment[idx],
781 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
782 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
787 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->duration);
793 position_running_time =
794 gst_segment_to_running_time(&player->gapless.segment[idx],
795 GST_FORMAT_TIME, player->gapless.segment[idx].position);
797 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
798 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
800 GST_TIME_ARGS(stop_running_time),
801 GST_TIME_ARGS(position_running_time),
802 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
803 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
805 position_running_time = MAX(position_running_time, stop_running_time);
806 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
807 GST_FORMAT_TIME, player->gapless.segment[idx].start);
808 position_running_time = MAX(0, position_running_time);
809 position = MAX(position, position_running_time);
813 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
814 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
815 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
817 player->gapless.start_time[stream_type] += position;
823 static GstPadProbeReturn
824 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
826 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
827 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
828 mm_player_t *player = (mm_player_t *)data;
829 GstCaps *caps = NULL;
830 GstStructure *str = NULL;
831 const gchar *name = NULL;
832 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
833 gboolean caps_ret = TRUE;
835 if (GST_EVENT_IS_DOWNSTREAM(event) &&
836 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
837 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
838 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
839 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
841 } else if (GST_EVENT_IS_UPSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
846 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
850 if (strstr(name, "audio")) {
851 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
852 } else if (strstr(name, "video")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
855 /* text track is not supportable */
856 LOGE("invalid name %s", name);
860 switch (GST_EVENT_TYPE(event)) {
863 /* in case of gapless, drop eos event not to send it to sink */
864 if (player->gapless.reconfigure && !player->msg_posted) {
865 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
866 ret = GST_PAD_PROBE_DROP;
870 case GST_EVENT_STREAM_START:
872 __mmplayer_gst_selector_update_start_time(player, stream_type);
875 case GST_EVENT_FLUSH_STOP:
877 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
878 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
879 player->gapless.start_time[stream_type] = 0;
882 case GST_EVENT_SEGMENT:
887 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
888 gst_event_copy_segment(event, &segment);
890 if (segment.format != GST_FORMAT_TIME)
893 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
894 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
895 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
896 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
897 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
898 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
900 /* keep the all the segment ev to cover the seeking */
901 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
902 player->gapless.update_segment[stream_type] = TRUE;
904 if (!player->gapless.running)
907 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
909 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
911 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
912 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
913 gst_event_unref(event);
914 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
920 gdouble proportion = 0.0;
921 GstClockTimeDiff diff = 0;
922 GstClockTime timestamp = 0;
923 gint64 running_time_diff = -1;
925 GstEvent *tmpev = NULL;
927 running_time_diff = player->gapless.segment[stream_type].base;
929 if (running_time_diff <= 0) /* don't need to adjust */
932 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
933 gst_event_unref(event);
935 if (timestamp < running_time_diff) {
936 LOGW("QOS event from previous group");
937 ret = GST_PAD_PROBE_DROP;
941 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
942 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(timestamp),
944 GST_TIME_ARGS(running_time_diff),
945 GST_TIME_ARGS(timestamp - running_time_diff));
947 timestamp -= running_time_diff;
949 /* That case is invalid for QoS events */
950 if (diff < 0 && -diff > timestamp) {
951 LOGW("QOS event from previous group");
952 ret = GST_PAD_PROBE_DROP;
956 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
957 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
967 gst_caps_unref(caps);
971 /* create fakesink for audio or video path witout audiobin or videobin */
973 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
975 GstElement *pipeline = NULL;
976 GstElement *fakesink = NULL;
977 GstPad *sinkpad = NULL;
980 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
982 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
985 fakesink = gst_element_factory_make("fakesink", NULL);
986 if (fakesink == NULL) {
987 LOGE("failed to create fakesink");
991 /* store it as it's sink element */
992 __mmplayer_add_sink(player, fakesink);
994 gst_bin_add(GST_BIN(pipeline), fakesink);
997 sinkpad = gst_element_get_static_pad(fakesink, "sink");
999 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1001 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1002 LOGE("failed to link fakesink");
1003 gst_object_unref(GST_OBJECT(fakesink));
1007 if (strstr(name, "video")) {
1008 if (player->v_stream_caps) {
1009 gst_caps_unref(player->v_stream_caps);
1010 player->v_stream_caps = NULL;
1012 if (player->ini.set_dump_element_flag)
1013 __mmplayer_add_dump_buffer_probe(player, fakesink);
1016 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1017 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1021 gst_object_unref(GST_OBJECT(sinkpad));
1028 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1030 GstElement *pipeline = NULL;
1031 GstElement *selector = NULL;
1032 GstPad *srcpad = NULL;
1035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1037 selector = gst_element_factory_make("input-selector", NULL);
1039 LOGE("failed to create input-selector");
1042 g_object_set(selector, "sync-streams", TRUE, NULL);
1044 player->pipeline->mainbin[elem_idx].id = elem_idx;
1045 player->pipeline->mainbin[elem_idx].gst = selector;
1047 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1049 srcpad = gst_element_get_static_pad(selector, "src");
1051 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1052 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1053 __mmplayer_gst_selector_blocked, NULL, NULL);
1054 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1055 __mmplayer_gst_selector_event_probe, player, NULL);
1057 gst_element_set_state(selector, GST_STATE_PAUSED);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1060 gst_bin_add(GST_BIN(pipeline), selector);
1067 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1069 mm_player_t *player = (mm_player_t *)data;
1070 GstElement *selector = NULL;
1071 GstCaps *caps = NULL;
1072 GstStructure *str = NULL;
1073 const gchar *name = NULL;
1074 GstPad *sinkpad = NULL;
1075 gboolean first_track = FALSE;
1076 gboolean caps_ret = TRUE;
1078 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1079 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1082 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1083 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1085 LOGD("pad-added signal handling");
1087 /* get mimetype from caps */
1088 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1092 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1093 /* LOGD("detected mimetype : %s", name); */
1095 if (strstr(name, "video")) {
1097 gchar *caps_str = NULL;
1099 caps_str = gst_caps_to_string(caps);
1100 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1101 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1102 player->set_mode.video_zc = true;
1104 MMPLAYER_FREEIF(caps_str);
1106 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1107 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1109 LOGD("surface type : %d", stype);
1111 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1112 __mmplayer_gst_create_sinkbin(elem, pad, player);
1116 /* in case of exporting video frame, it requires the 360 video filter.
1117 * it will be handled in _no_more_pads(). */
1118 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1119 __mmplayer_gst_make_fakesink(player, pad, name);
1123 LOGD("video selector is required");
1124 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1125 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1126 } else if (strstr(name, "audio")) {
1127 gint samplerate = 0;
1130 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1131 if (player->build_audio_offload)
1132 player->no_more_pad = TRUE; /* remove state holder */
1133 __mmplayer_gst_create_sinkbin(elem, pad, player);
1137 gst_structure_get_int(str, "rate", &samplerate);
1138 gst_structure_get_int(str, "channels", &channels);
1140 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1141 __mmplayer_gst_make_fakesink(player, pad, name);
1145 LOGD("audio selector is required");
1146 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1147 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1149 } else if (strstr(name, "text")) {
1150 LOGD("text selector is required");
1151 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1152 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1154 LOGE("invalid caps info");
1158 /* check selector and create it */
1159 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1160 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1165 LOGD("input-selector is already created.");
1169 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1171 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1173 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1174 LOGE("failed to link selector");
1175 gst_object_unref(GST_OBJECT(selector));
1180 LOGD("this track will be activated");
1181 g_object_set(selector, "active-pad", sinkpad, NULL);
1184 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1190 gst_caps_unref(caps);
1193 gst_object_unref(GST_OBJECT(sinkpad));
1201 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1203 GstPad *srcpad = NULL;
1206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1208 LOGD("type %d", type);
1211 LOGD("there is no %d track", type);
1215 srcpad = gst_element_get_static_pad(selector, "src");
1217 LOGE("failed to get srcpad from selector");
1221 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1223 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1225 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1226 if (player->selector[type].block_id) {
1227 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1228 player->selector[type].block_id = 0;
1232 gst_object_unref(GST_OBJECT(srcpad));
1241 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1243 MMHandleType attrs = 0;
1244 gint active_index = 0;
1247 MMPLAYER_RETURN_IF_FAIL(player);
1249 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1251 /* change track to active pad */
1252 active_index = player->selector[type].active_pad_index;
1253 if ((active_index != DEFAULT_TRACK) &&
1254 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1255 LOGW("failed to change %d type track to %d", type, active_index);
1256 player->selector[type].active_pad_index = DEFAULT_TRACK;
1260 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1261 attrs = MMPLAYER_GET_ATTRS(player);
1263 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1264 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1266 if (mm_attrs_commit_all(attrs))
1267 LOGW("failed to commit attrs.");
1269 LOGW("cannot get content attribute");
1278 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1281 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1283 if (!audio_selector) {
1284 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1286 /* in case the source is changed, output can be changed. */
1287 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1288 LOGD("remove previous audiobin if it exist");
1290 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1291 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1293 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1294 MMPLAYER_FREEIF(player->pipeline->audiobin);
1297 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1298 __mmplayer_pipeline_complete(NULL, player);
1303 /* apply the audio track information */
1304 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1306 /* create audio sink path */
1307 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1308 LOGE("failed to create audio sink path");
1317 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1320 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1322 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1323 LOGD("text path is not supproted");
1327 /* apply the text track information */
1328 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1330 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1331 player->has_closed_caption = TRUE;
1333 /* create text decode path */
1334 player->no_more_pad = TRUE;
1336 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1337 LOGE("failed to create text sink path");
1346 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1348 gint64 dur_bytes = 0L;
1351 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1352 player->pipeline->mainbin && player->streamer, FALSE);
1354 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1355 LOGE("fail to get duration.");
1357 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1358 * use file information was already set on Q2 when it was created. */
1359 __mm_player_streaming_set_queue2(player->streamer,
1360 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1361 TRUE, /* use_buffering */
1362 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1363 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1370 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1372 mm_player_t *player = NULL;
1373 GstElement *video_selector = NULL;
1374 GstElement *audio_selector = NULL;
1375 GstElement *text_selector = NULL;
1378 player = (mm_player_t *)data;
1380 LOGD("no-more-pad signal handling");
1382 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1383 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1384 LOGW("player is shutting down");
1388 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1389 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1390 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1391 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1392 LOGE("failed to set queue2 buffering");
1397 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1398 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1399 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1401 if (!video_selector && !audio_selector && !text_selector) {
1402 LOGW("there is no selector");
1403 player->no_more_pad = TRUE;
1407 /* create video path followed by video-select */
1408 if (video_selector && !audio_selector && !text_selector)
1409 player->no_more_pad = TRUE;
1411 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1414 /* create audio path followed by audio-select */
1415 if (audio_selector && !text_selector)
1416 player->no_more_pad = TRUE;
1418 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1421 /* create text path followed by text-select */
1422 __mmplayer_create_text_sink_path(player, text_selector);
1425 if (player->gapless.reconfigure) {
1426 player->gapless.reconfigure = FALSE;
1427 MMPLAYER_PLAYBACK_UNLOCK(player);
1434 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1436 gboolean ret = FALSE;
1437 GstElement *pipeline = NULL;
1438 GstPad *sinkpad = NULL;
1441 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1444 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1446 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1448 LOGE("failed to get pad from sinkbin");
1454 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1455 LOGE("failed to link sinkbin for reusing");
1456 goto EXIT; /* exit either pass or fail */
1460 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1461 LOGE("failed to set state(READY) to sinkbin");
1466 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1467 LOGE("failed to add sinkbin to pipeline");
1472 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1473 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1478 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1479 LOGE("failed to set state(PAUSED) to sinkbin");
1488 gst_object_unref(GST_OBJECT(sinkpad));
1496 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t *player = NULL;
1499 GstCaps *caps = NULL;
1500 gchar *caps_str = NULL;
1501 GstStructure *str = NULL;
1502 const gchar *name = NULL;
1503 GstElement *sinkbin = NULL;
1504 gboolean reusing = FALSE;
1505 gboolean caps_ret = TRUE;
1506 gchar *sink_pad_name = "sink";
1509 player = (mm_player_t *)data;
1512 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1513 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1515 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1519 caps_str = gst_caps_to_string(caps);
1521 /* LOGD("detected mimetype : %s", name); */
1522 if (strstr(name, "audio")) {
1523 if (player->pipeline->audiobin == NULL) {
1524 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1525 LOGE("failed to create audiobin. continuing without audio");
1529 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1530 LOGD("creating audiobin success");
1533 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1534 LOGD("reusing audiobin");
1535 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1537 } else if (strstr(name, "video")) {
1538 /* 1. zero copy is updated at _decode_pad_added()
1539 * 2. NULL surface type is handled in _decode_pad_added() */
1540 LOGD("zero copy %d", player->set_mode.video_zc);
1541 if (player->pipeline->videobin == NULL) {
1542 int surface_type = 0;
1543 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1544 LOGD("display_surface_type (%d)", surface_type);
1546 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1547 LOGD("mark video overlay for acquire");
1548 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1549 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1550 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1551 &player->video_overlay_resource)
1552 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1553 LOGE("could not mark video_overlay resource for acquire");
1558 player->interrupted_by_resource = FALSE;
1560 if (mm_resource_manager_commit(player->resource_manager) !=
1561 MM_RESOURCE_MANAGER_ERROR_NONE) {
1562 LOGE("could not acquire resources for video playing");
1566 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1567 LOGE("failed to create videobin. continuing without video");
1571 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1572 LOGD("creating videosink bin success");
1575 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1576 LOGD("re-using videobin");
1577 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1579 } else if (strstr(name, "text")) {
1580 if (player->pipeline->textbin == NULL) {
1581 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1582 LOGE("failed to create text sink bin. continuing without text");
1586 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1587 player->textsink_linked = 1;
1588 LOGD("creating textsink bin success");
1590 if (!player->textsink_linked) {
1591 LOGD("re-using textbin");
1593 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1594 player->textsink_linked = 1;
1596 /* linked textbin exist which means that the external subtitle path exist already */
1597 LOGW("ignoring internal subtutle since external subtitle is available");
1600 sink_pad_name = "text_sink";
1602 LOGW("unknown mime type %s, ignoring it", name);
1606 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1609 LOGD("[handle: %p] success to create and link sink bin", player);
1611 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1612 * streaming task. if the task blocked, then buffer will not flow to the next element
1613 *(autoplugging element). so this is special hack for streaming. please try to remove it
1615 /* dec stream count. we can remove fakesink if it's zero */
1616 if (player->num_dynamic_pad)
1617 player->num_dynamic_pad--;
1619 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1621 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1622 __mmplayer_pipeline_complete(NULL, player);
1626 MMPLAYER_FREEIF(caps_str);
1629 gst_caps_unref(caps);
1635 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1637 int required_angle = 0; /* Angle required for straight view */
1638 int rotation_angle = 0;
1640 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1641 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1643 /* Counter clockwise */
1644 switch (orientation) {
1649 required_angle = 270;
1652 required_angle = 180;
1655 required_angle = 90;
1659 rotation_angle = display_angle + required_angle;
1660 if (rotation_angle >= 360)
1661 rotation_angle -= 360;
1663 /* chech if supported or not */
1664 if (rotation_angle % 90) {
1665 LOGD("not supported rotation angle = %d", rotation_angle);
1669 switch (rotation_angle) {
1671 *value = MM_DISPLAY_ROTATION_NONE;
1674 *value = MM_DISPLAY_ROTATION_90;
1677 *value = MM_DISPLAY_ROTATION_180;
1680 *value = MM_DISPLAY_ROTATION_270;
1684 LOGD("setting rotation property value : %d", *value);
1690 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1692 /* check video sinkbin is created */
1693 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1695 player->pipeline->videobin &&
1696 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1697 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1698 MM_ERROR_PLAYER_NOT_INITIALIZED);
1700 return MM_ERROR_NONE;
1704 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1706 int display_rotation = 0;
1707 gchar *org_orient = NULL;
1708 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1711 LOGE("cannot get content attribute");
1712 return MM_ERROR_PLAYER_INTERNAL;
1715 if (display_angle) {
1716 /* update user roation */
1717 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1719 /* Counter clockwise */
1720 switch (display_rotation) {
1721 case MM_DISPLAY_ROTATION_NONE:
1724 case MM_DISPLAY_ROTATION_90:
1725 *display_angle = 90;
1727 case MM_DISPLAY_ROTATION_180:
1728 *display_angle = 180;
1730 case MM_DISPLAY_ROTATION_270:
1731 *display_angle = 270;
1734 LOGW("wrong angle type : %d", display_rotation);
1737 LOGD("check user angle: %d", *display_angle);
1741 /* Counter clockwise */
1742 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1745 if (!strcmp(org_orient, "rotate-90"))
1747 else if (!strcmp(org_orient, "rotate-180"))
1749 else if (!strcmp(org_orient, "rotate-270"))
1752 LOGD("original rotation is %s", org_orient);
1754 LOGD("content_video_orientation get fail");
1757 LOGD("check orientation: %d", *orientation);
1760 return MM_ERROR_NONE;
1764 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1766 int rotation_value = 0;
1767 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1768 int display_angle = 0;
1771 /* check video sinkbin is created */
1772 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1775 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1777 /* get rotation value to set */
1778 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1779 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1780 LOGD("set video param : rotate %d", rotation_value);
1784 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1786 MMHandleType attrs = 0;
1790 /* check video sinkbin is created */
1791 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1794 attrs = MMPLAYER_GET_ATTRS(player);
1795 MMPLAYER_RETURN_IF_FAIL(attrs);
1797 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1798 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1799 LOGD("set video param : visible %d", visible);
1803 __mmplayer_video_param_set_display_method(mm_player_t *player)
1805 MMHandleType attrs = 0;
1806 int display_method = 0;
1809 /* check video sinkbin is created */
1810 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1813 attrs = MMPLAYER_GET_ATTRS(player);
1814 MMPLAYER_RETURN_IF_FAIL(attrs);
1816 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1817 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1818 LOGD("set video param : method %d", display_method);
1822 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1824 MMHandleType attrs = 0;
1825 void *handle = NULL;
1828 /* check video sinkbin is created */
1829 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1830 LOGW("There is no video sink");
1834 attrs = MMPLAYER_GET_ATTRS(player);
1835 MMPLAYER_RETURN_IF_FAIL(attrs);
1836 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1838 gst_video_overlay_set_video_roi_area(
1839 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1840 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1841 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1842 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1847 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1849 MMHandleType attrs = 0;
1850 void *handle = NULL;
1854 int win_roi_width = 0;
1855 int win_roi_height = 0;
1858 /* check video sinkbin is created */
1859 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1860 LOGW("There is no video sink");
1864 attrs = MMPLAYER_GET_ATTRS(player);
1865 MMPLAYER_RETURN_IF_FAIL(attrs);
1867 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1870 /* It should be set after setting window */
1871 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1872 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1873 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1874 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1876 /* After setting window handle, set display roi area */
1877 gst_video_overlay_set_display_roi_area(
1878 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1879 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1880 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1881 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1886 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1888 MMHandleType attrs = 0;
1889 void *handle = NULL;
1891 /* check video sinkbin is created */
1892 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1895 attrs = MMPLAYER_GET_ATTRS(player);
1896 MMPLAYER_RETURN_IF_FAIL(attrs);
1898 /* common case if using overlay surface */
1899 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1902 /* default is using wl_surface_id */
1903 unsigned int wl_surface_id = 0;
1904 wl_surface_id = *(int *)handle;
1905 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1906 gst_video_overlay_set_wl_window_wl_surface_id(
1907 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1910 /* FIXIT : is it error case? */
1911 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1916 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1918 gboolean update_all_param = FALSE;
1921 /* check video sinkbin is created */
1922 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1923 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1925 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1926 LOGE("can not find tizenwlsink");
1927 return MM_ERROR_PLAYER_INTERNAL;
1930 LOGD("param_name : %s", param_name);
1931 if (!g_strcmp0(param_name, "update_all_param"))
1932 update_all_param = TRUE;
1934 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1935 __mmplayer_video_param_set_display_overlay(player);
1936 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1937 __mmplayer_video_param_set_display_method(player);
1938 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1939 __mmplayer_video_param_set_display_visible(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1941 __mmplayer_video_param_set_display_rotation(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1943 __mmplayer_video_param_set_roi_area(player);
1944 if (update_all_param)
1945 __mmplayer_video_param_set_video_roi_area(player);
1947 return MM_ERROR_NONE;
1951 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1953 MMHandleType attrs = 0;
1954 int surface_type = 0;
1955 int ret = MM_ERROR_NONE;
1959 /* check video sinkbin is created */
1960 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1961 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1963 attrs = MMPLAYER_GET_ATTRS(player);
1965 LOGE("cannot get content attribute");
1966 return MM_ERROR_PLAYER_INTERNAL;
1968 LOGD("param_name : %s", param_name);
1970 /* update display surface */
1971 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1972 LOGD("check display surface type attribute: %d", surface_type);
1974 /* configuring display */
1975 switch (surface_type) {
1976 case MM_DISPLAY_SURFACE_OVERLAY:
1978 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1979 if (ret != MM_ERROR_NONE)
1987 return MM_ERROR_NONE;
1991 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1993 gboolean disable_overlay = FALSE;
1994 mm_player_t *player = (mm_player_t *)hplayer;
1995 int ret = MM_ERROR_NONE;
1998 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1999 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2000 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2001 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2003 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2004 LOGW("Display control is not supported");
2005 return MM_ERROR_PLAYER_INTERNAL;
2008 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2010 if (audio_only == (bool)disable_overlay) {
2011 LOGE("It's the same with current setting: (%d)", audio_only);
2012 return MM_ERROR_NONE;
2016 LOGE("disable overlay");
2017 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2019 /* release overlay resource */
2020 if (player->video_overlay_resource != NULL) {
2021 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2022 player->video_overlay_resource);
2023 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2024 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2027 player->video_overlay_resource = NULL;
2030 ret = mm_resource_manager_commit(player->resource_manager);
2031 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2032 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2036 /* mark video overlay for acquire */
2037 if (player->video_overlay_resource == NULL) {
2038 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2039 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2040 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2041 &player->video_overlay_resource);
2042 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2043 LOGE("could not prepare for video_overlay resource");
2048 player->interrupted_by_resource = FALSE;
2049 /* acquire resources for video overlay */
2050 ret = mm_resource_manager_commit(player->resource_manager);
2051 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2052 LOGE("could not acquire resources for video playing");
2056 LOGD("enable overlay");
2057 __mmplayer_video_param_set_display_overlay(player);
2058 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2063 return MM_ERROR_NONE;
2067 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2069 mm_player_t *player = (mm_player_t *)hplayer;
2070 gboolean disable_overlay = FALSE;
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2075 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2077 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2078 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2080 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2081 LOGW("Display control is not supported");
2082 return MM_ERROR_PLAYER_INTERNAL;
2085 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2087 *paudio_only = (bool)disable_overlay;
2089 LOGD("audio_only : %d", *paudio_only);
2093 return MM_ERROR_NONE;
2097 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2099 GList *bucket = element_bucket;
2100 MMPlayerGstElement *element = NULL;
2101 MMPlayerGstElement *prv_element = NULL;
2102 gint successful_link_count = 0;
2106 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2108 prv_element = (MMPlayerGstElement *)bucket->data;
2109 bucket = bucket->next;
2111 for (; bucket; bucket = bucket->next) {
2112 element = (MMPlayerGstElement *)bucket->data;
2114 if (element && element->gst) {
2115 if (prv_element && prv_element->gst) {
2116 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2117 LOGD("linking [%s] to [%s] success",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2120 successful_link_count++;
2122 LOGD("linking [%s] to [%s] failed",
2123 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2124 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2130 prv_element = element;
2135 return successful_link_count;
2139 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2141 GList *bucket = element_bucket;
2142 MMPlayerGstElement *element = NULL;
2143 int successful_add_count = 0;
2147 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2148 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2150 for (; bucket; bucket = bucket->next) {
2151 element = (MMPlayerGstElement *)bucket->data;
2153 if (element && element->gst) {
2154 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2155 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2156 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2157 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2160 successful_add_count++;
2166 return successful_add_count;
2170 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2172 mm_player_t *player = (mm_player_t *)data;
2173 GstCaps *caps = NULL;
2174 GstStructure *str = NULL;
2176 gboolean caps_ret = TRUE;
2180 MMPLAYER_RETURN_IF_FAIL(pad);
2181 MMPLAYER_RETURN_IF_FAIL(unused);
2182 MMPLAYER_RETURN_IF_FAIL(data);
2184 caps = gst_pad_get_current_caps(pad);
2188 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2192 LOGD("name = %s", name);
2194 if (strstr(name, "audio")) {
2195 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2197 if (player->audio_stream_changed_cb) {
2198 LOGE("call the audio stream changed cb");
2199 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2201 } else if (strstr(name, "video")) {
2202 if ((name = gst_structure_get_string(str, "format")))
2203 player->set_mode.video_zc = name[0] == 'S';
2205 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2207 if (player->video_stream_changed_cb) {
2208 LOGE("call the video stream changed cb");
2209 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2212 LOGW("invalid caps info");
2217 gst_caps_unref(caps);
2225 * This function is to create audio pipeline for playing.
2227 * @param player [in] handle of player
2229 * @return This function returns zero on success.
2231 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2233 /* macro for code readability. just for sinkbin-creation functions */
2234 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2236 x_bin[x_id].id = x_id;\
2237 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2238 if (!x_bin[x_id].gst) {\
2239 LOGE("failed to create %s", x_factory);\
2242 if (x_player->ini.set_dump_element_flag)\
2243 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2246 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2250 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2255 MMPLAYER_RETURN_IF_FAIL(player);
2257 if (player->audio_stream_buff_list) {
2258 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2259 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2262 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2263 __mmplayer_audio_stream_send_data(player, tmp);
2265 MMPLAYER_FREEIF(tmp->pcm_data);
2266 MMPLAYER_FREEIF(tmp);
2269 g_list_free(player->audio_stream_buff_list);
2270 player->audio_stream_buff_list = NULL;
2277 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2279 MMPlayerAudioStreamDataType audio_stream = { 0, };
2282 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2284 audio_stream.bitrate = a_buffer->bitrate;
2285 audio_stream.channel = a_buffer->channel;
2286 audio_stream.depth = a_buffer->depth;
2287 audio_stream.is_little_endian = a_buffer->is_little_endian;
2288 audio_stream.channel_mask = a_buffer->channel_mask;
2289 audio_stream.data_size = a_buffer->data_size;
2290 audio_stream.data = a_buffer->pcm_data;
2292 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2293 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2299 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2301 mm_player_t *player = (mm_player_t *)data;
2305 gint endianness = 0;
2306 guint64 channel_mask = 0;
2307 void *a_data = NULL;
2309 mm_player_audio_stream_buff_t *a_buffer = NULL;
2310 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2314 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2316 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2317 a_data = mapinfo.data;
2318 a_size = mapinfo.size;
2320 GstCaps *caps = gst_pad_get_current_caps(pad);
2321 GstStructure *structure = gst_caps_get_structure(caps, 0);
2323 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2324 gst_structure_get_int(structure, "rate", &rate);
2325 gst_structure_get_int(structure, "channels", &channel);
2326 gst_structure_get_int(structure, "depth", &depth);
2327 gst_structure_get_int(structure, "endianness", &endianness);
2328 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2329 gst_caps_unref(GST_CAPS(caps));
2331 /* In case of the sync is false, use buffer list. *
2332 * The num of buffer list depends on the num of audio channels */
2333 if (player->audio_stream_buff_list) {
2334 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2335 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2337 if (channel_mask == tmp->channel_mask) {
2338 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2339 if (tmp->data_size + a_size < tmp->buff_size) {
2340 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2341 tmp->data_size += a_size;
2343 /* send data to client */
2344 __mmplayer_audio_stream_send_data(player, tmp);
2346 if (a_size > tmp->buff_size) {
2347 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2348 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2349 if (tmp->pcm_data == NULL) {
2350 LOGE("failed to realloc data.");
2353 tmp->buff_size = a_size;
2355 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2356 memcpy(tmp->pcm_data, a_data, a_size);
2357 tmp->data_size = a_size;
2362 LOGE("data is empty in list.");
2368 /* create new audio stream data */
2369 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2370 if (a_buffer == NULL) {
2371 LOGE("failed to alloc data.");
2374 a_buffer->bitrate = rate;
2375 a_buffer->channel = channel;
2376 a_buffer->depth = depth;
2377 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2378 a_buffer->channel_mask = channel_mask;
2379 a_buffer->data_size = a_size;
2381 if (!player->audio_stream_sink_sync) {
2382 /* If sync is FALSE, use buffer list to reduce the IPC. */
2383 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2384 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2385 if (a_buffer->pcm_data == NULL) {
2386 LOGE("failed to alloc data.");
2387 MMPLAYER_FREEIF(a_buffer);
2390 memcpy(a_buffer->pcm_data, a_data, a_size);
2391 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2392 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2394 /* If sync is TRUE, send data directly. */
2395 a_buffer->pcm_data = a_data;
2396 __mmplayer_audio_stream_send_data(player, a_buffer);
2397 MMPLAYER_FREEIF(a_buffer);
2401 gst_buffer_unmap(buffer, &mapinfo);
2406 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2408 mm_player_t *player = (mm_player_t *)data;
2409 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2410 GstPad *sinkpad = NULL;
2411 GstElement *queue = NULL, *sink = NULL;
2414 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2416 queue = gst_element_factory_make("queue", NULL);
2417 if (queue == NULL) {
2418 LOGD("fail make queue");
2422 sink = gst_element_factory_make("fakesink", NULL);
2424 LOGD("fail make fakesink");
2428 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2430 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2431 LOGW("failed to link queue & sink");
2435 sinkpad = gst_element_get_static_pad(queue, "sink");
2437 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2438 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2442 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2444 gst_object_unref(sinkpad);
2445 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2446 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2448 gst_element_set_state(sink, GST_STATE_PAUSED);
2449 gst_element_set_state(queue, GST_STATE_PAUSED);
2451 __mmplayer_add_signal_connection(player,
2453 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2455 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2462 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2464 gst_object_unref(GST_OBJECT(queue));
2468 gst_object_unref(GST_OBJECT(sink));
2472 gst_object_unref(GST_OBJECT(sinkpad));
2480 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2482 #define MAX_PROPS_LEN 128
2483 gint latency_mode = 0;
2484 gchar *stream_type = NULL;
2485 gchar *latency = NULL;
2487 gchar stream_props[MAX_PROPS_LEN] = {0,};
2488 GstStructure *props = NULL;
2491 * It should be set after player creation through attribute.
2492 * But, it can not be changed during playing.
2495 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2497 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2498 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2501 LOGE("stream_type is null.");
2503 if (player->sound.focus_id)
2504 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2505 stream_type, stream_id, player->sound.focus_id);
2507 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2508 stream_type, stream_id);
2509 props = gst_structure_from_string(stream_props, NULL);
2510 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2511 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2512 stream_type, stream_id, player->sound.focus_id, stream_props);
2513 gst_structure_free(props);
2516 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2518 switch (latency_mode) {
2519 case AUDIO_LATENCY_MODE_LOW:
2520 latency = g_strndup("low", 3);
2522 case AUDIO_LATENCY_MODE_MID:
2523 latency = g_strndup("mid", 3);
2525 case AUDIO_LATENCY_MODE_HIGH:
2526 latency = g_strndup("high", 4);
2530 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2534 LOGD("audiosink property - latency=%s", latency);
2536 MMPLAYER_FREEIF(latency);
2542 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2544 MMPlayerGstElement *audiobin = NULL;
2547 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2549 audiobin = player->pipeline->audiobin;
2551 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2552 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2555 if (player->video360_yaw_radians <= M_PI &&
2556 player->video360_yaw_radians >= -M_PI &&
2557 player->video360_pitch_radians <= M_PI_2 &&
2558 player->video360_pitch_radians >= -M_PI_2) {
2559 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2560 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2561 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2562 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", player->video360_metadata.init_view_heading,
2565 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2572 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2574 MMPlayerGstElement *audiobin = NULL;
2575 MMHandleType attrs = 0;
2576 GList *element_bucket = NULL;
2577 GstCaps *acaps = NULL;
2578 GstPad *sink_pad = NULL;
2579 int pitch_control = 0;
2580 double pitch_value = 1.0;
2583 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2584 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2586 audiobin = player->pipeline->audiobin;
2587 attrs = MMPLAYER_GET_ATTRS(player);
2589 if (player->build_audio_offload) { /* skip all the audio filters */
2590 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2591 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2593 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2598 mm_attrs_multiple_get(player->attrs, NULL,
2599 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2600 MM_PLAYER_PITCH_VALUE, &pitch_value,
2603 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2604 if (pitch_control && (player->videodec_linked == 0)) {
2605 GstElementFactory *factory;
2607 factory = gst_element_factory_find("pitch");
2609 gst_object_unref(factory);
2612 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2615 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2616 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2618 LOGW("there is no pitch element");
2623 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2625 /* replaygain volume */
2626 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2627 if (player->sound.rg_enable)
2628 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2630 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2635 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2636 gchar *dst_format = NULL;
2638 int dst_samplerate = 0;
2639 int dst_channels = 0;
2640 GstCaps *caps = NULL;
2641 char *caps_str = NULL;
2643 /* get conf. values */
2644 mm_attrs_multiple_get(player->attrs, NULL,
2645 "pcm_audioformat", &dst_format, &dst_len,
2646 "pcm_extraction_samplerate", &dst_samplerate,
2647 "pcm_extraction_channels", &dst_channels,
2650 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2654 caps = gst_caps_new_simple("audio/x-raw",
2655 "format", G_TYPE_STRING, dst_format,
2656 "rate", G_TYPE_INT, dst_samplerate,
2657 "channels", G_TYPE_INT, dst_channels,
2660 caps_str = gst_caps_to_string(caps);
2661 LOGD("new caps : %s", caps_str);
2663 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2666 gst_caps_unref(caps);
2667 MMPLAYER_FREEIF(caps_str);
2669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2671 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2673 /* raw pad handling signal, audiosink will be added after getting signal */
2674 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2675 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2679 /* normal playback */
2682 /* for logical volume control */
2683 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2686 if (player->sound.mute) {
2687 LOGD("mute enabled");
2688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2691 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2693 /* audio effect element. if audio effect is enabled */
2694 if ((strcmp(player->ini.audioeffect_element, ""))
2696 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2697 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2699 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2701 if ((!player->bypass_audio_effect)
2702 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2703 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2704 if (!_mmplayer_audio_effect_custom_apply(player))
2705 LOGI("apply audio effect(custom) setting success");
2709 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2710 && (player->set_mode.rich_audio))
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2714 /* create audio sink */
2715 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2716 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2717 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2719 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2720 if (player->is_360_feature_enabled &&
2721 player->is_content_spherical &&
2723 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2724 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2725 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2727 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2729 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2732 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2734 gst_caps_unref(acaps);
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2738 player->is_openal_plugin_used = TRUE;
2740 if (player->is_360_feature_enabled && player->is_content_spherical)
2741 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2745 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2746 (player->videodec_linked && player->ini.use_system_clock)) {
2747 LOGD("system clock will be used.");
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2751 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2752 __mmplayer_gst_set_pulsesink_property(player, attrs);
2753 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2754 __mmplayer_gst_set_openalsink_property(player);
2757 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2758 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2760 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2761 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2762 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2763 gst_object_unref(GST_OBJECT(sink_pad));
2765 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2769 *bucket = element_bucket;
2772 return MM_ERROR_NONE;
2775 g_list_free(element_bucket);
2779 return MM_ERROR_PLAYER_INTERNAL;
2783 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2785 MMPlayerGstElement *first_element = NULL;
2786 MMPlayerGstElement *audiobin = NULL;
2788 GstPad *ghostpad = NULL;
2789 GList *element_bucket = NULL;
2793 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2796 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2798 LOGE("failed to allocate memory for audiobin");
2799 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2803 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2804 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2805 if (!audiobin[MMPLAYER_A_BIN].gst) {
2806 LOGE("failed to create audiobin");
2811 player->pipeline->audiobin = audiobin;
2813 /* create audio filters and audiosink */
2814 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2817 /* adding created elements to bin */
2818 LOGD("adding created elements to bin");
2819 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2822 /* linking elements in the bucket by added order. */
2823 LOGD("Linking elements in the bucket by added order.");
2824 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2827 /* get first element's sinkpad for creating ghostpad */
2828 first_element = (MMPlayerGstElement *)element_bucket->data;
2829 if (!first_element) {
2830 LOGE("failed to get first elem");
2834 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2836 LOGE("failed to get pad from first element of audiobin");
2840 ghostpad = gst_ghost_pad_new("sink", pad);
2842 LOGE("failed to create ghostpad");
2846 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2847 LOGE("failed to add ghostpad to audiobin");
2851 gst_object_unref(pad);
2853 g_list_free(element_bucket);
2856 return MM_ERROR_NONE;
2859 LOGD("ERROR : releasing audiobin");
2862 gst_object_unref(GST_OBJECT(pad));
2865 gst_object_unref(GST_OBJECT(ghostpad));
2868 g_list_free(element_bucket);
2870 /* release element which are not added to bin */
2871 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2872 /* NOTE : skip bin */
2873 if (audiobin[i].gst) {
2874 GstObject *parent = NULL;
2875 parent = gst_element_get_parent(audiobin[i].gst);
2878 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2879 audiobin[i].gst = NULL;
2881 gst_object_unref(GST_OBJECT(parent));
2885 /* release audiobin with it's childs */
2886 if (audiobin[MMPLAYER_A_BIN].gst)
2887 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2889 MMPLAYER_FREEIF(audiobin);
2891 player->pipeline->audiobin = NULL;
2893 return MM_ERROR_PLAYER_INTERNAL;
2897 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2899 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2903 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2905 int ret = MM_ERROR_NONE;
2907 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2908 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2910 MMPLAYER_VIDEO_BO_LOCK(player);
2912 if (player->video_bo_list) {
2913 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2914 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2915 if (tmp && tmp->bo == bo) {
2917 LOGD("release bo %p", bo);
2918 tbm_bo_unref(tmp->bo);
2919 MMPLAYER_VIDEO_BO_UNLOCK(player);
2920 MMPLAYER_VIDEO_BO_SIGNAL(player);
2925 /* hw codec is running or the list was reset for DRC. */
2926 LOGW("there is no bo list.");
2928 MMPLAYER_VIDEO_BO_UNLOCK(player);
2930 LOGW("failed to find bo %p", bo);
2935 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2940 MMPLAYER_RETURN_IF_FAIL(player);
2942 MMPLAYER_VIDEO_BO_LOCK(player);
2943 if (player->video_bo_list) {
2944 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2945 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2946 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2949 tbm_bo_unref(tmp->bo);
2953 g_list_free(player->video_bo_list);
2954 player->video_bo_list = NULL;
2956 player->video_bo_size = 0;
2957 MMPLAYER_VIDEO_BO_UNLOCK(player);
2964 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2967 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2968 gboolean ret = TRUE;
2970 /* check DRC, if it is, destroy the prev bo list to create again */
2971 if (player->video_bo_size != size) {
2972 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2973 __mmplayer_video_stream_destroy_bo_list(player);
2974 player->video_bo_size = size;
2977 MMPLAYER_VIDEO_BO_LOCK(player);
2979 if ((!player->video_bo_list) ||
2980 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2982 /* create bo list */
2984 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2986 if (player->video_bo_list) {
2987 /* if bo list did not created all, try it again. */
2988 idx = g_list_length(player->video_bo_list);
2989 LOGD("bo list exist(len: %d)", idx);
2992 for (; idx < player->ini.num_of_video_bo; idx++) {
2993 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2995 LOGE("Fail to alloc bo_info.");
2998 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3000 LOGE("Fail to tbm_bo_alloc.");
3001 MMPLAYER_FREEIF(bo_info);
3004 bo_info->used = FALSE;
3005 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3008 /* update video num buffers */
3009 player->video_num_buffers = idx;
3010 if (idx == player->ini.num_of_video_bo)
3011 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3014 MMPLAYER_VIDEO_BO_UNLOCK(player);
3018 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3022 /* get bo from list*/
3023 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3024 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3025 if (tmp && (tmp->used == FALSE)) {
3026 LOGD("found bo %p to use", tmp->bo);
3028 MMPLAYER_VIDEO_BO_UNLOCK(player);
3029 return tbm_bo_ref(tmp->bo);
3033 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3034 MMPLAYER_VIDEO_BO_UNLOCK(player);
3038 if (player->ini.video_bo_timeout <= 0) {
3039 MMPLAYER_VIDEO_BO_WAIT(player);
3041 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3042 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3049 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3051 mm_player_t *player = (mm_player_t *)data;
3053 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3055 /* send prerolled pkt */
3056 player->video_stream_prerolled = false;
3058 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3060 /* not to send prerolled pkt again */
3061 player->video_stream_prerolled = true;
3065 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3067 mm_player_t *player = (mm_player_t *)data;
3068 MMPlayerVideoStreamDataType *stream = NULL;
3069 GstMemory *mem = NULL;
3072 MMPLAYER_RETURN_IF_FAIL(player);
3073 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3075 if (player->video_stream_prerolled) {
3076 player->video_stream_prerolled = false;
3077 LOGD("skip the prerolled pkt not to send it again");
3081 /* clear stream data structure */
3082 stream = __mmplayer_create_stream_from_pad(pad);
3084 LOGE("failed to alloc stream");
3088 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3090 /* set size and timestamp */
3091 mem = gst_buffer_peek_memory(buffer, 0);
3092 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3093 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3095 /* check zero-copy */
3096 if (player->set_mode.video_zc &&
3097 player->set_mode.media_packet_video_stream &&
3098 gst_is_tizen_memory(mem)) {
3099 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3100 stream->internal_buffer = gst_buffer_ref(buffer);
3101 } else { /* sw codec */
3102 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3105 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3109 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3110 LOGE("failed to send video stream data.");
3117 LOGE("release video stream resource.");
3118 if (gst_is_tizen_memory(mem)) {
3120 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3122 tbm_bo_unref(stream->bo[i]);
3125 /* unref gst buffer */
3126 if (stream->internal_buffer)
3127 gst_buffer_unref(stream->internal_buffer);
3130 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3132 MMPLAYER_FREEIF(stream);
3137 __mmplayer_gst_set_video360_property(mm_player_t *player)
3139 MMPlayerGstElement *videobin = NULL;
3142 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3144 videobin = player->pipeline->videobin;
3146 /* Set spatial media metadata and/or user settings to the element.
3148 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3149 "projection-type", player->video360_metadata.projection_type, NULL);
3151 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3152 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3154 if (player->video360_metadata.full_pano_width_pixels &&
3155 player->video360_metadata.full_pano_height_pixels &&
3156 player->video360_metadata.cropped_area_image_width &&
3157 player->video360_metadata.cropped_area_image_height) {
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3160 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3161 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3162 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3163 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3164 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3168 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3169 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3170 "horizontal-fov", player->video360_horizontal_fov,
3171 "vertical-fov", player->video360_vertical_fov, NULL);
3174 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3175 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3176 "zoom", 1.0f / player->video360_zoom, NULL);
3179 if (player->video360_yaw_radians <= M_PI &&
3180 player->video360_yaw_radians >= -M_PI &&
3181 player->video360_pitch_radians <= M_PI_2 &&
3182 player->video360_pitch_radians >= -M_PI_2) {
3183 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3184 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3185 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3186 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3187 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188 "pose-yaw", player->video360_metadata.init_view_heading,
3189 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3192 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3193 "passthrough", !player->is_video360_enabled, NULL);
3200 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3202 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3203 GList *element_bucket = NULL;
3206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3208 /* create video360 filter */
3209 if (player->is_360_feature_enabled && player->is_content_spherical) {
3210 LOGD("create video360 element");
3211 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3212 __mmplayer_gst_set_video360_property(player);
3216 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3217 LOGD("skip creating the videoconv and rotator");
3218 return MM_ERROR_NONE;
3221 /* in case of sw codec & overlay surface type, except 360 playback.
3222 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3223 LOGD("create video converter: %s", video_csc);
3224 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3227 *bucket = element_bucket;
3229 return MM_ERROR_NONE;
3231 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3232 g_list_free(element_bucket);
3236 return MM_ERROR_PLAYER_INTERNAL;
3240 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3242 gchar *factory_name = NULL;
3244 switch (surface_type) {
3245 case MM_DISPLAY_SURFACE_OVERLAY:
3246 if (strlen(player->ini.videosink_element_overlay) > 0)
3247 factory_name = player->ini.videosink_element_overlay;
3249 case MM_DISPLAY_SURFACE_REMOTE:
3250 case MM_DISPLAY_SURFACE_NULL:
3251 if (strlen(player->ini.videosink_element_fake) > 0)
3252 factory_name = player->ini.videosink_element_fake;
3255 LOGE("unidentified surface type");
3259 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3260 return factory_name;
3264 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3266 gchar *factory_name = NULL;
3267 MMPlayerGstElement *videobin = NULL;
3272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3274 videobin = player->pipeline->videobin;
3275 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3277 attrs = MMPLAYER_GET_ATTRS(player);
3279 LOGE("cannot get content attribute");
3280 return MM_ERROR_PLAYER_INTERNAL;
3283 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3284 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3285 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3287 /* support shard memory with S/W codec on HawkP */
3288 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3289 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3290 "use-tbm", use_tbm, NULL);
3294 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3295 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3298 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3300 LOGD("disable last-sample");
3301 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3304 if (player->set_mode.media_packet_video_stream) {
3306 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3307 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3308 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3310 __mmplayer_add_signal_connection(player,
3311 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3312 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3314 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3317 __mmplayer_add_signal_connection(player,
3318 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3319 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3321 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3325 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3326 return MM_ERROR_PLAYER_INTERNAL;
3328 if (videobin[MMPLAYER_V_SINK].gst) {
3329 GstPad *sink_pad = NULL;
3330 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3332 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3333 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3334 gst_object_unref(GST_OBJECT(sink_pad));
3336 LOGE("failed to get sink pad from videosink");
3340 return MM_ERROR_NONE;
3345 * - video overlay surface(arm/x86) : tizenwlsink
3348 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3351 GList *element_bucket = NULL;
3352 MMPlayerGstElement *first_element = NULL;
3353 MMPlayerGstElement *videobin = NULL;
3354 gchar *videosink_factory_name = NULL;
3357 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3360 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3362 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3364 player->pipeline->videobin = videobin;
3367 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3368 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3369 if (!videobin[MMPLAYER_V_BIN].gst) {
3370 LOGE("failed to create videobin");
3374 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3377 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3378 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3380 /* additional setting for sink plug-in */
3381 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3382 LOGE("failed to set video property");
3386 /* store it as it's sink element */
3387 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3389 /* adding created elements to bin */
3390 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3391 LOGE("failed to add elements");
3395 /* Linking elements in the bucket by added order */
3396 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3397 LOGE("failed to link elements");
3401 /* get first element's sinkpad for creating ghostpad */
3402 first_element = (MMPlayerGstElement *)element_bucket->data;
3403 if (!first_element) {
3404 LOGE("failed to get first element from bucket");
3408 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3410 LOGE("failed to get pad from first element");
3414 /* create ghostpad */
3415 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3416 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3417 LOGE("failed to add ghostpad to videobin");
3420 gst_object_unref(pad);
3422 /* done. free allocated variables */
3423 g_list_free(element_bucket);
3427 return MM_ERROR_NONE;
3430 LOGE("ERROR : releasing videobin");
3431 g_list_free(element_bucket);
3434 gst_object_unref(GST_OBJECT(pad));
3436 /* release videobin with it's childs */
3437 if (videobin[MMPLAYER_V_BIN].gst)
3438 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3440 MMPLAYER_FREEIF(videobin);
3441 player->pipeline->videobin = NULL;
3443 return MM_ERROR_PLAYER_INTERNAL;
3447 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3449 GList *element_bucket = NULL;
3450 MMPlayerGstElement *textbin = player->pipeline->textbin;
3452 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3453 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3454 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3455 "signal-handoffs", FALSE,
3458 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3459 __mmplayer_add_signal_connection(player,
3460 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3461 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3463 G_CALLBACK(__mmplayer_update_subtitle),
3466 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3467 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3469 if (!player->play_subtitle) {
3470 LOGD("add textbin sink as sink element of whole pipeline.");
3471 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3474 /* adding created elements to bin */
3475 LOGD("adding created elements to bin");
3476 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3477 LOGE("failed to add elements");
3481 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3482 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3483 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3485 /* linking elements in the bucket by added order. */
3486 LOGD("Linking elements in the bucket by added order.");
3487 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3488 LOGE("failed to link elements");
3492 /* done. free allocated variables */
3493 g_list_free(element_bucket);
3495 if (textbin[MMPLAYER_T_QUEUE].gst) {
3497 GstPad *ghostpad = NULL;
3499 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3501 LOGE("failed to get sink pad of text queue");
3505 ghostpad = gst_ghost_pad_new("text_sink", pad);
3506 gst_object_unref(pad);
3509 LOGE("failed to create ghostpad of textbin");
3513 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3514 LOGE("failed to add ghostpad to textbin");
3515 gst_object_unref(ghostpad);
3520 return MM_ERROR_NONE;
3523 g_list_free(element_bucket);
3525 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3526 LOGE("remove textbin sink from sink list");
3527 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3530 /* release element at __mmplayer_gst_create_text_sink_bin */
3531 return MM_ERROR_PLAYER_INTERNAL;
3535 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3537 MMPlayerGstElement *textbin = NULL;
3538 GList *element_bucket = NULL;
3539 int surface_type = 0;
3544 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3547 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3549 LOGE("failed to allocate memory for textbin");
3550 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3554 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3555 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3556 if (!textbin[MMPLAYER_T_BIN].gst) {
3557 LOGE("failed to create textbin");
3562 player->pipeline->textbin = textbin;
3565 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3566 LOGD("surface type for subtitle : %d", surface_type);
3567 switch (surface_type) {
3568 case MM_DISPLAY_SURFACE_OVERLAY:
3569 case MM_DISPLAY_SURFACE_NULL:
3570 case MM_DISPLAY_SURFACE_REMOTE:
3571 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3572 LOGE("failed to make plain text elements");
3583 return MM_ERROR_NONE;
3587 LOGD("ERROR : releasing textbin");
3589 g_list_free(element_bucket);
3591 /* release signal */
3592 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3594 /* release element which are not added to bin */
3595 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3596 /* NOTE : skip bin */
3597 if (textbin[i].gst) {
3598 GstObject *parent = NULL;
3599 parent = gst_element_get_parent(textbin[i].gst);
3602 gst_object_unref(GST_OBJECT(textbin[i].gst));
3603 textbin[i].gst = NULL;
3605 gst_object_unref(GST_OBJECT(parent));
3610 /* release textbin with it's childs */
3611 if (textbin[MMPLAYER_T_BIN].gst)
3612 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3614 MMPLAYER_FREEIF(player->pipeline->textbin);
3615 player->pipeline->textbin = NULL;
3618 return MM_ERROR_PLAYER_INTERNAL;
3622 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3624 MMPlayerGstElement *mainbin = NULL;
3625 MMPlayerGstElement *textbin = NULL;
3626 MMHandleType attrs = 0;
3627 GstElement *subsrc = NULL;
3628 GstElement *subparse = NULL;
3629 gchar *subtitle_uri = NULL;
3630 const gchar *charset = NULL;
3636 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3638 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3640 mainbin = player->pipeline->mainbin;
3642 attrs = MMPLAYER_GET_ATTRS(player);
3644 LOGE("cannot get content attribute");
3645 return MM_ERROR_PLAYER_INTERNAL;
3648 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3649 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3650 LOGE("subtitle uri is not proper filepath.");
3651 return MM_ERROR_PLAYER_INVALID_URI;
3654 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3655 LOGE("failed to get storage info of subtitle path");
3656 return MM_ERROR_PLAYER_INVALID_URI;
3659 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3661 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3662 player->subtitle_language_list = NULL;
3663 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3665 /* create the subtitle source */
3666 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3668 LOGE("failed to create filesrc element");
3671 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3673 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3674 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3676 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3677 LOGW("failed to add queue");
3678 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3679 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3680 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3685 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3687 LOGE("failed to create subparse element");
3691 charset = util_get_charset(subtitle_uri);
3693 LOGD("detected charset is %s", charset);
3694 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3697 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3698 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3700 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3701 LOGW("failed to add subparse");
3702 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3703 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3704 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3708 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3709 LOGW("failed to link subsrc and subparse");
3713 player->play_subtitle = TRUE;
3714 player->adjust_subtitle_pos = 0;
3716 LOGD("play subtitle using subtitle file");
3718 if (player->pipeline->textbin == NULL) {
3719 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3720 LOGE("failed to create text sink bin. continuing without text");
3724 textbin = player->pipeline->textbin;
3726 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3727 LOGW("failed to add textbin");
3729 /* release signal */
3730 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3732 /* release textbin with it's childs */
3733 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3734 MMPLAYER_FREEIF(player->pipeline->textbin);
3735 player->pipeline->textbin = textbin = NULL;
3739 LOGD("link text input selector and textbin ghost pad");
3741 player->textsink_linked = 1;
3742 player->external_text_idx = 0;
3743 LOGI("textsink is linked");
3745 textbin = player->pipeline->textbin;
3746 LOGD("text bin has been created. reuse it.");
3747 player->external_text_idx = 1;
3750 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3751 LOGW("failed to link subparse and textbin");
3755 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3757 LOGE("failed to get sink pad from textsink to probe data");
3761 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3762 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3764 gst_object_unref(pad);
3767 /* create dot. for debugging */
3768 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3771 return MM_ERROR_NONE;
3774 /* release text pipeline resource */
3775 player->textsink_linked = 0;
3777 /* release signal */
3778 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3780 if (player->pipeline->textbin) {
3781 LOGE("remove textbin");
3783 /* release textbin with it's childs */
3784 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3785 MMPLAYER_FREEIF(player->pipeline->textbin);
3786 player->pipeline->textbin = NULL;
3790 /* release subtitle elem */
3791 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3792 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3794 return MM_ERROR_PLAYER_INTERNAL;
3798 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3800 mm_player_t *player = (mm_player_t *)data;
3801 MMMessageParamType msg = {0, };
3802 GstClockTime duration = 0;
3803 gpointer text = NULL;
3804 guint text_size = 0;
3805 gboolean ret = TRUE;
3806 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3810 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3811 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3813 if (player->is_subtitle_force_drop) {
3814 LOGW("subtitle is dropped forcedly.");
3818 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3819 text = mapinfo.data;
3820 text_size = mapinfo.size;
3821 duration = GST_BUFFER_DURATION(buffer);
3823 if (player->set_mode.subtitle_off) {
3824 LOGD("subtitle is OFF.");
3828 if (!text || (text_size == 0)) {
3829 LOGD("There is no subtitle to be displayed.");
3833 msg.data = (void *)text;
3834 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3836 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3838 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3839 gst_buffer_unmap(buffer, &mapinfo);
3846 static GstPadProbeReturn
3847 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3849 mm_player_t *player = (mm_player_t *)u_data;
3850 GstClockTime cur_timestamp = 0;
3851 gint64 adjusted_timestamp = 0;
3852 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3854 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3856 if (player->set_mode.subtitle_off) {
3857 LOGD("subtitle is OFF.");
3861 if (player->adjust_subtitle_pos == 0) {
3862 LOGD("nothing to do");
3866 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3867 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3869 if (adjusted_timestamp < 0) {
3870 LOGD("adjusted_timestamp under zero");
3875 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3876 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3877 GST_TIME_ARGS(cur_timestamp),
3878 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3880 return GST_PAD_PROBE_OK;
3884 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3888 /* check player and subtitlebin are created */
3889 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3890 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3892 if (position == 0) {
3893 LOGD("nothing to do");
3895 return MM_ERROR_NONE;
3899 case MM_PLAYER_POS_FORMAT_TIME:
3901 /* check current postion */
3902 player->adjust_subtitle_pos = position;
3904 LOGD("save adjust_subtitle_pos in player") ;
3910 LOGW("invalid format.");
3912 return MM_ERROR_INVALID_ARGUMENT;
3918 return MM_ERROR_NONE;
3922 * This function is to create audio or video pipeline for playing.
3924 * @param player [in] handle of player
3926 * @return This function returns zero on success.
3931 __mmplayer_gst_create_pipeline(mm_player_t *player)
3933 int ret = MM_ERROR_NONE;
3934 MMPlayerGstElement *mainbin = NULL;
3935 MMHandleType attrs = 0;
3938 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3940 /* get profile attribute */
3941 attrs = MMPLAYER_GET_ATTRS(player);
3943 LOGE("failed to get content attribute");
3947 /* create pipeline handles */
3948 if (player->pipeline) {
3949 LOGE("pipeline should be released before create new one");
3953 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3954 if (player->pipeline == NULL)
3957 /* create mainbin */
3958 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3959 if (mainbin == NULL)
3962 /* create pipeline */
3963 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3964 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3965 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3966 LOGE("failed to create pipeline");
3971 player->pipeline->mainbin = mainbin;
3973 /* create the source and decoder elements */
3974 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3975 ret = __mmplayer_gst_build_es_pipeline(player);
3977 ret = __mmplayer_gst_build_pipeline(player);
3979 if (ret != MM_ERROR_NONE) {
3980 LOGE("failed to create some elements");
3984 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3985 if (__mmplayer_check_subtitle(player)
3986 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3987 LOGE("failed to create text pipeline");
3990 ret = __mmplayer_gst_add_bus_watch(player);
3991 if (ret != MM_ERROR_NONE) {
3992 LOGE("failed to add bus watch");
3997 return MM_ERROR_NONE;
4000 __mmplayer_gst_destroy_pipeline(player);
4001 return MM_ERROR_PLAYER_INTERNAL;
4005 __mmplayer_reset_gapless_state(mm_player_t *player)
4008 MMPLAYER_RETURN_IF_FAIL(player
4010 && player->pipeline->audiobin
4011 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4013 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4020 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4023 int ret = MM_ERROR_NONE;
4027 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4029 /* cleanup stuffs */
4030 MMPLAYER_FREEIF(player->type);
4031 player->no_more_pad = FALSE;
4032 player->num_dynamic_pad = 0;
4033 player->demux_pad_index = 0;
4035 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4036 player->subtitle_language_list = NULL;
4037 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4039 __mmplayer_reset_gapless_state(player);
4041 if (player->streamer) {
4042 __mm_player_streaming_initialize(player->streamer, FALSE);
4043 __mm_player_streaming_destroy(player->streamer);
4044 player->streamer = NULL;
4047 /* cleanup unlinked mime type */
4048 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4049 MMPLAYER_FREEIF(player->unlinked_video_mime);
4050 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4052 /* cleanup running stuffs */
4053 __mmplayer_cancel_eos_timer(player);
4055 /* cleanup gst stuffs */
4056 if (player->pipeline) {
4057 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4058 GstTagList *tag_list = player->pipeline->tag_list;
4060 /* first we need to disconnect all signal hander */
4061 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4064 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4065 MMPlayerGstElement *videobin = player->pipeline->videobin;
4066 MMPlayerGstElement *textbin = player->pipeline->textbin;
4067 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4068 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4069 gst_object_unref(bus);
4071 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4072 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4073 if (ret != MM_ERROR_NONE) {
4074 LOGE("fail to change state to NULL");
4075 return MM_ERROR_PLAYER_INTERNAL;
4078 LOGW("succeeded in changing state to NULL");
4080 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4083 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4084 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4086 /* free avsysaudiosink
4087 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4088 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4090 MMPLAYER_FREEIF(audiobin);
4091 MMPLAYER_FREEIF(videobin);
4092 MMPLAYER_FREEIF(textbin);
4093 MMPLAYER_FREEIF(mainbin);
4097 gst_tag_list_unref(tag_list);
4099 MMPLAYER_FREEIF(player->pipeline);
4101 MMPLAYER_FREEIF(player->album_art);
4103 if (player->v_stream_caps) {
4104 gst_caps_unref(player->v_stream_caps);
4105 player->v_stream_caps = NULL;
4108 if (player->a_stream_caps) {
4109 gst_caps_unref(player->a_stream_caps);
4110 player->a_stream_caps = NULL;
4113 if (player->s_stream_caps) {
4114 gst_caps_unref(player->s_stream_caps);
4115 player->s_stream_caps = NULL;
4117 __mmplayer_track_destroy(player);
4119 if (player->sink_elements)
4120 g_list_free(player->sink_elements);
4121 player->sink_elements = NULL;
4123 if (player->bufmgr) {
4124 tbm_bufmgr_deinit(player->bufmgr);
4125 player->bufmgr = NULL;
4128 LOGW("finished destroy pipeline");
4136 __mmplayer_gst_realize(mm_player_t *player)
4139 int ret = MM_ERROR_NONE;
4143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4145 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4147 ret = __mmplayer_gst_create_pipeline(player);
4149 LOGE("failed to create pipeline");
4153 /* set pipeline state to READY */
4154 /* NOTE : state change to READY must be performed sync. */
4155 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4156 ret = __mmplayer_gst_set_state(player,
4157 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4159 if (ret != MM_ERROR_NONE) {
4160 /* return error if failed to set state */
4161 LOGE("failed to set READY state");
4165 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4167 /* create dot before error-return. for debugging */
4168 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4176 __mmplayer_gst_unrealize(mm_player_t *player)
4178 int ret = MM_ERROR_NONE;
4182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4184 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4185 MMPLAYER_PRINT_STATE(player);
4187 /* release miscellaneous information */
4188 __mmplayer_release_misc(player);
4190 /* destroy pipeline */
4191 ret = __mmplayer_gst_destroy_pipeline(player);
4192 if (ret != MM_ERROR_NONE) {
4193 LOGE("failed to destory pipeline");
4197 /* release miscellaneous information.
4198 these info needs to be released after pipeline is destroyed. */
4199 __mmplayer_release_misc_post(player);
4201 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4209 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4214 LOGW("set_message_callback is called with invalid player handle");
4215 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4218 player->msg_cb = callback;
4219 player->msg_cb_param = user_param;
4221 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4225 return MM_ERROR_NONE;
4229 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4231 int ret = MM_ERROR_NONE;
4236 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4237 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4238 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4240 memset(data, 0, sizeof(MMPlayerParseProfile));
4242 if (strstr(uri, "es_buff://")) {
4243 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4244 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4245 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4246 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4248 tmp = g_ascii_strdown(uri, strlen(uri));
4249 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4250 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4252 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4254 } else if (strstr(uri, "mms://")) {
4255 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4256 } else if ((path = strstr(uri, "mem://"))) {
4257 ret = __mmplayer_set_mem_uri(data, path, param);
4259 ret = __mmplayer_set_file_uri(data, uri);
4262 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4263 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4264 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4265 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4267 /* dump parse result */
4268 SECURE_LOGW("incoming uri : %s", uri);
4269 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4270 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4278 __mmplayer_can_do_interrupt(mm_player_t *player)
4280 if (!player || !player->pipeline || !player->attrs) {
4281 LOGW("not initialized");
4285 if (player->audio_stream_render_cb) {
4286 LOGW("not support in pcm extraction mode");
4290 /* check if seeking */
4291 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4292 MMMessageParamType msg_param;
4293 memset(&msg_param, 0, sizeof(MMMessageParamType));
4294 msg_param.code = MM_ERROR_PLAYER_SEEK;
4295 player->seek_state = MMPLAYER_SEEK_NONE;
4296 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4300 /* check other thread */
4301 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4302 LOGW("locked already, cmd state : %d", player->cmd);
4304 /* check application command */
4305 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4306 LOGW("playing.. should wait cmd lock then, will be interrupted");
4308 /* lock will be released at mrp_resource_release_cb() */
4309 MMPLAYER_CMD_LOCK(player);
4312 LOGW("nothing to do");
4315 LOGW("can interrupt immediately");
4319 FAILED: /* with CMD UNLOCKED */
4322 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4327 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4330 mm_player_t *player = NULL;
4334 if (user_data == NULL) {
4335 LOGE("- user_data is null");
4338 player = (mm_player_t *)user_data;
4340 /* do something to release resource here.
4341 * player stop and interrupt forwarding */
4342 if (!__mmplayer_can_do_interrupt(player)) {
4343 LOGW("no need to interrupt, so leave");
4345 MMMessageParamType msg = {0, };
4348 player->interrupted_by_resource = TRUE;
4350 /* get last play position */
4351 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4352 LOGW("failed to get play position.");
4354 msg.union_type = MM_MSG_UNION_TIME;
4355 msg.time.elapsed = pos;
4356 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4358 LOGD("video resource conflict so, resource will be freed by unrealizing");
4359 if (_mmplayer_unrealize((MMHandleType)player))
4360 LOGW("failed to unrealize");
4362 /* lock is called in __mmplayer_can_do_interrupt() */
4363 MMPLAYER_CMD_UNLOCK(player);
4366 if (res == player->video_overlay_resource)
4367 player->video_overlay_resource = FALSE;
4369 player->video_decoder_resource = FALSE;
4377 __mmplayer_initialize_video_roi(mm_player_t *player)
4379 player->video_roi.scale_x = 0.0;
4380 player->video_roi.scale_y = 0.0;
4381 player->video_roi.scale_width = 1.0;
4382 player->video_roi.scale_height = 1.0;
4386 _mmplayer_create_player(MMHandleType handle)
4388 int ret = MM_ERROR_PLAYER_INTERNAL;
4389 bool enabled = false;
4391 mm_player_t *player = MM_PLAYER_CAST(handle);
4395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4397 /* initialize player state */
4398 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4399 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4400 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4401 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4403 /* check current state */
4404 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4406 /* construct attributes */
4407 player->attrs = _mmplayer_construct_attribute(handle);
4409 if (!player->attrs) {
4410 LOGE("Failed to construct attributes");
4414 /* initialize gstreamer with configured parameter */
4415 if (!__mmplayer_init_gstreamer(player)) {
4416 LOGE("Initializing gstreamer failed");
4417 _mmplayer_deconstruct_attribute(handle);
4421 /* create lock. note that g_tread_init() has already called in gst_init() */
4422 g_mutex_init(&player->fsink_lock);
4424 /* create update tag lock */
4425 g_mutex_init(&player->update_tag_lock);
4427 /* create gapless play mutex */
4428 g_mutex_init(&player->gapless_play_thread_mutex);
4430 /* create gapless play cond */
4431 g_cond_init(&player->gapless_play_thread_cond);
4433 /* create gapless play thread */
4434 player->gapless_play_thread =
4435 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4436 if (!player->gapless_play_thread) {
4437 LOGE("failed to create gapless play thread");
4438 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4439 g_mutex_clear(&player->gapless_play_thread_mutex);
4440 g_cond_clear(&player->gapless_play_thread_cond);
4444 player->bus_msg_q = g_queue_new();
4445 if (!player->bus_msg_q) {
4446 LOGE("failed to create queue for bus_msg");
4447 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4451 ret = _mmplayer_initialize_video_capture(player);
4452 if (ret != MM_ERROR_NONE) {
4453 LOGE("failed to initialize video capture");
4457 /* initialize resource manager */
4458 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4459 __resource_release_cb, player, &player->resource_manager)
4460 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4461 LOGE("failed to initialize resource manager");
4462 ret = MM_ERROR_PLAYER_INTERNAL;
4466 /* create video bo lock and cond */
4467 g_mutex_init(&player->video_bo_mutex);
4468 g_cond_init(&player->video_bo_cond);
4470 /* create media stream callback mutex */
4471 g_mutex_init(&player->media_stream_cb_lock);
4473 /* create subtitle info lock and cond */
4474 g_mutex_init(&player->subtitle_info_mutex);
4475 g_cond_init(&player->subtitle_info_cond);
4477 player->streaming_type = STREAMING_SERVICE_NONE;
4479 /* give default value of audio effect setting */
4480 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4481 player->sound.rg_enable = false;
4482 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4484 player->play_subtitle = FALSE;
4485 player->has_closed_caption = FALSE;
4486 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4487 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4488 player->pending_resume = FALSE;
4489 if (player->ini.dump_element_keyword[0][0] == '\0')
4490 player->ini.set_dump_element_flag = FALSE;
4492 player->ini.set_dump_element_flag = TRUE;
4494 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4495 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4496 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4498 /* Set video360 settings to their defaults for just-created player.
4501 player->is_360_feature_enabled = FALSE;
4502 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4503 LOGI("spherical feature info: %d", enabled);
4505 player->is_360_feature_enabled = TRUE;
4507 LOGE("failed to get spherical feature info");
4510 player->is_content_spherical = FALSE;
4511 player->is_video360_enabled = TRUE;
4512 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4513 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4514 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4515 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4516 player->video360_zoom = 1.0f;
4517 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4518 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4520 __mmplayer_initialize_video_roi(player);
4522 /* set player state to null */
4523 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4524 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4528 return MM_ERROR_NONE;
4532 g_mutex_clear(&player->fsink_lock);
4533 /* free update tag lock */
4534 g_mutex_clear(&player->update_tag_lock);
4535 g_queue_free(player->bus_msg_q);
4536 /* free gapless play thread */
4537 if (player->gapless_play_thread) {
4538 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4539 player->gapless_play_thread_exit = TRUE;
4540 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4541 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4543 g_thread_join(player->gapless_play_thread);
4544 player->gapless_play_thread = NULL;
4546 g_mutex_clear(&player->gapless_play_thread_mutex);
4547 g_cond_clear(&player->gapless_play_thread_cond);
4550 /* release attributes */
4551 _mmplayer_deconstruct_attribute(handle);
4559 __mmplayer_init_gstreamer(mm_player_t *player)
4561 static gboolean initialized = FALSE;
4562 static const int max_argc = 50;
4564 gchar **argv = NULL;
4565 gchar **argv2 = NULL;
4571 LOGD("gstreamer already initialized.");
4576 argc = malloc(sizeof(int));
4577 argv = malloc(sizeof(gchar *) * max_argc);
4578 argv2 = malloc(sizeof(gchar *) * max_argc);
4580 if (!argc || !argv || !argv2)
4583 memset(argv, 0, sizeof(gchar *) * max_argc);
4584 memset(argv2, 0, sizeof(gchar *) * max_argc);
4588 argv[0] = g_strdup("mmplayer");
4591 for (i = 0; i < 5; i++) {
4592 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4593 if (strlen(player->ini.gst_param[i]) > 0) {
4594 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4599 /* we would not do fork for scanning plugins */
4600 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4603 /* check disable registry scan */
4604 if (player->ini.skip_rescan) {
4605 argv[*argc] = g_strdup("--gst-disable-registry-update");
4609 /* check disable segtrap */
4610 if (player->ini.disable_segtrap) {
4611 argv[*argc] = g_strdup("--gst-disable-segtrap");
4615 LOGD("initializing gstreamer with following parameter");
4616 LOGD("argc : %d", *argc);
4619 for (i = 0; i < arg_count; i++) {
4621 LOGD("argv[%d] : %s", i, argv2[i]);
4624 /* initializing gstreamer */
4625 if (!gst_init_check(argc, &argv, &err)) {
4626 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4633 for (i = 0; i < arg_count; i++) {
4634 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4635 MMPLAYER_FREEIF(argv2[i]);
4638 MMPLAYER_FREEIF(argv);
4639 MMPLAYER_FREEIF(argv2);
4640 MMPLAYER_FREEIF(argc);
4650 for (i = 0; i < arg_count; i++) {
4651 LOGD("free[%d] : %s", i, argv2[i]);
4652 MMPLAYER_FREEIF(argv2[i]);
4655 MMPLAYER_FREEIF(argv);
4656 MMPLAYER_FREEIF(argv2);
4657 MMPLAYER_FREEIF(argc);
4663 __mmplayer_check_async_state_transition(mm_player_t *player)
4665 GstState element_state = GST_STATE_VOID_PENDING;
4666 GstState element_pending_state = GST_STATE_VOID_PENDING;
4667 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4668 GstElement *element = NULL;
4669 gboolean async = FALSE;
4671 /* check player handle */
4672 MMPLAYER_RETURN_IF_FAIL(player &&
4674 player->pipeline->mainbin &&
4675 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4678 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4680 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4681 LOGD("don't need to check the pipeline state");
4685 MMPLAYER_PRINT_STATE(player);
4687 /* wait for state transition */
4688 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4689 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4691 if (ret == GST_STATE_CHANGE_FAILURE) {
4692 LOGE(" [%s] state : %s pending : %s",
4693 GST_ELEMENT_NAME(element),
4694 gst_element_state_get_name(element_state),
4695 gst_element_state_get_name(element_pending_state));
4697 /* dump state of all element */
4698 __mmplayer_dump_pipeline_state(player);
4703 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4708 _mmplayer_destroy(MMHandleType handle)
4710 mm_player_t *player = MM_PLAYER_CAST(handle);
4714 /* check player handle */
4715 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4717 /* destroy can called at anytime */
4718 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4720 /* check async state transition */
4721 __mmplayer_check_async_state_transition(player);
4723 /* release gapless play thread */
4724 if (player->gapless_play_thread) {
4725 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4726 player->gapless_play_thread_exit = TRUE;
4727 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4728 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4730 LOGD("waitting for gapless play thread exit");
4731 g_thread_join(player->gapless_play_thread);
4732 g_mutex_clear(&player->gapless_play_thread_mutex);
4733 g_cond_clear(&player->gapless_play_thread_cond);
4734 LOGD("gapless play thread released");
4737 _mmplayer_release_video_capture(player);
4739 /* de-initialize resource manager */
4740 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4741 player->resource_manager))
4742 LOGE("failed to deinitialize resource manager");
4744 /* release pipeline */
4745 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4746 LOGE("failed to destory pipeline");
4747 return MM_ERROR_PLAYER_INTERNAL;
4750 g_queue_free(player->bus_msg_q);
4752 /* release subtitle info lock and cond */
4753 g_mutex_clear(&player->subtitle_info_mutex);
4754 g_cond_clear(&player->subtitle_info_cond);
4756 __mmplayer_release_dump_list(player->dump_list);
4758 /* release miscellaneous information */
4759 __mmplayer_release_misc(player);
4761 /* release miscellaneous information.
4762 these info needs to be released after pipeline is destroyed. */
4763 __mmplayer_release_misc_post(player);
4765 /* release attributes */
4766 _mmplayer_deconstruct_attribute(handle);
4769 g_mutex_clear(&player->fsink_lock);
4772 g_mutex_clear(&player->update_tag_lock);
4774 /* release video bo lock and cond */
4775 g_mutex_clear(&player->video_bo_mutex);
4776 g_cond_clear(&player->video_bo_cond);
4778 /* release media stream callback lock */
4779 g_mutex_clear(&player->media_stream_cb_lock);
4783 return MM_ERROR_NONE;
4787 _mmplayer_realize(MMHandleType hplayer)
4789 mm_player_t *player = (mm_player_t *)hplayer;
4792 MMHandleType attrs = 0;
4793 int ret = MM_ERROR_NONE;
4797 /* check player handle */
4798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4800 /* check current state */
4801 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4803 attrs = MMPLAYER_GET_ATTRS(player);
4805 LOGE("fail to get attributes.");
4806 return MM_ERROR_PLAYER_INTERNAL;
4808 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4809 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4811 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4812 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4814 if (ret != MM_ERROR_NONE) {
4815 LOGE("failed to parse profile");
4820 if (uri && (strstr(uri, "es_buff://"))) {
4821 if (strstr(uri, "es_buff://push_mode"))
4822 player->es_player_push_mode = TRUE;
4824 player->es_player_push_mode = FALSE;
4827 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4828 LOGW("mms protocol is not supported format.");
4829 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4832 if (MMPLAYER_IS_STREAMING(player))
4833 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4835 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4837 player->smooth_streaming = FALSE;
4838 player->videodec_linked = 0;
4839 player->audiodec_linked = 0;
4840 player->textsink_linked = 0;
4841 player->is_external_subtitle_present = FALSE;
4842 player->is_external_subtitle_added_now = FALSE;
4843 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4844 player->video360_metadata.is_spherical = -1;
4845 player->is_openal_plugin_used = FALSE;
4846 player->demux_pad_index = 0;
4847 player->subtitle_language_list = NULL;
4848 player->is_subtitle_force_drop = FALSE;
4849 player->last_multiwin_status = FALSE;
4851 __mmplayer_track_initialize(player);
4852 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4854 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4855 gint prebuffer_ms = 0, rebuffer_ms = 0;
4857 player->streamer = __mm_player_streaming_create();
4858 __mm_player_streaming_initialize(player->streamer, TRUE);
4860 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4861 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4863 if (prebuffer_ms > 0) {
4864 prebuffer_ms = MAX(prebuffer_ms, 1000);
4865 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4868 if (rebuffer_ms > 0) {
4869 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4870 rebuffer_ms = MAX(rebuffer_ms, 1000);
4871 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4874 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4875 player->streamer->buffering_req.rebuffer_time);
4878 /* realize pipeline */
4879 ret = __mmplayer_gst_realize(player);
4880 if (ret != MM_ERROR_NONE)
4881 LOGE("fail to realize the player.");
4883 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4891 _mmplayer_unrealize(MMHandleType hplayer)
4893 mm_player_t *player = (mm_player_t *)hplayer;
4894 int ret = MM_ERROR_NONE;
4898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4900 MMPLAYER_CMD_UNLOCK(player);
4901 /* destroy the gst bus msg thread which is created during realize.
4902 this funct have to be called before getting cmd lock. */
4903 __mmplayer_bus_msg_thread_destroy(player);
4904 MMPLAYER_CMD_LOCK(player);
4906 /* check current state */
4907 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4909 /* check async state transition */
4910 __mmplayer_check_async_state_transition(player);
4912 /* unrealize pipeline */
4913 ret = __mmplayer_gst_unrealize(player);
4915 /* set asm stop if success */
4916 if (MM_ERROR_NONE == ret) {
4917 if (!player->interrupted_by_resource) {
4918 if (player->video_decoder_resource != NULL) {
4919 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4920 player->video_decoder_resource);
4921 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4922 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4924 player->video_decoder_resource = NULL;
4927 if (player->video_overlay_resource != NULL) {
4928 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4929 player->video_overlay_resource);
4930 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4931 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4933 player->video_overlay_resource = NULL;
4936 ret = mm_resource_manager_commit(player->resource_manager);
4937 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4938 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4941 LOGE("failed and don't change asm state to stop");
4949 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4951 mm_player_t *player = (mm_player_t *)hplayer;
4953 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4955 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4959 _mmplayer_get_state(MMHandleType hplayer, int *state)
4961 mm_player_t *player = (mm_player_t *)hplayer;
4963 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4965 *state = MMPLAYER_CURRENT_STATE(player);
4967 return MM_ERROR_NONE;
4972 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4974 mm_player_t *player = (mm_player_t *)hplayer;
4975 GstElement *vol_element = NULL;
4980 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4982 LOGD("volume [L]=%f:[R]=%f",
4983 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4985 /* invalid factor range or not */
4986 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4987 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4988 LOGE("Invalid factor!(valid factor:0~1.0)");
4989 return MM_ERROR_INVALID_ARGUMENT;
4993 /* not support to set other value into each channel */
4994 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4995 return MM_ERROR_INVALID_ARGUMENT;
4997 /* Save volume to handle. Currently the first array element will be saved. */
4998 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5000 /* check pipeline handle */
5001 if (!player->pipeline || !player->pipeline->audiobin) {
5002 LOGD("audiobin is not created yet");
5003 LOGD("but, current stored volume will be set when it's created.");
5005 /* NOTE : stored volume will be used in create_audiobin
5006 * returning MM_ERROR_NONE here makes application to able to
5007 * set volume at anytime.
5009 return MM_ERROR_NONE;
5012 /* setting volume to volume element */
5013 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5016 LOGD("volume is set [%f]", player->sound.volume);
5017 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5022 return MM_ERROR_NONE;
5026 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5028 mm_player_t *player = (mm_player_t *)hplayer;
5033 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5034 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5036 /* returning stored volume */
5037 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5038 volume->level[i] = player->sound.volume;
5042 return MM_ERROR_NONE;
5046 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5048 mm_player_t *player = (mm_player_t *)hplayer;
5049 GstElement *vol_element = NULL;
5053 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5055 /* mute value shoud 0 or 1 */
5056 if (mute != 0 && mute != 1) {
5057 LOGE("bad mute value");
5059 /* FIXIT : definitly, we need _BAD_PARAM error code */
5060 return MM_ERROR_INVALID_ARGUMENT;
5063 player->sound.mute = mute;
5065 /* just hold mute value if pipeline is not ready */
5066 if (!player->pipeline || !player->pipeline->audiobin) {
5067 LOGD("pipeline is not ready. holding mute value");
5068 return MM_ERROR_NONE;
5071 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5073 /* NOTE : volume will only created when the bt is enabled */
5075 LOGD("mute : %d", mute);
5076 g_object_set(vol_element, "mute", mute, NULL);
5078 LOGD("volume elemnet is not created. using volume in audiosink");
5082 return MM_ERROR_NONE;
5086 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5088 mm_player_t *player = (mm_player_t *)hplayer;
5092 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5093 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5095 /* just hold mute value if pipeline is not ready */
5096 if (!player->pipeline || !player->pipeline->audiobin) {
5097 LOGD("pipeline is not ready. returning stored value");
5098 *pmute = player->sound.mute;
5099 return MM_ERROR_NONE;
5102 *pmute = player->sound.mute;
5106 return MM_ERROR_NONE;
5110 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5112 mm_player_t *player = (mm_player_t *)hplayer;
5116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5118 player->video_stream_changed_cb = callback;
5119 player->video_stream_changed_cb_user_param = user_param;
5120 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5124 return MM_ERROR_NONE;
5128 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5130 mm_player_t *player = (mm_player_t *)hplayer;
5134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5136 player->audio_stream_changed_cb = callback;
5137 player->audio_stream_changed_cb_user_param = user_param;
5138 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5142 return MM_ERROR_NONE;
5146 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5148 mm_player_t *player = (mm_player_t *)hplayer;
5152 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5154 player->audio_stream_render_cb = callback;
5155 player->audio_stream_cb_user_param = user_param;
5156 player->audio_stream_sink_sync = sync;
5157 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5161 return MM_ERROR_NONE;
5165 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5167 mm_player_t *player = (mm_player_t *)hplayer;
5171 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5173 if (callback && !player->bufmgr)
5174 player->bufmgr = tbm_bufmgr_init(-1);
5176 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5177 player->video_stream_cb = callback;
5178 player->video_stream_cb_user_param = user_param;
5180 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5184 return MM_ERROR_NONE;
5188 _mmplayer_start(MMHandleType hplayer)
5190 mm_player_t *player = (mm_player_t *)hplayer;
5191 gint ret = MM_ERROR_NONE;
5195 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5197 /* check current state */
5198 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5200 /* start pipeline */
5201 ret = __mmplayer_gst_start(player);
5202 if (ret != MM_ERROR_NONE)
5203 LOGE("failed to start player.");
5205 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5206 LOGD("force playing start even during buffering");
5207 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5215 /* NOTE: post "not supported codec message" to application
5216 * when one codec is not found during AUTOPLUGGING in MSL.
5217 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5218 * And, if any codec is not found, don't send message here.
5219 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5222 __mmplayer_handle_missed_plugin(mm_player_t *player)
5224 MMMessageParamType msg_param;
5225 memset(&msg_param, 0, sizeof(MMMessageParamType));
5226 gboolean post_msg_direct = FALSE;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5232 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5233 player->not_supported_codec, player->can_support_codec);
5235 if (player->not_found_demuxer) {
5236 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5237 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5239 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5240 MMPLAYER_FREEIF(msg_param.data);
5242 return MM_ERROR_NONE;
5245 if (player->not_supported_codec) {
5246 if (player->can_support_codec) {
5247 // There is one codec to play
5248 post_msg_direct = TRUE;
5250 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5251 post_msg_direct = TRUE;
5254 if (post_msg_direct) {
5255 MMMessageParamType msg_param;
5256 memset(&msg_param, 0, sizeof(MMMessageParamType));
5258 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5259 LOGW("not found AUDIO codec, posting error code to application.");
5261 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5262 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5263 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5264 LOGW("not found VIDEO codec, posting error code to application.");
5266 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5267 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5270 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5272 MMPLAYER_FREEIF(msg_param.data);
5274 return MM_ERROR_NONE;
5276 // no any supported codec case
5277 LOGW("not found any codec, posting error code to application.");
5279 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5280 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5281 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5283 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5284 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5287 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5289 MMPLAYER_FREEIF(msg_param.data);
5295 return MM_ERROR_NONE;
5299 __mmplayer_check_pipeline(mm_player_t *player)
5301 GstState element_state = GST_STATE_VOID_PENDING;
5302 GstState element_pending_state = GST_STATE_VOID_PENDING;
5304 int ret = MM_ERROR_NONE;
5306 if (!player->gapless.reconfigure)
5309 LOGW("pipeline is under construction.");
5311 MMPLAYER_PLAYBACK_LOCK(player);
5312 MMPLAYER_PLAYBACK_UNLOCK(player);
5314 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5316 /* wait for state transition */
5317 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5318 if (ret == GST_STATE_CHANGE_FAILURE)
5319 LOGE("failed to change pipeline state within %d sec", timeout);
5322 /* NOTE : it should be able to call 'stop' anytime*/
5324 _mmplayer_stop(MMHandleType hplayer)
5326 mm_player_t *player = (mm_player_t *)hplayer;
5327 int ret = MM_ERROR_NONE;
5331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5333 /* check current state */
5334 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5336 /* check pipline building state */
5337 __mmplayer_check_pipeline(player);
5338 __mmplayer_reset_gapless_state(player);
5340 /* NOTE : application should not wait for EOS after calling STOP */
5341 __mmplayer_cancel_eos_timer(player);
5344 player->seek_state = MMPLAYER_SEEK_NONE;
5347 ret = __mmplayer_gst_stop(player);
5349 if (ret != MM_ERROR_NONE)
5350 LOGE("failed to stop player.");
5358 _mmplayer_pause(MMHandleType hplayer)
5360 mm_player_t *player = (mm_player_t *)hplayer;
5361 gint64 pos_nsec = 0;
5362 gboolean async = FALSE;
5363 gint ret = MM_ERROR_NONE;
5367 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5369 /* check current state */
5370 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5372 /* check pipline building state */
5373 __mmplayer_check_pipeline(player);
5375 switch (MMPLAYER_CURRENT_STATE(player)) {
5376 case MM_PLAYER_STATE_READY:
5378 /* check prepare async or not.
5379 * In the case of streaming playback, it's recommned to avoid blocking wait.
5381 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5382 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5384 /* Changing back sync of rtspsrc to async */
5385 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5386 LOGD("async prepare working mode for rtsp");
5392 case MM_PLAYER_STATE_PLAYING:
5394 /* NOTE : store current point to overcome some bad operation
5395 *(returning zero when getting current position in paused state) of some
5398 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5399 LOGW("getting current position failed in paused");
5401 player->last_position = pos_nsec;
5403 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5404 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5405 This causes problem is position calculation during normal pause resume scenarios also.
5406 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5407 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5408 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5409 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5415 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5416 LOGD("doing async pause in case of ms buff src");
5420 /* pause pipeline */
5421 ret = __mmplayer_gst_pause(player, async);
5423 if (ret != MM_ERROR_NONE)
5424 LOGE("failed to pause player. ret : 0x%x", ret);
5426 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5427 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5428 LOGE("failed to update display_rotation");
5436 /* in case of streaming, pause could take long time.*/
5438 _mmplayer_abort_pause(MMHandleType hplayer)
5440 mm_player_t *player = (mm_player_t *)hplayer;
5441 int ret = MM_ERROR_NONE;
5445 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5447 player->pipeline->mainbin,
5448 MM_ERROR_PLAYER_NOT_INITIALIZED);
5450 LOGD("set the pipeline state to READY");
5452 /* set state to READY */
5453 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5454 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5455 if (ret != MM_ERROR_NONE) {
5456 LOGE("fail to change state to READY");
5457 return MM_ERROR_PLAYER_INTERNAL;
5460 LOGD("succeeded in changing state to READY");
5465 _mmplayer_resume(MMHandleType hplayer)
5467 mm_player_t *player = (mm_player_t *)hplayer;
5468 int ret = MM_ERROR_NONE;
5469 gboolean async = FALSE;
5473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5475 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5476 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5477 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5481 /* Changing back sync mode rtspsrc to async */
5482 LOGD("async resume for rtsp case");
5486 /* check current state */
5487 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5489 ret = __mmplayer_gst_resume(player, async);
5490 if (ret != MM_ERROR_NONE)
5491 LOGE("failed to resume player.");
5493 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5494 LOGD("force resume even during buffering");
5495 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5504 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5506 mm_player_t *player = (mm_player_t *)hplayer;
5507 gint64 pos_nsec = 0;
5508 int ret = MM_ERROR_NONE;
5510 signed long long start = 0, stop = 0;
5511 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5514 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5515 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5517 /* The sound of video is not supported under 0.0 and over 2.0. */
5518 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5519 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5522 _mmplayer_set_mute(hplayer, mute);
5524 if (player->playback_rate == rate)
5525 return MM_ERROR_NONE;
5527 /* If the position is reached at start potion during fast backward, EOS is posted.
5528 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5530 player->playback_rate = rate;
5532 current_state = MMPLAYER_CURRENT_STATE(player);
5534 if (current_state != MM_PLAYER_STATE_PAUSED)
5535 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5537 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5539 if ((current_state == MM_PLAYER_STATE_PAUSED)
5540 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5541 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5542 pos_nsec = player->last_position;
5547 stop = GST_CLOCK_TIME_NONE;
5549 start = GST_CLOCK_TIME_NONE;
5553 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5554 player->playback_rate,
5556 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5557 GST_SEEK_TYPE_SET, start,
5558 GST_SEEK_TYPE_SET, stop)) {
5559 LOGE("failed to set speed playback");
5560 return MM_ERROR_PLAYER_SEEK;
5563 LOGD("succeeded to set speed playback as %0.1f", rate);
5567 return MM_ERROR_NONE;;
5571 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5573 mm_player_t *player = (mm_player_t *)hplayer;
5574 int ret = MM_ERROR_NONE;
5578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5580 /* check pipline building state */
5581 __mmplayer_check_pipeline(player);
5583 ret = __mmplayer_gst_set_position(player, position, FALSE);
5591 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5593 mm_player_t *player = (mm_player_t *)hplayer;
5594 int ret = MM_ERROR_NONE;
5596 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5598 ret = __mmplayer_gst_get_position(player, position);
5604 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5606 mm_player_t *player = (mm_player_t *)hplayer;
5607 int ret = MM_ERROR_NONE;
5609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5610 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5612 if (g_strrstr(player->type, "video/mpegts"))
5613 __mmplayer_update_duration_value(player);
5615 *duration = player->duration;
5620 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5622 mm_player_t *player = (mm_player_t *)hplayer;
5623 int ret = MM_ERROR_NONE;
5625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5627 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5633 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5635 mm_player_t *player = (mm_player_t *)hplayer;
5636 int ret = MM_ERROR_NONE;
5640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5642 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5650 __mmplayer_is_midi_type(gchar *str_caps)
5652 if ((g_strrstr(str_caps, "audio/midi")) ||
5653 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5654 (g_strrstr(str_caps, "application/x-smaf")) ||
5655 (g_strrstr(str_caps, "audio/x-imelody")) ||
5656 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5657 (g_strrstr(str_caps, "audio/xmf")) ||
5658 (g_strrstr(str_caps, "audio/mxmf"))) {
5667 __mmplayer_is_only_mp3_type(gchar *str_caps)
5669 if (g_strrstr(str_caps, "application/x-id3") ||
5670 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5676 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5678 GstStructure *caps_structure = NULL;
5679 gint samplerate = 0;
5683 MMPLAYER_RETURN_IF_FAIL(player && caps);
5685 caps_structure = gst_caps_get_structure(caps, 0);
5687 /* set stream information */
5688 gst_structure_get_int(caps_structure, "rate", &samplerate);
5689 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5691 gst_structure_get_int(caps_structure, "channels", &channels);
5692 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5694 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5698 __mmplayer_update_content_type_info(mm_player_t *player)
5701 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5703 if (__mmplayer_is_midi_type(player->type)) {
5704 player->bypass_audio_effect = TRUE;
5708 if (!player->streamer) {
5709 LOGD("no need to check streaming type");
5713 if (g_strrstr(player->type, "application/x-hls")) {
5714 /* If it can't know exact type when it parses uri because of redirection case,
5715 * it will be fixed by typefinder or when doing autoplugging.
5717 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5718 player->streamer->is_adaptive_streaming = TRUE;
5719 } else if (g_strrstr(player->type, "application/dash+xml")) {
5720 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5721 player->streamer->is_adaptive_streaming = TRUE;
5724 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5725 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5726 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5728 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5729 if (player->streamer->is_adaptive_streaming)
5730 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5732 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5736 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5741 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5742 GstCaps *caps, gpointer data)
5744 mm_player_t *player = (mm_player_t *)data;
5749 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5751 /* store type string */
5752 MMPLAYER_FREEIF(player->type);
5753 player->type = gst_caps_to_string(caps);
5755 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5756 player, player->type, probability, gst_caps_get_size(caps));
5758 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5759 (g_strrstr(player->type, "audio/x-raw-int"))) {
5760 LOGE("not support media format");
5762 if (player->msg_posted == FALSE) {
5763 MMMessageParamType msg_param;
5764 memset(&msg_param, 0, sizeof(MMMessageParamType));
5766 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5767 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5769 /* don't post more if one was sent already */
5770 player->msg_posted = TRUE;
5775 __mmplayer_update_content_type_info(player);
5777 pad = gst_element_get_static_pad(tf, "src");
5779 LOGE("fail to get typefind src pad.");
5783 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5784 gboolean async = FALSE;
5785 LOGE("failed to autoplug %s", player->type);
5787 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5789 if (async && player->msg_posted == FALSE)
5790 __mmplayer_handle_missed_plugin(player);
5796 gst_object_unref(GST_OBJECT(pad));
5804 __mmplayer_gst_make_decodebin(mm_player_t *player)
5806 GstElement *decodebin = NULL;
5810 /* create decodebin */
5811 decodebin = gst_element_factory_make("decodebin", NULL);
5814 LOGE("fail to create decodebin");
5818 /* raw pad handling signal */
5819 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5820 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5822 /* no-more-pad pad handling signal */
5823 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5824 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5826 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5827 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5829 /* This signal is emitted when a pad for which there is no further possible
5830 decoding is added to the decodebin.*/
5831 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5832 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5834 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5835 before looking for any elements that can handle that stream.*/
5836 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5837 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5839 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5840 before looking for any elements that can handle that stream.*/
5841 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5842 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5844 /* This signal is emitted once decodebin has finished decoding all the data.*/
5845 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5846 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5848 /* This signal is emitted when a element is added to the bin.*/
5849 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5850 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5857 __mmplayer_gst_make_queue2(mm_player_t *player)
5859 GstElement *queue2 = NULL;
5860 gint64 dur_bytes = 0L;
5861 MMPlayerGstElement *mainbin = NULL;
5862 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5865 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5867 mainbin = player->pipeline->mainbin;
5869 queue2 = gst_element_factory_make("queue2", "queue2");
5871 LOGE("failed to create buffering queue element");
5875 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5876 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5878 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5880 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5881 * skip the pull mode(file or ring buffering) setting. */
5882 if (dur_bytes > 0) {
5883 if (!g_strrstr(player->type, "video/mpegts")) {
5884 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5885 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5891 __mm_player_streaming_set_queue2(player->streamer,
5895 (guint64)dur_bytes); /* no meaning at the moment */
5901 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5903 MMPlayerGstElement *mainbin = NULL;
5904 GstElement *decodebin = NULL;
5905 GstElement *queue2 = NULL;
5906 GstPad *sinkpad = NULL;
5907 GstPad *qsrcpad = NULL;
5910 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5912 mainbin = player->pipeline->mainbin;
5914 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5916 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5917 LOGW("need to check: muxed buffer is not null");
5920 queue2 = __mmplayer_gst_make_queue2(player);
5922 LOGE("failed to make queue2");
5926 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5927 LOGE("failed to add buffering queue");
5931 sinkpad = gst_element_get_static_pad(queue2, "sink");
5932 qsrcpad = gst_element_get_static_pad(queue2, "src");
5934 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5935 LOGE("failed to link [%s:%s]-[%s:%s]",
5936 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5940 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5941 LOGE("failed to sync queue2 state with parent");
5945 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5946 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5950 gst_object_unref(GST_OBJECT(sinkpad));
5954 /* create decodebin */
5955 decodebin = __mmplayer_gst_make_decodebin(player);
5957 LOGE("failed to make decodebin");
5961 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5962 LOGE("failed to add decodebin");
5966 /* to force caps on the decodebin element and avoid reparsing stuff by
5967 * typefind. It also avoids a deadlock in the way typefind activates pads in
5968 * the state change */
5969 g_object_set(decodebin, "sink-caps", caps, NULL);
5971 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5973 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5974 LOGE("failed to link [%s:%s]-[%s:%s]",
5975 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5979 gst_object_unref(GST_OBJECT(sinkpad));
5982 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5983 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5985 /* set decodebin property about buffer in streaming playback. *
5986 * in case of HLS/DASH, it does not need to have big buffer *
5987 * because it is kind of adaptive streaming. */
5988 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5989 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5990 gint high_percent = 0;
5992 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5993 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5995 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
5997 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
5999 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6000 "high-percent", high_percent,
6001 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6002 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6003 "max-size-buffers", 0, NULL); // disable or automatic
6006 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6007 LOGE("failed to sync decodebin state with parent");
6018 gst_object_unref(GST_OBJECT(sinkpad));
6021 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6022 * You need to explicitly set elements to the NULL state before
6023 * dropping the final reference, to allow them to clean up.
6025 gst_element_set_state(queue2, GST_STATE_NULL);
6027 /* And, it still has a parent "player".
6028 * You need to let the parent manage the object instead of unreffing the object directly.
6030 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6031 gst_object_unref(queue2);
6036 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6037 * You need to explicitly set elements to the NULL state before
6038 * dropping the final reference, to allow them to clean up.
6040 gst_element_set_state(decodebin, GST_STATE_NULL);
6042 /* And, it still has a parent "player".
6043 * You need to let the parent manage the object instead of unreffing the object directly.
6046 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6047 gst_object_unref(decodebin);
6055 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6059 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6060 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6062 LOGD("class : %s, mime : %s", factory_class, mime);
6064 /* add missing plugin */
6065 /* NOTE : msl should check missing plugin for image mime type.
6066 * Some motion jpeg clips can have playable audio track.
6067 * So, msl have to play audio after displaying popup written video format not supported.
6069 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6070 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6071 LOGD("not found demuxer");
6072 player->not_found_demuxer = TRUE;
6073 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6079 if (!g_strrstr(factory_class, "Demuxer")) {
6080 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6081 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6082 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6084 /* check that clip have multi tracks or not */
6085 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6086 LOGD("video plugin is already linked");
6088 LOGW("add VIDEO to missing plugin");
6089 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6090 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6092 } else if (g_str_has_prefix(mime, "audio")) {
6093 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6094 LOGD("audio plugin is already linked");
6096 LOGW("add AUDIO to missing plugin");
6097 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6098 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6106 return MM_ERROR_NONE;
6110 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6112 mm_player_t *player = (mm_player_t *)data;
6116 MMPLAYER_RETURN_IF_FAIL(player);
6118 /* remove fakesink. */
6119 if (!__mmplayer_gst_remove_fakesink(player,
6120 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6121 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6122 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6123 * source element are not same. To overcome this situation, this function will called
6124 * several places and several times. Therefore, this is not an error case.
6129 LOGD("[handle: %p] pipeline has completely constructed", player);
6131 if ((player->ini.async_start) &&
6132 (player->msg_posted == FALSE) &&
6133 (player->cmd >= MMPLAYER_COMMAND_START))
6134 __mmplayer_handle_missed_plugin(player);
6136 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6140 __mmplayer_check_profile(void)
6143 static int profile_tv = -1;
6145 if (__builtin_expect(profile_tv != -1, 1))
6148 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6149 switch (*profileName) {
6164 __mmplayer_get_next_uri(mm_player_t *player)
6166 MMPlayerParseProfile profile;
6168 guint num_of_list = 0;
6171 num_of_list = g_list_length(player->uri_info.uri_list);
6172 uri_idx = player->uri_info.uri_idx;
6174 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6175 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6176 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6178 LOGW("next uri does not exist");
6182 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6183 LOGE("failed to parse profile");
6187 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6188 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6189 LOGW("uri type is not supported(%d)", profile.uri_type);
6193 LOGD("success to find next uri %d", uri_idx);
6197 if (uri_idx == num_of_list) {
6198 LOGE("failed to find next uri");
6202 player->uri_info.uri_idx = uri_idx;
6203 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6205 if (mm_attrs_commit_all(player->attrs)) {
6206 LOGE("failed to commit");
6210 SECURE_LOGD("next playback uri: %s", uri);
6215 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6217 #define REPEAT_COUNT_INFINITELY -1
6218 #define REPEAT_COUNT_MIN 2
6220 MMHandleType attrs = 0;
6224 guint num_of_list = 0;
6225 int profile_tv = -1;
6229 LOGD("checking for gapless play option");
6231 if (player->pipeline->textbin) {
6232 LOGE("subtitle path is enabled. gapless play is not supported.");
6236 attrs = MMPLAYER_GET_ATTRS(player);
6238 LOGE("fail to get attributes.");
6242 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6244 /* gapless playback is not supported in case of video at TV profile. */
6245 profile_tv = __mmplayer_check_profile();
6246 if (profile_tv && video) {
6247 LOGW("not support video gapless playback");
6251 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6252 LOGE("failed to get play count");
6254 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6255 LOGE("failed to get gapless mode");
6257 /* check repeat count in case of audio */
6259 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6260 LOGW("gapless is disabled");
6264 num_of_list = g_list_length(player->uri_info.uri_list);
6266 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6268 if (num_of_list == 0) {
6269 /* audio looping path */
6270 if (count >= REPEAT_COUNT_MIN) {
6271 /* decrease play count */
6272 /* we succeeded to rewind. update play count and then wait for next EOS */
6274 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6275 /* commit attribute */
6276 if (mm_attrs_commit_all(attrs))
6277 LOGE("failed to commit attribute");
6279 } else if (count != REPEAT_COUNT_INFINITELY) {
6280 LOGD("there is no next uri and no repeat");
6283 LOGD("looping cnt %d", count);
6285 /* gapless playback path */
6286 if (!__mmplayer_get_next_uri(player)) {
6287 LOGE("failed to get next uri");
6294 LOGE("unable to play gapless path. EOS will be posted soon");
6299 __mmplayer_initialize_gapless_play(mm_player_t *player)
6305 player->smooth_streaming = FALSE;
6306 player->videodec_linked = 0;
6307 player->audiodec_linked = 0;
6308 player->textsink_linked = 0;
6309 player->is_external_subtitle_present = FALSE;
6310 player->is_external_subtitle_added_now = FALSE;
6311 player->not_supported_codec = MISSING_PLUGIN_NONE;
6312 player->can_support_codec = FOUND_PLUGIN_NONE;
6313 player->pending_seek.is_pending = false;
6314 player->pending_seek.pos = 0;
6315 player->msg_posted = FALSE;
6316 player->has_many_types = FALSE;
6317 player->no_more_pad = FALSE;
6318 player->not_found_demuxer = 0;
6319 player->seek_state = MMPLAYER_SEEK_NONE;
6320 player->is_subtitle_force_drop = FALSE;
6321 player->play_subtitle = FALSE;
6322 player->adjust_subtitle_pos = 0;
6324 player->total_bitrate = 0;
6325 player->total_maximum_bitrate = 0;
6327 __mmplayer_track_initialize(player);
6328 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6330 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6331 player->bitrate[i] = 0;
6332 player->maximum_bitrate[i] = 0;
6335 if (player->v_stream_caps) {
6336 gst_caps_unref(player->v_stream_caps);
6337 player->v_stream_caps = NULL;
6340 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6342 /* clean found parsers */
6343 if (player->parsers) {
6344 GList *parsers = player->parsers;
6345 for (; parsers; parsers = g_list_next(parsers)) {
6346 gchar *name = parsers->data;
6347 MMPLAYER_FREEIF(name);
6349 g_list_free(player->parsers);
6350 player->parsers = NULL;
6353 /* clean found audio decoders */
6354 if (player->audio_decoders) {
6355 GList *a_dec = player->audio_decoders;
6356 for (; a_dec; a_dec = g_list_next(a_dec)) {
6357 gchar *name = a_dec->data;
6358 MMPLAYER_FREEIF(name);
6360 g_list_free(player->audio_decoders);
6361 player->audio_decoders = NULL;
6368 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6370 MMPlayerGstElement *mainbin = NULL;
6371 MMMessageParamType msg_param = {0,};
6372 GstElement *element = NULL;
6373 MMHandleType attrs = 0;
6375 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6379 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6380 LOGE("player is not initialized");
6384 mainbin = player->pipeline->mainbin;
6385 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6387 attrs = MMPLAYER_GET_ATTRS(player);
6389 LOGE("fail to get attributes");
6393 /* Initialize Player values */
6394 __mmplayer_initialize_gapless_play(player);
6396 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6398 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6399 LOGE("failed to parse profile");
6400 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6404 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6405 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6406 LOGE("dash or hls is not supportable");
6407 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6411 element = __mmplayer_gst_create_source(player);
6413 LOGE("no source element was created");
6417 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6418 LOGE("failed to add source element to pipeline");
6419 gst_object_unref(GST_OBJECT(element));
6424 /* take source element */
6425 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6426 mainbin[MMPLAYER_M_SRC].gst = element;
6430 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6431 if (player->streamer == NULL) {
6432 player->streamer = __mm_player_streaming_create();
6433 __mm_player_streaming_initialize(player->streamer, TRUE);
6436 elem_idx = MMPLAYER_M_TYPEFIND;
6437 element = gst_element_factory_make("typefind", "typefinder");
6438 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6439 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6441 elem_idx = MMPLAYER_M_AUTOPLUG;
6442 element = __mmplayer_gst_make_decodebin(player);
6445 /* check autoplug element is OK */
6447 LOGE("can not create element(%d)", elem_idx);
6451 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6452 LOGE("failed to add sinkbin to pipeline");
6453 gst_object_unref(GST_OBJECT(element));
6458 mainbin[elem_idx].id = elem_idx;
6459 mainbin[elem_idx].gst = element;
6461 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6462 LOGE("Failed to link src - autoplug(or typefind)");
6466 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6467 LOGE("Failed to change state of src element");
6471 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6472 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6473 LOGE("Failed to change state of decodebin");
6477 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6478 LOGE("Failed to change state of src element");
6483 player->gapless.stream_changed = TRUE;
6484 player->gapless.running = TRUE;
6490 MMPLAYER_PLAYBACK_UNLOCK(player);
6492 if (!player->msg_posted) {
6493 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6494 player->msg_posted = TRUE;
6501 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6503 mm_player_selector_t *selector = &player->selector[type];
6504 MMPlayerGstElement *sinkbin = NULL;
6505 enum MainElementID selectorId = MMPLAYER_M_NUM;
6506 enum MainElementID sinkId = MMPLAYER_M_NUM;
6507 GstPad *srcpad = NULL;
6508 GstPad *sinkpad = NULL;
6509 gboolean send_notice = FALSE;
6512 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6514 LOGD("type %d", type);
6517 case MM_PLAYER_TRACK_TYPE_AUDIO:
6518 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6519 sinkId = MMPLAYER_A_BIN;
6520 sinkbin = player->pipeline->audiobin;
6522 case MM_PLAYER_TRACK_TYPE_VIDEO:
6523 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6524 sinkId = MMPLAYER_V_BIN;
6525 sinkbin = player->pipeline->videobin;
6528 case MM_PLAYER_TRACK_TYPE_TEXT:
6529 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6530 sinkId = MMPLAYER_T_BIN;
6531 sinkbin = player->pipeline->textbin;
6534 LOGE("requested type is not supportable");
6539 if (player->pipeline->mainbin[selectorId].gst) {
6542 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6544 if (selector->event_probe_id != 0)
6545 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6546 selector->event_probe_id = 0;
6548 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6549 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6551 if (srcpad && sinkpad) {
6552 /* after getting drained signal there is no data flows, so no need to do pad_block */
6553 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6554 gst_pad_unlink(srcpad, sinkpad);
6556 /* send custom event to sink pad to handle it at video sink */
6558 LOGD("send custom event to sinkpad");
6559 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6560 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6561 gst_pad_send_event(sinkpad, event);
6565 gst_object_unref(sinkpad);
6568 gst_object_unref(srcpad);
6571 LOGD("selector release");
6573 /* release and unref requests pad from the selector */
6574 for (n = 0; n < selector->channels->len; n++) {
6575 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6576 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6578 g_ptr_array_set_size(selector->channels, 0);
6580 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6581 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6583 player->pipeline->mainbin[selectorId].gst = NULL;
6591 __mmplayer_deactivate_old_path(mm_player_t *player)
6594 MMPLAYER_RETURN_IF_FAIL(player);
6596 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6597 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6598 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6599 LOGE("deactivate selector error");
6603 __mmplayer_track_destroy(player);
6604 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6606 if (player->streamer) {
6607 __mm_player_streaming_initialize(player->streamer, FALSE);
6608 __mm_player_streaming_destroy(player->streamer);
6609 player->streamer = NULL;
6612 MMPLAYER_PLAYBACK_LOCK(player);
6613 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6620 if (!player->msg_posted) {
6621 MMMessageParamType msg = {0,};
6624 msg.code = MM_ERROR_PLAYER_INTERNAL;
6625 LOGE("gapless_uri_play> deactivate error");
6627 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6628 player->msg_posted = TRUE;
6634 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6636 int result = MM_ERROR_NONE;
6637 mm_player_t *player = (mm_player_t *)hplayer;
6640 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6642 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6643 if (mm_attrs_commit_all(player->attrs)) {
6644 LOGE("failed to commit the original uri.");
6645 result = MM_ERROR_PLAYER_INTERNAL;
6647 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6648 LOGE("failed to add the original uri in the uri list.");
6656 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6658 mm_player_t *player = (mm_player_t *)hplayer;
6659 guint num_of_list = 0;
6663 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6664 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6666 if (player->pipeline && player->pipeline->textbin) {
6667 LOGE("subtitle path is enabled.");
6668 return MM_ERROR_PLAYER_INVALID_STATE;
6671 num_of_list = g_list_length(player->uri_info.uri_list);
6673 if (is_first_path) {
6674 if (num_of_list == 0) {
6675 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6676 LOGD("add original path : %s", uri);
6678 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6679 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6681 LOGD("change original path : %s", uri);
6684 MMHandleType attrs = 0;
6685 attrs = MMPLAYER_GET_ATTRS(player);
6687 if (num_of_list == 0) {
6688 char *original_uri = NULL;
6691 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6693 if (!original_uri) {
6694 LOGE("there is no original uri.");
6695 return MM_ERROR_PLAYER_INVALID_STATE;
6698 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6699 player->uri_info.uri_idx = 0;
6701 LOGD("add original path at first : %s", original_uri);
6705 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6706 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6710 return MM_ERROR_NONE;
6714 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6716 mm_player_t *player = (mm_player_t *)hplayer;
6717 char *next_uri = NULL;
6718 guint num_of_list = 0;
6721 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6723 num_of_list = g_list_length(player->uri_info.uri_list);
6725 if (num_of_list > 0) {
6726 gint uri_idx = player->uri_info.uri_idx;
6728 if (uri_idx < num_of_list-1)
6733 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6734 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6736 *uri = g_strdup(next_uri);
6740 return MM_ERROR_NONE;
6744 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6745 GstCaps *caps, gpointer data)
6747 mm_player_t *player = (mm_player_t *)data;
6748 const gchar *klass = NULL;
6749 const gchar *mime = NULL;
6750 gchar *caps_str = NULL;
6752 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6753 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6754 caps_str = gst_caps_to_string(caps);
6756 LOGW("unknown type of caps : %s from %s",
6757 caps_str, GST_ELEMENT_NAME(elem));
6759 MMPLAYER_FREEIF(caps_str);
6761 /* There is no available codec. */
6762 __mmplayer_check_not_supported_codec(player, klass, mime);
6766 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6767 GstCaps *caps, gpointer data)
6769 mm_player_t *player = (mm_player_t *)data;
6770 const char *mime = NULL;
6771 gboolean ret = TRUE;
6773 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6774 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6776 if (g_str_has_prefix(mime, "audio")) {
6777 GstStructure *caps_structure = NULL;
6778 gint samplerate = 0;
6780 gchar *caps_str = NULL;
6782 caps_structure = gst_caps_get_structure(caps, 0);
6783 gst_structure_get_int(caps_structure, "rate", &samplerate);
6784 gst_structure_get_int(caps_structure, "channels", &channels);
6786 if ((channels > 0 && samplerate == 0)) {
6787 LOGD("exclude audio...");
6791 caps_str = gst_caps_to_string(caps);
6792 /* set it directly because not sent by TAG */
6793 if (g_strrstr(caps_str, "mobile-xmf"))
6794 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6795 MMPLAYER_FREEIF(caps_str);
6796 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6797 MMMessageParamType msg_param;
6798 memset(&msg_param, 0, sizeof(MMMessageParamType));
6799 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6800 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6801 LOGD("video file is not supported on this device");
6803 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6804 LOGD("already video linked");
6807 LOGD("found new stream");
6814 __mmplayer_check_offload_path(mm_player_t *player)
6816 gboolean ret = FALSE;
6817 GstElementFactory *factory = NULL;
6820 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6822 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6823 /* FIXME : 1. need to consider the current audio output path and
6824 player have to know whether it support offload or not.
6825 2. could be added new condition about content length */
6826 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6827 if (!__mmplayer_is_only_mp3_type(player->type))
6830 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6834 LOGD("can setup the audio offload path");
6835 gst_object_unref(factory);
6844 static GstAutoplugSelectResult
6845 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6847 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6849 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6850 int audio_offload = 0;
6852 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6853 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6855 if (audio_offload && __mmplayer_check_offload_path(player)) {
6856 LOGD("expose audio path to build offload path");
6857 player->build_audio_offload = TRUE;
6858 /* update codec info */
6859 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6860 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6861 player->audiodec_linked = 1;
6863 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6867 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6869 LOGD("audio codec type: %d", codec_type);
6870 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6871 /* sw codec will be skipped */
6872 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6873 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6874 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6875 ret = GST_AUTOPLUG_SELECT_SKIP;
6879 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6880 /* hw codec will be skipped */
6881 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6882 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6883 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6884 ret = GST_AUTOPLUG_SELECT_SKIP;
6889 /* set stream information */
6890 if (!player->audiodec_linked)
6891 __mmplayer_set_audio_attrs(player, caps);
6893 /* update codec info */
6894 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6895 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6896 player->audiodec_linked = 1;
6898 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6900 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6902 LOGD("video codec type: %d", codec_type);
6903 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6904 /* sw codec is skipped */
6905 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6906 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6907 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6908 ret = GST_AUTOPLUG_SELECT_SKIP;
6912 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6913 /* hw codec is skipped */
6914 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6915 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6916 ret = GST_AUTOPLUG_SELECT_SKIP;
6921 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6922 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6924 /* mark video decoder for acquire */
6925 if (player->video_decoder_resource == NULL) {
6926 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6927 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6928 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6929 &player->video_decoder_resource)
6930 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6931 LOGE("could not mark video_decoder resource for acquire");
6932 ret = GST_AUTOPLUG_SELECT_SKIP;
6936 LOGW("video decoder resource is already acquired, skip it.");
6937 ret = GST_AUTOPLUG_SELECT_SKIP;
6941 player->interrupted_by_resource = FALSE;
6942 /* acquire resources for video playing */
6943 if (mm_resource_manager_commit(player->resource_manager)
6944 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6945 LOGE("could not acquire resources for video decoding");
6946 ret = GST_AUTOPLUG_SELECT_SKIP;
6951 /* update codec info */
6952 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6953 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6954 player->videodec_linked = 1;
6962 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6963 GstCaps *caps, GstElementFactory *factory, gpointer data)
6965 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6966 mm_player_t *player = (mm_player_t *)data;
6968 gchar *factory_name = NULL;
6969 gchar *caps_str = NULL;
6970 const gchar *klass = NULL;
6973 factory_name = GST_OBJECT_NAME(factory);
6974 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6975 caps_str = gst_caps_to_string(caps);
6977 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6979 /* store type string */
6980 if (player->type == NULL) {
6981 player->type = gst_caps_to_string(caps);
6982 __mmplayer_update_content_type_info(player);
6985 /* filtering exclude keyword */
6986 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6987 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6988 LOGW("skipping [%s] by exculde keyword [%s]",
6989 factory_name, player->ini.exclude_element_keyword[idx]);
6991 result = GST_AUTOPLUG_SELECT_SKIP;
6996 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
6997 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
6998 LOGW("skipping [%s] by unsupported codec keyword [%s]",
6999 factory_name, player->ini.unsupported_codec_keyword[idx]);
7000 result = GST_AUTOPLUG_SELECT_SKIP;
7005 /* exclude webm format */
7006 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7007 * because webm format is not supportable.
7008 * If webm is disabled in "autoplug-continue", there is no state change
7009 * failure or error because the decodebin will expose the pad directly.
7010 * It make MSL invoke _prepare_async_callback.
7011 * So, we need to disable webm format in "autoplug-select" */
7012 if (caps_str && strstr(caps_str, "webm")) {
7013 LOGW("webm is not supported");
7014 result = GST_AUTOPLUG_SELECT_SKIP;
7018 /* check factory class for filtering */
7019 /* NOTE : msl don't need to use image plugins.
7020 * So, those plugins should be skipped for error handling.
7022 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7023 LOGD("skipping [%s] by not required", factory_name);
7024 result = GST_AUTOPLUG_SELECT_SKIP;
7028 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7029 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7030 // TO CHECK : subtitle if needed, add subparse exception.
7031 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7032 result = GST_AUTOPLUG_SELECT_SKIP;
7036 if (g_strrstr(factory_name, "mpegpsdemux")) {
7037 LOGD("skipping PS container - not support");
7038 result = GST_AUTOPLUG_SELECT_SKIP;
7042 if (g_strrstr(factory_name, "mssdemux"))
7043 player->smooth_streaming = TRUE;
7045 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7046 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7049 GstStructure *str = NULL;
7050 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7052 /* don't make video because of not required */
7053 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7054 (!player->set_mode.media_packet_video_stream)) {
7055 LOGD("no need video decoding, expose pad");
7056 result = GST_AUTOPLUG_SELECT_EXPOSE;
7060 /* get w/h for omx state-tune */
7061 /* FIXME: deprecated? */
7062 str = gst_caps_get_structure(caps, 0);
7063 gst_structure_get_int(str, "width", &width);
7066 if (player->v_stream_caps) {
7067 gst_caps_unref(player->v_stream_caps);
7068 player->v_stream_caps = NULL;
7071 player->v_stream_caps = gst_caps_copy(caps);
7072 LOGD("take caps for video state tune");
7073 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7077 if (g_strrstr(klass, "Codec/Decoder")) {
7078 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7079 if (result != GST_AUTOPLUG_SELECT_TRY) {
7080 LOGW("skip add decoder");
7086 MMPLAYER_FREEIF(caps_str);
7092 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7095 //mm_player_t *player = (mm_player_t *)data;
7096 GstCaps *caps = NULL;
7098 LOGD("[Decodebin2] pad-removed signal");
7100 caps = gst_pad_query_caps(new_pad, NULL);
7102 LOGW("query caps is NULL");
7106 gchar *caps_str = NULL;
7107 caps_str = gst_caps_to_string(caps);
7109 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7111 MMPLAYER_FREEIF(caps_str);
7112 gst_caps_unref(caps);
7116 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7118 mm_player_t *player = (mm_player_t *)data;
7119 GstIterator *iter = NULL;
7120 GValue item = { 0, };
7122 gboolean done = FALSE;
7123 gboolean is_all_drained = TRUE;
7126 MMPLAYER_RETURN_IF_FAIL(player);
7128 LOGD("__mmplayer_gst_decode_drained");
7130 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7131 LOGW("Fail to get cmd lock");
7135 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7136 !__mmplayer_verify_gapless_play_path(player)) {
7137 LOGD("decoding is finished.");
7138 __mmplayer_reset_gapless_state(player);
7139 MMPLAYER_CMD_UNLOCK(player);
7143 player->gapless.reconfigure = TRUE;
7145 /* check decodebin src pads whether they received EOS or not */
7146 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7149 switch (gst_iterator_next(iter, &item)) {
7150 case GST_ITERATOR_OK:
7151 pad = g_value_get_object(&item);
7152 if (pad && !GST_PAD_IS_EOS(pad)) {
7153 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7154 is_all_drained = FALSE;
7157 g_value_reset(&item);
7159 case GST_ITERATOR_RESYNC:
7160 gst_iterator_resync(iter);
7162 case GST_ITERATOR_ERROR:
7163 case GST_ITERATOR_DONE:
7168 g_value_unset(&item);
7169 gst_iterator_free(iter);
7171 if (!is_all_drained) {
7172 LOGD("Wait util the all pads get EOS.");
7173 MMPLAYER_CMD_UNLOCK(player);
7178 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7179 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7181 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7182 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7183 __mmplayer_deactivate_old_path(player);
7184 MMPLAYER_CMD_UNLOCK(player);
7190 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7192 mm_player_t *player = (mm_player_t *)data;
7193 const gchar *klass = NULL;
7194 gchar *factory_name = NULL;
7196 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7197 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7199 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7201 if (__mmplayer_add_dump_buffer_probe(player, element))
7202 LOGD("add buffer probe");
7205 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7206 gchar *selected = NULL;
7207 selected = g_strdup(GST_ELEMENT_NAME(element));
7208 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7212 if (g_strrstr(klass, "Parser")) {
7213 gchar *selected = NULL;
7215 selected = g_strdup(factory_name);
7216 player->parsers = g_list_append(player->parsers, selected);
7219 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7220 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7221 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7223 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7224 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7226 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7227 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7228 "max-video-width", player->adaptive_info.limit.width,
7229 "max-video-height", player->adaptive_info.limit.height, NULL);
7231 } else if (g_strrstr(klass, "Demuxer")) {
7232 //LOGD("plugged element is demuxer. take it");
7233 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7234 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7237 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7238 int surface_type = 0;
7240 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7243 // to support trust-zone only
7244 if (g_strrstr(factory_name, "asfdemux")) {
7245 LOGD("set file-location %s", player->profile.uri);
7246 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7247 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7248 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7249 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7250 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7251 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7252 (__mmplayer_is_only_mp3_type(player->type))) {
7253 LOGD("[mpegaudioparse] set streaming pull mode.");
7254 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7256 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7257 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7260 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7261 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7262 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7264 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7265 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7267 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7268 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7269 (MMPLAYER_IS_DASH_STREAMING(player))) {
7270 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7271 __mm_player_streaming_set_multiqueue(player->streamer, element);
7272 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7281 __mmplayer_release_misc(mm_player_t *player)
7284 bool cur_mode = player->set_mode.rich_audio;
7287 MMPLAYER_RETURN_IF_FAIL(player);
7289 player->video_stream_cb = NULL;
7290 player->video_stream_cb_user_param = NULL;
7291 player->video_stream_prerolled = false;
7293 player->audio_stream_render_cb = NULL;
7294 player->audio_stream_cb_user_param = NULL;
7295 player->audio_stream_sink_sync = false;
7297 player->video_stream_changed_cb = NULL;
7298 player->video_stream_changed_cb_user_param = NULL;
7300 player->audio_stream_changed_cb = NULL;
7301 player->audio_stream_changed_cb_user_param = NULL;
7303 player->sent_bos = FALSE;
7304 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7306 player->seek_state = MMPLAYER_SEEK_NONE;
7308 player->total_bitrate = 0;
7309 player->total_maximum_bitrate = 0;
7311 player->not_found_demuxer = 0;
7313 player->last_position = 0;
7314 player->duration = 0;
7315 player->http_content_size = 0;
7316 player->not_supported_codec = MISSING_PLUGIN_NONE;
7317 player->can_support_codec = FOUND_PLUGIN_NONE;
7318 player->pending_seek.is_pending = false;
7319 player->pending_seek.pos = 0;
7320 player->msg_posted = FALSE;
7321 player->has_many_types = FALSE;
7322 player->is_subtitle_force_drop = FALSE;
7323 player->play_subtitle = FALSE;
7324 player->adjust_subtitle_pos = 0;
7325 player->last_multiwin_status = FALSE;
7326 player->has_closed_caption = FALSE;
7327 player->set_mode.media_packet_video_stream = false;
7328 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7329 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7331 player->set_mode.rich_audio = cur_mode;
7333 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7334 player->bitrate[i] = 0;
7335 player->maximum_bitrate[i] = 0;
7338 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7340 /* remove media stream cb(appsrc cb) */
7341 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7342 player->media_stream_buffer_status_cb[i] = NULL;
7343 player->media_stream_seek_data_cb[i] = NULL;
7344 player->buffer_cb_user_param[i] = NULL;
7345 player->seek_cb_user_param[i] = NULL;
7347 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7349 /* free memory related to audio effect */
7350 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7352 if (player->adaptive_info.var_list) {
7353 g_list_free_full(player->adaptive_info.var_list, g_free);
7354 player->adaptive_info.var_list = NULL;
7357 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7358 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7359 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7361 /* Reset video360 settings to their defaults in case if the pipeline is to be
7364 player->video360_metadata.is_spherical = -1;
7365 player->is_openal_plugin_used = FALSE;
7367 player->is_content_spherical = FALSE;
7368 player->is_video360_enabled = TRUE;
7369 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7370 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7371 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7372 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7373 player->video360_zoom = 1.0f;
7374 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7375 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7377 player->sound.rg_enable = false;
7379 __mmplayer_initialize_video_roi(player);
7384 __mmplayer_release_misc_post(mm_player_t *player)
7386 char *original_uri = NULL;
7389 /* player->pipeline is already released before. */
7391 MMPLAYER_RETURN_IF_FAIL(player);
7393 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7395 /* clean found parsers */
7396 if (player->parsers) {
7397 GList *parsers = player->parsers;
7398 for (; parsers; parsers = g_list_next(parsers)) {
7399 gchar *name = parsers->data;
7400 MMPLAYER_FREEIF(name);
7402 g_list_free(player->parsers);
7403 player->parsers = NULL;
7406 /* clean found audio decoders */
7407 if (player->audio_decoders) {
7408 GList *a_dec = player->audio_decoders;
7409 for (; a_dec; a_dec = g_list_next(a_dec)) {
7410 gchar *name = a_dec->data;
7411 MMPLAYER_FREEIF(name);
7413 g_list_free(player->audio_decoders);
7414 player->audio_decoders = NULL;
7417 /* clean the uri list except original uri */
7418 if (player->uri_info.uri_list) {
7419 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7421 if (player->attrs) {
7422 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7423 LOGD("restore original uri = %s", original_uri);
7425 if (mm_attrs_commit_all(player->attrs))
7426 LOGE("failed to commit the original uri.");
7429 GList *uri_list = player->uri_info.uri_list;
7430 for (; uri_list; uri_list = g_list_next(uri_list)) {
7431 gchar *uri = uri_list->data;
7432 MMPLAYER_FREEIF(uri);
7434 g_list_free(player->uri_info.uri_list);
7435 player->uri_info.uri_list = NULL;
7438 /* clear the audio stream buffer list */
7439 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7441 /* clear the video stream bo list */
7442 __mmplayer_video_stream_destroy_bo_list(player);
7443 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7445 if (player->profile.input_mem.buf) {
7446 free(player->profile.input_mem.buf);
7447 player->profile.input_mem.buf = NULL;
7449 player->profile.input_mem.len = 0;
7450 player->profile.input_mem.offset = 0;
7452 player->uri_info.uri_idx = 0;
7457 __mmplayer_check_subtitle(mm_player_t *player)
7459 MMHandleType attrs = 0;
7460 char *subtitle_uri = NULL;
7464 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7466 /* get subtitle attribute */
7467 attrs = MMPLAYER_GET_ATTRS(player);
7471 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7472 if (!subtitle_uri || !strlen(subtitle_uri))
7475 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7476 player->is_external_subtitle_present = TRUE;
7484 __mmplayer_cancel_eos_timer(mm_player_t *player)
7486 MMPLAYER_RETURN_IF_FAIL(player);
7488 if (player->eos_timer) {
7489 LOGD("cancel eos timer");
7490 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7491 player->eos_timer = 0;
7498 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7502 MMPLAYER_RETURN_IF_FAIL(player);
7503 MMPLAYER_RETURN_IF_FAIL(sink);
7505 player->sink_elements = g_list_append(player->sink_elements, sink);
7511 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7515 MMPLAYER_RETURN_IF_FAIL(player);
7516 MMPLAYER_RETURN_IF_FAIL(sink);
7518 player->sink_elements = g_list_remove(player->sink_elements, sink);
7524 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7525 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7527 MMPlayerSignalItem *item = NULL;
7530 MMPLAYER_RETURN_IF_FAIL(player);
7532 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7533 LOGE("invalid signal type [%d]", type);
7537 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7539 LOGE("cannot connect signal [%s]", signal);
7544 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7545 player->signals[type] = g_list_append(player->signals[type], item);
7551 /* NOTE : be careful with calling this api. please refer to below glib comment
7552 * glib comment : Note that there is a bug in GObject that makes this function much
7553 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7554 * will no longer be called, but, the signal handler is not currently disconnected.
7555 * If the instance is itself being freed at the same time than this doesn't matter,
7556 * since the signal will automatically be removed, but if instance persists,
7557 * then the signal handler will leak. You should not remove the signal yourself
7558 * because in a future versions of GObject, the handler will automatically be
7561 * It's possible to work around this problem in a way that will continue to work
7562 * with future versions of GObject by checking that the signal handler is still
7563 * connected before disconnected it:
7565 * if (g_signal_handler_is_connected(instance, id))
7566 * g_signal_handler_disconnect(instance, id);
7569 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7571 GList *sig_list = NULL;
7572 MMPlayerSignalItem *item = NULL;
7576 MMPLAYER_RETURN_IF_FAIL(player);
7578 LOGD("release signals type : %d", type);
7580 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7581 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7582 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7583 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7584 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7585 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7589 sig_list = player->signals[type];
7591 for (; sig_list; sig_list = sig_list->next) {
7592 item = sig_list->data;
7594 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7595 if (g_signal_handler_is_connected(item->obj, item->sig))
7596 g_signal_handler_disconnect(item->obj, item->sig);
7599 MMPLAYER_FREEIF(item);
7602 g_list_free(player->signals[type]);
7603 player->signals[type] = NULL;
7611 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7613 mm_player_t *player = 0;
7614 int prev_display_surface_type = 0;
7615 void *prev_display_overlay = NULL;
7619 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7620 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7622 player = MM_PLAYER_CAST(handle);
7624 /* check video sinkbin is created */
7625 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7626 LOGE("Videosink is already created");
7627 return MM_ERROR_NONE;
7630 LOGD("videosink element is not yet ready");
7632 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7633 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7635 return MM_ERROR_INVALID_ARGUMENT;
7638 /* load previous attributes */
7639 if (player->attrs) {
7640 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7641 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7642 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7643 if (prev_display_surface_type == surface_type) {
7644 LOGD("incoming display surface type is same as previous one, do nothing..");
7646 return MM_ERROR_NONE;
7649 LOGE("failed to load attributes");
7651 return MM_ERROR_PLAYER_INTERNAL;
7654 /* videobin is not created yet, so we just set attributes related to display surface */
7655 LOGD("store display attribute for given surface type(%d)", surface_type);
7656 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7657 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7658 if (mm_attrs_commit_all(player->attrs)) {
7659 LOGE("failed to commit attribute");
7661 return MM_ERROR_PLAYER_INTERNAL;
7665 return MM_ERROR_NONE;
7668 /* Note : if silent is true, then subtitle would not be displayed. :*/
7670 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7672 mm_player_t *player = (mm_player_t *)hplayer;
7676 /* check player handle */
7677 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7679 player->set_mode.subtitle_off = silent;
7681 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7685 return MM_ERROR_NONE;
7689 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7691 MMPlayerGstElement *mainbin = NULL;
7692 MMPlayerGstElement *textbin = NULL;
7693 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7694 GstState current_state = GST_STATE_VOID_PENDING;
7695 GstState element_state = GST_STATE_VOID_PENDING;
7696 GstState element_pending_state = GST_STATE_VOID_PENDING;
7698 GstEvent *event = NULL;
7699 int result = MM_ERROR_NONE;
7701 GstClock *curr_clock = NULL;
7702 GstClockTime base_time, start_time, curr_time;
7707 /* check player handle */
7708 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7710 player->pipeline->mainbin &&
7711 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7713 mainbin = player->pipeline->mainbin;
7714 textbin = player->pipeline->textbin;
7716 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7718 // sync clock with current pipeline
7719 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7720 curr_time = gst_clock_get_time(curr_clock);
7722 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7723 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7725 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7726 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7728 if (current_state > GST_STATE_READY) {
7729 // sync state with current pipeline
7730 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7731 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7732 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7734 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7735 if (GST_STATE_CHANGE_FAILURE == ret) {
7736 LOGE("fail to state change.");
7737 result = MM_ERROR_PLAYER_INTERNAL;
7741 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7742 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7745 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7746 gst_object_unref(curr_clock);
7749 // seek to current position
7750 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7751 result = MM_ERROR_PLAYER_INVALID_STATE;
7752 LOGE("gst_element_query_position failed, invalid state");
7756 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7757 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);
7759 __mmplayer_gst_send_event_to_sink(player, event);
7761 result = MM_ERROR_PLAYER_INTERNAL;
7762 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7766 /* sync state with current pipeline */
7767 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7768 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7769 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7771 return MM_ERROR_NONE;
7774 /* release text pipeline resource */
7775 player->textsink_linked = 0;
7777 /* release signal */
7778 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7780 /* release textbin with it's childs */
7781 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7782 MMPLAYER_FREEIF(player->pipeline->textbin);
7783 player->pipeline->textbin = NULL;
7785 /* release subtitle elem */
7786 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7787 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7793 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7795 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7796 GstState current_state = GST_STATE_VOID_PENDING;
7798 MMHandleType attrs = 0;
7799 MMPlayerGstElement *mainbin = NULL;
7800 MMPlayerGstElement *textbin = NULL;
7802 gchar *subtitle_uri = NULL;
7803 int result = MM_ERROR_NONE;
7804 const gchar *charset = NULL;
7808 /* check player handle */
7809 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7811 player->pipeline->mainbin &&
7812 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7813 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7815 mainbin = player->pipeline->mainbin;
7816 textbin = player->pipeline->textbin;
7818 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7819 if (current_state < GST_STATE_READY) {
7820 result = MM_ERROR_PLAYER_INVALID_STATE;
7821 LOGE("Pipeline is not in proper state");
7825 attrs = MMPLAYER_GET_ATTRS(player);
7827 LOGE("cannot get content attribute");
7828 result = MM_ERROR_PLAYER_INTERNAL;
7832 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7833 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7834 LOGE("subtitle uri is not proper filepath");
7835 result = MM_ERROR_PLAYER_INVALID_URI;
7839 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7840 LOGE("failed to get storage info of subtitle path");
7841 result = MM_ERROR_PLAYER_INVALID_URI;
7845 LOGD("old subtitle file path is [%s]", subtitle_uri);
7846 LOGD("new subtitle file path is [%s]", filepath);
7848 if (!strcmp(filepath, subtitle_uri)) {
7849 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7852 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7853 if (mm_attrs_commit_all(player->attrs)) {
7854 LOGE("failed to commit.");
7859 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7860 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7861 player->subtitle_language_list = NULL;
7862 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7864 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7865 if (ret != GST_STATE_CHANGE_SUCCESS) {
7866 LOGE("failed to change state of textbin to READY");
7867 result = MM_ERROR_PLAYER_INTERNAL;
7871 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7872 if (ret != GST_STATE_CHANGE_SUCCESS) {
7873 LOGE("failed to change state of subparse to READY");
7874 result = MM_ERROR_PLAYER_INTERNAL;
7878 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7879 if (ret != GST_STATE_CHANGE_SUCCESS) {
7880 LOGE("failed to change state of filesrc to READY");
7881 result = MM_ERROR_PLAYER_INTERNAL;
7885 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7887 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7889 charset = util_get_charset(filepath);
7891 LOGD("detected charset is %s", charset);
7892 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7895 result = _mmplayer_sync_subtitle_pipeline(player);
7902 /* API to switch between external subtitles */
7904 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7906 int result = MM_ERROR_NONE;
7907 mm_player_t *player = (mm_player_t *)hplayer;
7912 /* check player handle */
7913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7915 /* filepath can be null in idle state */
7917 /* check file path */
7918 if ((path = strstr(filepath, "file://")))
7919 result = util_exist_file_path(path + 7);
7921 result = util_exist_file_path(filepath);
7923 if (result != MM_ERROR_NONE) {
7924 LOGE("invalid subtitle path 0x%X", result);
7925 return result; /* file not found or permission denied */
7929 if (!player->pipeline) {
7931 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7932 if (mm_attrs_commit_all(player->attrs)) {
7933 LOGE("failed to commit"); /* subtitle path will not be created */
7934 return MM_ERROR_PLAYER_INTERNAL;
7937 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7938 /* check filepath */
7939 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7941 if (!__mmplayer_check_subtitle(player)) {
7942 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7943 if (mm_attrs_commit_all(player->attrs)) {
7944 LOGE("failed to commit");
7945 return MM_ERROR_PLAYER_INTERNAL;
7948 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7949 LOGE("fail to create text pipeline");
7950 return MM_ERROR_PLAYER_INTERNAL;
7953 result = _mmplayer_sync_subtitle_pipeline(player);
7955 result = __mmplayer_change_external_subtitle_language(player, filepath);
7958 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7959 player->is_external_subtitle_added_now = TRUE;
7961 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7962 if (!player->subtitle_language_list) {
7963 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7964 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7965 LOGW("subtitle language list is not updated yet");
7967 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7975 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7977 int result = MM_ERROR_NONE;
7978 gchar *change_pad_name = NULL;
7979 GstPad *sinkpad = NULL;
7980 MMPlayerGstElement *mainbin = NULL;
7981 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7982 GstCaps *caps = NULL;
7983 gint total_track_num = 0;
7987 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7988 MM_ERROR_PLAYER_NOT_INITIALIZED);
7990 LOGD("Change Track(%d) to %d", type, index);
7992 mainbin = player->pipeline->mainbin;
7994 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7995 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7996 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
7997 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
7999 /* Changing Video Track is not supported. */
8000 LOGE("Track Type Error");
8004 if (mainbin[elem_idx].gst == NULL) {
8005 result = MM_ERROR_PLAYER_NO_OP;
8006 LOGD("Req track doesn't exist");
8010 total_track_num = player->selector[type].total_track_num;
8011 if (total_track_num <= 0) {
8012 result = MM_ERROR_PLAYER_NO_OP;
8013 LOGD("Language list is not available");
8017 if ((index < 0) || (index >= total_track_num)) {
8018 result = MM_ERROR_INVALID_ARGUMENT;
8019 LOGD("Not a proper index : %d", index);
8023 /*To get the new pad from the selector*/
8024 change_pad_name = g_strdup_printf("sink_%u", index);
8025 if (change_pad_name == NULL) {
8026 result = MM_ERROR_PLAYER_INTERNAL;
8027 LOGD("Pad does not exists");
8031 LOGD("new active pad name: %s", change_pad_name);
8033 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8034 if (sinkpad == NULL) {
8035 LOGD("sinkpad is NULL");
8036 result = MM_ERROR_PLAYER_INTERNAL;
8040 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8041 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8043 caps = gst_pad_get_current_caps(sinkpad);
8044 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8047 gst_object_unref(sinkpad);
8049 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8050 __mmplayer_set_audio_attrs(player, caps);
8053 MMPLAYER_FREEIF(change_pad_name);
8058 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8060 int result = MM_ERROR_NONE;
8061 mm_player_t *player = NULL;
8062 MMPlayerGstElement *mainbin = NULL;
8064 gint current_active_index = 0;
8066 GstState current_state = GST_STATE_VOID_PENDING;
8067 GstEvent *event = NULL;
8072 player = (mm_player_t *)hplayer;
8073 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8075 if (!player->pipeline) {
8076 LOGE("Track %d pre setting -> %d", type, index);
8078 player->selector[type].active_pad_index = index;
8082 mainbin = player->pipeline->mainbin;
8084 current_active_index = player->selector[type].active_pad_index;
8086 /*If index is same as running index no need to change the pad*/
8087 if (current_active_index == index)
8090 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8091 result = MM_ERROR_PLAYER_INVALID_STATE;
8095 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8096 if (current_state < GST_STATE_PAUSED) {
8097 result = MM_ERROR_PLAYER_INVALID_STATE;
8098 LOGW("Pipeline not in porper state");
8102 result = __mmplayer_change_selector_pad(player, type, index);
8103 if (result != MM_ERROR_NONE) {
8104 LOGE("change selector pad error");
8108 player->selector[type].active_pad_index = index;
8110 if (current_state == GST_STATE_PLAYING) {
8111 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8112 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8113 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8115 __mmplayer_gst_send_event_to_sink(player, event);
8117 result = MM_ERROR_PLAYER_INTERNAL;
8127 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8129 mm_player_t *player = (mm_player_t *)hplayer;
8133 /* check player handle */
8134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8136 *silent = player->set_mode.subtitle_off;
8138 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8142 return MM_ERROR_NONE;
8146 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8148 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8149 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8151 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8152 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8156 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8157 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8158 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8159 mm_player_dump_t *dump_s;
8160 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8161 if (dump_s == NULL) {
8162 LOGE("malloc fail");
8166 dump_s->dump_element_file = NULL;
8167 dump_s->dump_pad = NULL;
8168 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8170 if (dump_s->dump_pad) {
8171 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8172 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]);
8173 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8174 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);
8175 /* add list for removed buffer probe and close FILE */
8176 player->dump_list = g_list_append(player->dump_list, dump_s);
8177 LOGD("%s sink pad added buffer probe for dump", factory_name);
8180 MMPLAYER_FREEIF(dump_s);
8181 LOGE("failed to get %s sink pad added", factory_name);
8188 static GstPadProbeReturn
8189 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8191 FILE *dump_data = (FILE *)u_data;
8193 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8194 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8196 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8198 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8200 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8202 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8204 return GST_PAD_PROBE_OK;
8208 __mmplayer_release_dump_list(GList *dump_list)
8210 GList *d_list = dump_list;
8215 for (; d_list; d_list = g_list_next(d_list)) {
8216 mm_player_dump_t *dump_s = d_list->data;
8217 if (dump_s->dump_pad) {
8218 if (dump_s->probe_handle_id)
8219 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8221 if (dump_s->dump_element_file) {
8222 fclose(dump_s->dump_element_file);
8223 dump_s->dump_element_file = NULL;
8225 MMPLAYER_FREEIF(dump_s);
8227 g_list_free(dump_list);
8232 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8234 mm_player_t *player = (mm_player_t *)hplayer;
8238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8239 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8241 *exist = (bool)player->has_closed_caption;
8245 return MM_ERROR_NONE;
8249 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8253 // LOGD("unref internal gst buffer %p", buffer);
8254 gst_buffer_unref((GstBuffer *)buffer);
8261 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8263 mm_player_t *player = (mm_player_t *)hplayer;
8267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8268 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8270 if (MMPLAYER_IS_STREAMING(player))
8271 *timeout = (int)player->ini.live_state_change_timeout;
8273 *timeout = (int)player->ini.localplayback_state_change_timeout;
8275 LOGD("timeout = %d", *timeout);
8278 return MM_ERROR_NONE;
8282 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8284 mm_player_t *player = (mm_player_t *)hplayer;
8288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8289 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8291 *num = player->video_num_buffers;
8292 *extra_num = player->video_extra_num_buffers;
8294 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8297 return MM_ERROR_NONE;
8301 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8305 MMPLAYER_RETURN_IF_FAIL(player);
8307 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8309 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8310 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8311 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8312 player->storage_info[i].id = -1;
8313 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8315 if (path_type != MMPLAYER_PATH_MAX)
8324 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8326 int ret = MM_ERROR_NONE;
8327 mm_player_t *player = (mm_player_t *)hplayer;
8328 MMMessageParamType msg_param = {0, };
8331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8333 LOGW("state changed storage %d:%d", id, state);
8335 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8336 return MM_ERROR_NONE;
8338 /* FIXME: text path should be handled seperately. */
8339 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8340 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8341 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8342 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8343 LOGW("external storage is removed");
8345 if (player->msg_posted == FALSE) {
8346 memset(&msg_param, 0, sizeof(MMMessageParamType));
8347 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8348 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8349 player->msg_posted = TRUE;
8352 /* unrealize the player */
8353 ret = _mmplayer_unrealize(hplayer);
8354 if (ret != MM_ERROR_NONE)
8355 LOGE("failed to unrealize");
8363 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8365 int ret = MM_ERROR_NONE;
8366 mm_player_t *player = (mm_player_t *)hplayer;
8367 int idx = 0, total = 0;
8368 gchar *result = NULL, *tmp = NULL;
8371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8372 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8374 total = *num = g_list_length(player->adaptive_info.var_list);
8376 LOGW("There is no stream variant info.");
8380 result = g_strdup("");
8381 for (idx = 0 ; idx < total ; idx++) {
8382 VariantData *v_data = NULL;
8383 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8386 gchar data[64] = {0};
8387 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8389 tmp = g_strconcat(result, data, NULL);
8393 LOGW("There is no variant data in %d", idx);
8398 *var_info = (char *)result;
8400 LOGD("variant info %d:%s", *num, *var_info);
8406 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8408 int ret = MM_ERROR_NONE;
8409 mm_player_t *player = (mm_player_t *)hplayer;
8412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8414 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8416 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8417 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8418 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8420 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8421 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8422 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8423 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8425 /* FIXME: seek to current position for applying new variant limitation */
8434 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8436 int ret = MM_ERROR_NONE;
8437 mm_player_t *player = (mm_player_t *)hplayer;
8440 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8441 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8443 *bandwidth = player->adaptive_info.limit.bandwidth;
8444 *width = player->adaptive_info.limit.width;
8445 *height = player->adaptive_info.limit.height;
8447 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8454 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8456 int ret = MM_ERROR_NONE;
8457 mm_player_t *player = (mm_player_t *)hplayer;
8460 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8461 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8462 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8464 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8466 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8467 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8468 else /* live case */
8469 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8471 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8478 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8480 #define IDX_FIRST_SW_CODEC 0
8481 mm_player_t *player = (mm_player_t *)hplayer;
8482 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8483 MMHandleType attrs = 0;
8486 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8488 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8489 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8490 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8492 switch (stream_type) {
8493 case MM_PLAYER_STREAM_TYPE_AUDIO:
8494 /* to support audio codec selection, codec info have to be added in ini file as below.
8495 audio codec element hw = xxxx
8496 audio codec element sw = avdec */
8497 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8498 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8499 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8500 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8501 LOGE("There is no audio codec info for codec_type %d", codec_type);
8502 return MM_ERROR_PLAYER_NO_OP;
8505 case MM_PLAYER_STREAM_TYPE_VIDEO:
8506 /* to support video codec selection, codec info have to be added in ini file as below.
8507 video codec element hw = omx
8508 video codec element sw = avdec */
8509 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8510 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8511 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8512 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8513 LOGE("There is no video codec info for codec_type %d", codec_type);
8514 return MM_ERROR_PLAYER_NO_OP;
8518 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8519 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8523 LOGD("update %s codec_type to %d", attr_name, codec_type);
8525 attrs = MMPLAYER_GET_ATTRS(player);
8526 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8528 if (mm_attrs_commit_all(player->attrs)) {
8529 LOGE("failed to commit codec_type attributes");
8530 return MM_ERROR_PLAYER_INTERNAL;
8534 return MM_ERROR_NONE;
8538 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8540 mm_player_t *player = (mm_player_t *)hplayer;
8541 GstElement *rg_vol_element = NULL;
8545 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8547 player->sound.rg_enable = enabled;
8549 /* just hold rgvolume enable value if pipeline is not ready */
8550 if (!player->pipeline || !player->pipeline->audiobin) {
8551 LOGD("pipeline is not ready. holding rgvolume enable value");
8552 return MM_ERROR_NONE;
8555 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8557 if (!rg_vol_element) {
8558 LOGD("rgvolume element is not created");
8559 return MM_ERROR_PLAYER_INTERNAL;
8563 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8565 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8569 return MM_ERROR_NONE;
8573 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8575 mm_player_t *player = (mm_player_t *)hplayer;
8576 GstElement *rg_vol_element = NULL;
8577 gboolean enable = FALSE;
8581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8582 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8584 /* just hold enable_rg value if pipeline is not ready */
8585 if (!player->pipeline || !player->pipeline->audiobin) {
8586 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8587 *enabled = player->sound.rg_enable;
8588 return MM_ERROR_NONE;
8591 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8593 if (!rg_vol_element) {
8594 LOGD("rgvolume element is not created");
8595 return MM_ERROR_PLAYER_INTERNAL;
8598 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8599 *enabled = (bool)enable;
8603 return MM_ERROR_NONE;
8607 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8609 mm_player_t *player = (mm_player_t *)hplayer;
8610 MMHandleType attrs = 0;
8611 void *handle = NULL;
8612 int ret = MM_ERROR_NONE;
8616 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8618 attrs = MMPLAYER_GET_ATTRS(player);
8619 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8621 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8623 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8624 return MM_ERROR_PLAYER_INTERNAL;
8627 player->video_roi.scale_x = scale_x;
8628 player->video_roi.scale_y = scale_y;
8629 player->video_roi.scale_width = scale_width;
8630 player->video_roi.scale_height = scale_height;
8632 /* check video sinkbin is created */
8633 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8634 return MM_ERROR_NONE;
8636 if (!gst_video_overlay_set_video_roi_area(
8637 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8638 scale_x, scale_y, scale_width, scale_height))
8639 ret = MM_ERROR_PLAYER_INTERNAL;
8641 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8642 scale_x, scale_y, scale_width, scale_height);
8650 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8652 mm_player_t *player = (mm_player_t *)hplayer;
8653 int ret = MM_ERROR_NONE;
8657 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8658 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8660 *scale_x = player->video_roi.scale_x;
8661 *scale_y = player->video_roi.scale_y;
8662 *scale_width = player->video_roi.scale_width;
8663 *scale_height = player->video_roi.scale_height;
8665 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8666 *scale_x, *scale_y, *scale_width, *scale_height);
8672 __mmplayer_update_duration_value(mm_player_t *player)
8674 gboolean ret = FALSE;
8675 gint64 dur_nsec = 0;
8676 LOGD("try to update duration");
8678 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8679 player->duration = dur_nsec;
8680 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8684 if (player->duration < 0) {
8685 LOGW("duration is Non-Initialized !!!");
8686 player->duration = 0;
8689 /* update streaming service type */
8690 player->streaming_type = __mmplayer_get_stream_service_type(player);
8692 /* check duration is OK */
8693 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8694 /* FIXIT : find another way to get duration here. */
8695 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8701 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8703 /* update audio params
8704 NOTE : We need original audio params and it can be only obtained from src pad of audio
8705 decoder. Below code only valid when we are not using 'resampler' just before
8706 'audioconverter'. */
8707 GstCaps *caps_a = NULL;
8709 gint samplerate = 0, channels = 0;
8710 GstStructure *p = NULL;
8712 LOGD("try to update audio attrs");
8714 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8715 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8717 pad = gst_element_get_static_pad(
8718 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8721 LOGW("failed to get pad from audiosink");
8725 caps_a = gst_pad_get_current_caps(pad);
8727 LOGW("not ready to get audio caps");
8728 gst_object_unref(pad);
8732 p = gst_caps_get_structure(caps_a, 0);
8734 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8736 gst_structure_get_int(p, "rate", &samplerate);
8737 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8739 gst_structure_get_int(p, "channels", &channels);
8740 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8742 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8744 gst_caps_unref(caps_a);
8745 gst_object_unref(pad);
8751 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8753 LOGD("try to update video attrs");
8755 GstCaps *caps_v = NULL;
8759 GstStructure *p = NULL;
8761 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8762 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8764 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8766 LOGD("no videosink sink pad");
8770 caps_v = gst_pad_get_current_caps(pad);
8771 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8772 if (!caps_v && player->v_stream_caps) {
8773 caps_v = player->v_stream_caps;
8774 gst_caps_ref(caps_v);
8778 LOGD("no negitiated caps from videosink");
8779 gst_object_unref(pad);
8783 p = gst_caps_get_structure(caps_v, 0);
8784 gst_structure_get_int(p, "width", &width);
8785 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8787 gst_structure_get_int(p, "height", &height);
8788 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8790 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8792 SECURE_LOGD("width : %d height : %d", width, height);
8794 gst_caps_unref(caps_v);
8795 gst_object_unref(pad);
8798 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8799 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8806 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8808 gboolean ret = FALSE;
8809 guint64 data_size = 0;
8813 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8814 if (!player->duration)
8817 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8818 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8819 if (stat(path, &sb) == 0)
8820 data_size = (guint64)sb.st_size;
8822 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8823 data_size = player->http_content_size;
8826 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8829 guint64 bitrate = 0;
8830 guint64 msec_dur = 0;
8832 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8834 bitrate = data_size * 8 * 1000 / msec_dur;
8835 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8836 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8840 LOGD("player duration is less than 0");
8844 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8845 if (player->total_bitrate) {
8846 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8855 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8857 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8858 data->uri_type = uri_type;
8862 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8864 int ret = MM_ERROR_PLAYER_INVALID_URI;
8866 char *buffer = NULL;
8867 char *seperator = strchr(path, ',');
8868 char ext[100] = {0,}, size[100] = {0,};
8871 if ((buffer = strstr(path, "ext="))) {
8872 buffer += strlen("ext=");
8874 if (strlen(buffer)) {
8875 strncpy(ext, buffer, 99);
8877 if ((seperator = strchr(ext, ','))
8878 || (seperator = strchr(ext, ' '))
8879 || (seperator = strchr(ext, '\0'))) {
8880 seperator[0] = '\0';
8885 if ((buffer = strstr(path, "size="))) {
8886 buffer += strlen("size=");
8888 if (strlen(buffer) > 0) {
8889 strncpy(size, buffer, 99);
8891 if ((seperator = strchr(size, ','))
8892 || (seperator = strchr(size, ' '))
8893 || (seperator = strchr(size, '\0'))) {
8894 seperator[0] = '\0';
8897 mem_size = atoi(size);
8902 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8904 if (mem_size && param) {
8905 if (data->input_mem.buf)
8906 free(data->input_mem.buf);
8907 data->input_mem.buf = malloc(mem_size);
8909 if (data->input_mem.buf) {
8910 memcpy(data->input_mem.buf, param, mem_size);
8911 data->input_mem.len = mem_size;
8912 ret = MM_ERROR_NONE;
8914 LOGE("failed to alloc mem %d", mem_size);
8915 ret = MM_ERROR_PLAYER_INTERNAL;
8918 data->input_mem.offset = 0;
8919 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8926 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8928 gchar *location = NULL;
8931 int ret = MM_ERROR_NONE;
8933 if ((path = strstr(uri, "file://"))) {
8934 location = g_filename_from_uri(uri, NULL, &err);
8935 if (!location || (err != NULL)) {
8936 LOGE("Invalid URI '%s' for filesrc: %s", path,
8937 (err != NULL) ? err->message : "unknown error");
8941 MMPLAYER_FREEIF(location);
8943 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8944 return MM_ERROR_PLAYER_INVALID_URI;
8946 LOGD("path from uri: %s", location);
8949 path = (location != NULL) ? (location) : ((char *)uri);
8952 ret = util_exist_file_path(path);
8954 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8955 if (ret == MM_ERROR_NONE) {
8956 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8957 if (util_is_sdp_file(path)) {
8958 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8959 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8961 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8963 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8964 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8966 LOGE("invalid uri, could not play..");
8967 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8970 MMPLAYER_FREEIF(location);
8975 static MMPlayerVideoStreamDataType *
8976 __mmplayer_create_stream_from_pad(GstPad *pad)
8978 GstCaps *caps = NULL;
8979 GstStructure *structure = NULL;
8980 unsigned int fourcc = 0;
8981 const gchar *string_format = NULL;
8982 MMPlayerVideoStreamDataType *stream = NULL;
8984 MMPixelFormatType format;
8986 caps = gst_pad_get_current_caps(pad);
8988 LOGE("Caps is NULL.");
8992 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8993 structure = gst_caps_get_structure(caps, 0);
8994 gst_structure_get_int(structure, "width", &width);
8995 gst_structure_get_int(structure, "height", &height);
8996 string_format = gst_structure_get_string(structure, "format");
8998 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
8999 format = util_get_pixtype(fourcc);
9000 gst_caps_unref(caps);
9003 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9004 LOGE("Wrong condition!!");
9008 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9010 LOGE("failed to alloc mem for video data");
9014 stream->width = width;
9015 stream->height = height;
9016 stream->format = format;
9022 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9024 unsigned int pitch = 0;
9026 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9028 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9029 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9030 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9031 stream->stride[index] = pitch;
9032 stream->elevation[index] = stream->height;
9037 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9039 if (stream->format == MM_PIXEL_FORMAT_I420) {
9040 int ret = TBM_SURFACE_ERROR_NONE;
9041 tbm_surface_h surface;
9042 tbm_surface_info_s info;
9044 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9046 ret = tbm_surface_get_info(surface, &info);
9047 if (ret != TBM_SURFACE_ERROR_NONE) {
9048 tbm_surface_destroy(surface);
9052 tbm_surface_destroy(surface);
9053 stream->stride[0] = info.planes[0].stride;
9054 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9055 stream->stride[1] = info.planes[1].stride;
9056 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9057 stream->stride[2] = info.planes[2].stride;
9058 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9059 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9060 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9061 stream->stride[0] = stream->width * 4;
9062 stream->elevation[0] = stream->height;
9063 stream->bo_size = stream->stride[0] * stream->height;
9065 LOGE("Not support format %d", stream->format);
9073 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9075 tbm_bo_handle thandle;
9077 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9078 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9079 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9083 unsigned char *src = NULL;
9084 unsigned char *dest = NULL;
9085 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9087 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9089 LOGE("fail to gst_memory_map");
9093 if (!mapinfo.data) {
9094 LOGE("data pointer is wrong");
9098 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9099 if (!stream->bo[0]) {
9100 LOGE("Fail to tbm_bo_alloc!!");
9104 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9106 LOGE("thandle pointer is wrong");
9110 if (stream->format == MM_PIXEL_FORMAT_I420) {
9111 src_stride[0] = GST_ROUND_UP_4(stream->width);
9112 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9113 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9114 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9117 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9118 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9120 for (i = 0; i < 3; i++) {
9121 src = mapinfo.data + src_offset[i];
9122 dest = thandle.ptr + dest_offset[i];
9127 for (j = 0; j < stream->height >> k; j++) {
9128 memcpy(dest, src, stream->width>>k);
9129 src += src_stride[i];
9130 dest += stream->stride[i];
9133 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9134 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9136 LOGE("Not support format %d", stream->format);
9140 tbm_bo_unmap(stream->bo[0]);
9141 gst_memory_unmap(mem, &mapinfo);
9147 tbm_bo_unmap(stream->bo[0]);
9150 gst_memory_unmap(mem, &mapinfo);
9156 __mmplayer_set_pause_state(mm_player_t *player)
9158 if (player->sent_bos)
9161 /* rtsp case, get content attrs by GstMessage */
9162 if (MMPLAYER_IS_RTSP_STREAMING(player))
9165 /* it's first time to update all content attrs. */
9166 __mmplayer_update_content_attrs(player, ATTR_ALL);
9170 __mmplayer_set_playing_state(mm_player_t *player)
9172 gchar *audio_codec = NULL;
9174 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9175 /* initialize because auto resume is done well. */
9176 player->resumed_by_rewind = FALSE;
9177 player->playback_rate = 1.0;
9180 if (player->sent_bos)
9183 /* try to get content metadata */
9185 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9186 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9187 * legacy mmfw-player api
9189 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9191 if ((player->cmd == MMPLAYER_COMMAND_START)
9192 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9193 __mmplayer_handle_missed_plugin(player);
9196 /* check audio codec field is set or not
9197 * we can get it from typefinder or codec's caps.
9199 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9201 /* The codec format can't be sent for audio only case like amr, mid etc.
9202 * Because, parser don't make related TAG.
9203 * So, if it's not set yet, fill it with found data.
9206 if (g_strrstr(player->type, "audio/midi"))
9207 audio_codec = "MIDI";
9208 else if (g_strrstr(player->type, "audio/x-amr"))
9209 audio_codec = "AMR";
9210 else if (g_strrstr(player->type, "audio/mpeg")
9211 && !g_strrstr(player->type, "mpegversion= (int)1"))
9212 audio_codec = "AAC";
9214 audio_codec = "unknown";
9216 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9218 if (mm_attrs_commit_all(player->attrs))
9219 LOGE("failed to update attributes");
9221 LOGD("set audio codec type with caps");