4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
42 #include "mm_player_priv.h"
43 #include "mm_player_ini.h"
44 #include "mm_player_attrs.h"
45 #include "mm_player_capture.h"
46 #include "mm_player_utils.h"
47 #include "mm_player_tracks.h"
48 #include "mm_player_360.h"
49 #include "mm_player_gst.h"
51 #include <system_info.h>
52 #include <sound_manager.h>
53 #include <gst/allocators/gsttizenmemory.h>
54 #include <tbm_surface_internal.h>
56 /*===========================================================================================
58 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
60 ========================================================================================== */
62 /*---------------------------------------------------------------------------
63 | GLOBAL CONSTANT DEFINITIONS: |
64 ---------------------------------------------------------------------------*/
66 /*---------------------------------------------------------------------------
67 | IMPORTED VARIABLE DECLARATIONS: |
68 ---------------------------------------------------------------------------*/
70 /*---------------------------------------------------------------------------
71 | IMPORTED FUNCTION DECLARATIONS: |
72 ---------------------------------------------------------------------------*/
74 /*---------------------------------------------------------------------------
76 ---------------------------------------------------------------------------*/
77 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
78 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
80 #define MM_VOLUME_FACTOR_DEFAULT 1.0
81 #define MM_VOLUME_FACTOR_MIN 0
82 #define MM_VOLUME_FACTOR_MAX 1.0
84 /* Don't need to sleep for sound fadeout
85 * fadeout related fucntion will be deleted(Deprecated)
87 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
89 #define DEFAULT_PLAYBACK_RATE 1.0
90 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 /*---------------------------------------------------------------------------
107 | LOCAL CONSTANT DEFINITIONS: |
108 ---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------
111 | LOCAL DATA TYPE DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
113 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
114 We are defining our own and will be removed when it actually exposed */
116 GST_AUTOPLUG_SELECT_TRY,
117 GST_AUTOPLUG_SELECT_EXPOSE,
118 GST_AUTOPLUG_SELECT_SKIP
119 } GstAutoplugSelectResult;
121 /*---------------------------------------------------------------------------
122 | GLOBAL VARIABLE DEFINITIONS: |
123 ---------------------------------------------------------------------------*/
125 /*---------------------------------------------------------------------------
126 | LOCAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
128 static sound_stream_info_h stream_info;
130 /*---------------------------------------------------------------------------
131 | LOCAL FUNCTION PROTOTYPES: |
132 ---------------------------------------------------------------------------*/
133 static int __mmplayer_gst_create_pipeline(mm_player_t *player);
134 static int __mmplayer_gst_destroy_pipeline(mm_player_t *player);
135 static int __mmplayer_gst_create_text_pipeline(mm_player_t *player);
136 static int __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
137 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t *player);
138 static int __mmplayer_gst_create_text_sink_bin(mm_player_t *player);
140 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
141 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
142 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
143 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
144 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
145 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
146 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
147 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
148 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
149 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
150 static void __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps);
152 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_release_misc(mm_player_t *player);
154 static void __mmplayer_release_misc_post(mm_player_t *player);
155 static gboolean __mmplayer_init_gstreamer(mm_player_t *player);
156 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
158 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
159 static int __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index);
161 static gboolean __mmplayer_check_subtitle(mm_player_t *player);
162 static int __mmplayer_handle_missed_plugin(mm_player_t *player);
163 static int __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime);
164 static void __mmplayer_add_sink(mm_player_t *player, GstElement *sink);
165 static void __mmplayer_del_sink(mm_player_t *player, GstElement *sink);
166 static void __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type);
167 static gpointer __mmplayer_gapless_play_thread(gpointer data);
168 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
169 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
170 static void __mmplayer_release_dump_list(GList *dump_list);
171 static int __mmplayer_gst_realize(mm_player_t *player);
172 static int __mmplayer_gst_unrealize(mm_player_t *player);
173 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position);
174 static int __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param);
177 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
178 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
179 static void __mmplayer_check_pipeline(mm_player_t *player);
180 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
181 static void __mmplayer_deactivate_old_path(mm_player_t *player);
182 static int __mmplayer_gst_create_plain_text_elements(mm_player_t *player);
183 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
184 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
185 static void __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer);
186 static void __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type);
187 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
188 static gboolean __mmplayer_update_duration_value(mm_player_t *player);
189 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
190 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
193 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type);
194 static int __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param);
195 static int __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri);
197 static MMPlayerVideoStreamDataType *__mmplayer_create_stream_from_pad(GstPad *pad);
198 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
199 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
200 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
202 static void __mmplayer_set_pause_state(mm_player_t *player);
203 static void __mmplayer_set_playing_state(mm_player_t *player);
204 /*===========================================================================================
206 | FUNCTION DEFINITIONS |
208 ========================================================================================== */
212 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
216 count = gst_tag_list_get_tag_size(list, tag);
218 LOGD("count = %d", count);
220 for (i = 0; i < count; i++) {
223 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
224 if (!gst_tag_list_get_string_index(list, tag, i, &str))
225 g_assert_not_reached();
227 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
231 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
233 g_print(" : %s", str);
240 /* This function should be called after the pipeline goes PAUSED or higher
243 __mmplayer_update_content_attrs(mm_player_t *player, enum content_attr_flag flag)
245 static gboolean has_duration = FALSE;
246 static gboolean has_video_attrs = FALSE;
247 static gboolean has_audio_attrs = FALSE;
248 static gboolean has_bitrate = FALSE;
249 gboolean missing_only = FALSE;
250 gboolean all = FALSE;
251 MMHandleType attrs = 0;
255 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
257 /* check player state here */
258 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
259 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
260 /* give warning now only */
261 LOGW("be careful. content attributes may not available in this state ");
264 /* get content attribute first */
265 attrs = MMPLAYER_GET_ATTRS(player);
267 LOGE("cannot get content attribute");
271 /* get update flag */
273 if (flag & ATTR_MISSING_ONLY) {
275 LOGD("updating missed attr only");
278 if (flag & ATTR_ALL) {
280 has_duration = FALSE;
281 has_video_attrs = FALSE;
282 has_audio_attrs = FALSE;
285 LOGD("updating all attrs");
288 if (missing_only && all) {
289 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
290 missing_only = FALSE;
293 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
294 has_duration = __mmplayer_update_duration_value(player);
296 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
297 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
299 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
300 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
302 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
303 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
306 if (mm_attrs_commit_all(attrs)) {
307 LOGE("failed to update attributes");
317 __mmplayer_get_stream_service_type(mm_player_t *player)
319 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
325 player->pipeline->mainbin &&
326 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
327 STREAMING_SERVICE_NONE);
329 /* streaming service type if streaming */
330 if (!MMPLAYER_IS_STREAMING(player))
331 return STREAMING_SERVICE_NONE;
333 streaming_type = (player->duration == 0) ?
334 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
336 switch (streaming_type) {
337 case STREAMING_SERVICE_LIVE:
338 LOGD("it's live streaming");
340 case STREAMING_SERVICE_VOD:
341 LOGD("it's vod streaming");
344 LOGE("should not get here");
350 return streaming_type;
353 /* this function sets the player state and also report
354 * it to applicaton by calling callback function
357 __mmplayer_set_state(mm_player_t *player, int state)
359 MMMessageParamType msg = {0, };
361 MMPLAYER_RETURN_IF_FAIL(player);
363 if (MMPLAYER_CURRENT_STATE(player) == state) {
364 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
365 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
369 /* update player states */
370 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
371 MMPLAYER_CURRENT_STATE(player) = state;
373 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
374 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
377 MMPLAYER_PRINT_STATE(player);
379 switch (MMPLAYER_CURRENT_STATE(player)) {
380 case MM_PLAYER_STATE_NULL:
381 case MM_PLAYER_STATE_READY:
383 case MM_PLAYER_STATE_PAUSED:
384 __mmplayer_set_pause_state(player);
386 case MM_PLAYER_STATE_PLAYING:
387 __mmplayer_set_playing_state(player);
389 case MM_PLAYER_STATE_NONE:
391 LOGW("invalid target state, there is nothing to do.");
396 /* post message to application */
397 if (MMPLAYER_TARGET_STATE(player) == state) {
398 /* fill the message with state of player */
399 msg.union_type = MM_MSG_UNION_STATE;
400 msg.state.previous = MMPLAYER_PREV_STATE(player);
401 msg.state.current = MMPLAYER_CURRENT_STATE(player);
403 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
405 /* state changed by resource callback */
406 if (player->interrupted_by_resource)
407 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
408 else /* state changed by usecase */
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
412 LOGD("intermediate state, do nothing.");
413 MMPLAYER_PRINT_STATE(player);
417 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
418 && !player->sent_bos) {
419 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
420 player->sent_bos = TRUE;
427 __mmplayer_check_state(mm_player_t *player, enum PlayerCommandState command)
429 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
430 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
434 //LOGD("incomming command : %d ", command);
436 current_state = MMPLAYER_CURRENT_STATE(player);
437 pending_state = MMPLAYER_PENDING_STATE(player);
439 MMPLAYER_PRINT_STATE(player);
442 case MMPLAYER_COMMAND_CREATE:
444 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
446 if (current_state == MM_PLAYER_STATE_NULL ||
447 current_state == MM_PLAYER_STATE_READY ||
448 current_state == MM_PLAYER_STATE_PAUSED ||
449 current_state == MM_PLAYER_STATE_PLAYING)
454 case MMPLAYER_COMMAND_DESTROY:
456 /* destroy can called anytime */
458 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
462 case MMPLAYER_COMMAND_REALIZE:
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
466 if (pending_state != MM_PLAYER_STATE_NONE) {
469 /* need ready state to realize */
470 if (current_state == MM_PLAYER_STATE_READY)
473 if (current_state != MM_PLAYER_STATE_NULL)
479 case MMPLAYER_COMMAND_UNREALIZE:
481 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
483 if (current_state == MM_PLAYER_STATE_NULL)
488 case MMPLAYER_COMMAND_START:
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PLAYING)
495 else if (current_state != MM_PLAYER_STATE_READY &&
496 current_state != MM_PLAYER_STATE_PAUSED)
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
501 LOGD("player is going to paused state, just change the pending state as playing");
508 case MMPLAYER_COMMAND_STOP:
510 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
512 if (current_state == MM_PLAYER_STATE_READY)
515 /* need playing/paused state to stop */
516 if (current_state != MM_PLAYER_STATE_PLAYING &&
517 current_state != MM_PLAYER_STATE_PAUSED)
522 case MMPLAYER_COMMAND_PAUSE:
524 if (MMPLAYER_IS_LIVE_STREAMING(player))
527 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
528 goto NOT_COMPLETED_SEEK;
530 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
532 if (pending_state == MM_PLAYER_STATE_NONE) {
533 if (current_state == MM_PLAYER_STATE_PAUSED)
535 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
537 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
539 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
540 if (current_state == MM_PLAYER_STATE_PAUSED)
541 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
548 case MMPLAYER_COMMAND_RESUME:
550 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
551 goto NOT_COMPLETED_SEEK;
553 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
555 if (pending_state == MM_PLAYER_STATE_NONE) {
556 if (current_state == MM_PLAYER_STATE_PLAYING)
558 else if (current_state != MM_PLAYER_STATE_PAUSED)
560 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
562 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
563 LOGD("player is going to paused state, just change the pending state as playing");
573 player->cmd = command;
575 return MM_ERROR_NONE;
578 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
579 MMPLAYER_STATE_GET_NAME(current_state), command);
580 return MM_ERROR_PLAYER_INVALID_STATE;
583 LOGW("not completed seek");
584 return MM_ERROR_PLAYER_DOING_SEEK;
587 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
592 return MM_ERROR_PLAYER_NO_OP;
596 __mmplayer_gapless_play_thread(gpointer data)
598 mm_player_t *player = (mm_player_t *)data;
599 MMPlayerGstElement *mainbin = NULL;
601 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
603 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
604 while (!player->gapless_play_thread_exit) {
605 LOGD("gapless play thread started. waiting for signal.");
606 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
608 LOGD("reconfigure pipeline for gapless play.");
610 if (player->gapless_play_thread_exit) {
611 if (player->gapless.reconfigure) {
612 player->gapless.reconfigure = false;
613 MMPLAYER_PLAYBACK_UNLOCK(player);
615 LOGD("exiting gapless play thread");
619 mainbin = player->pipeline->mainbin;
621 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
622 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
623 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
627 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
629 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
635 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
637 GSource *source = NULL;
641 source = g_main_context_find_source_by_id(context, source_id);
642 if (source != NULL) {
643 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
644 g_source_destroy(source);
651 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
653 mm_player_t *player = (mm_player_t *)hplayer;
654 GstMessage *msg = NULL;
655 GQueue *queue = NULL;
658 MMPLAYER_RETURN_IF_FAIL(player);
660 /* disconnecting bus watch */
661 if (player->bus_watcher)
662 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
663 player->bus_watcher = 0;
665 /* destroy the gst bus msg thread */
666 if (player->bus_msg_thread) {
667 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
668 player->bus_msg_thread_exit = TRUE;
669 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
670 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
672 LOGD("gst bus msg thread exit.");
673 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
674 player->bus_msg_thread = NULL;
676 g_mutex_clear(&player->bus_msg_thread_mutex);
677 g_cond_clear(&player->bus_msg_thread_cond);
680 g_mutex_lock(&player->bus_msg_q_lock);
681 queue = player->bus_msg_q;
682 while (!g_queue_is_empty(queue)) {
683 msg = (GstMessage *)g_queue_pop_head(queue);
688 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
689 gst_message_unref(msg);
691 g_mutex_unlock(&player->bus_msg_q_lock);
697 __mmplayer_gst_remove_fakesink(mm_player_t *player, MMPlayerGstElement *fakesink)
699 GstElement *parent = NULL;
701 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
703 /* if we have no fakesink. this meas we are using decodebin which doesn'
704 t need to add extra fakesink */
705 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
708 MMPLAYER_FSINK_LOCK(player);
713 /* get parent of fakesink */
714 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
716 LOGD("fakesink already removed");
720 gst_element_set_locked_state(fakesink->gst, TRUE);
722 /* setting the state to NULL never returns async
723 * so no need to wait for completion of state transiton
725 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
726 LOGE("fakesink state change failure!");
727 /* FIXIT : should I return here? or try to proceed to next? */
730 /* remove fakesink from it's parent */
731 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
732 LOGE("failed to remove fakesink");
734 gst_object_unref(parent);
739 gst_object_unref(parent);
741 LOGD("state-holder removed");
743 gst_element_set_locked_state(fakesink->gst, FALSE);
745 MMPLAYER_FSINK_UNLOCK(player);
750 gst_element_set_locked_state(fakesink->gst, FALSE);
752 MMPLAYER_FSINK_UNLOCK(player);
756 static GstPadProbeReturn
757 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
759 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
760 return GST_PAD_PROBE_OK;
764 __mmplayer_gst_selector_update_start_time(mm_player_t *player, MMPlayerTrackType stream_type)
766 gint64 stop_running_time = 0;
767 gint64 position_running_time = 0;
771 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
772 if ((player->gapless.update_segment[idx] == TRUE) ||
773 !(player->selector[idx].event_probe_id)) {
774 /* LOGW("[%d] skip", idx); */
778 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
780 gst_segment_to_running_time(&player->gapless.segment[idx],
781 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
782 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
784 gst_segment_to_running_time(&player->gapless.segment[idx],
785 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
787 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
789 gst_segment_to_running_time(&player->gapless.segment[idx],
790 GST_FORMAT_TIME, player->duration);
793 position_running_time =
794 gst_segment_to_running_time(&player->gapless.segment[idx],
795 GST_FORMAT_TIME, player->gapless.segment[idx].position);
797 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
798 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
800 GST_TIME_ARGS(stop_running_time),
801 GST_TIME_ARGS(position_running_time),
802 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
803 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
805 position_running_time = MAX(position_running_time, stop_running_time);
806 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
807 GST_FORMAT_TIME, player->gapless.segment[idx].start);
808 position_running_time = MAX(0, position_running_time);
809 position = MAX(position, position_running_time);
813 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
814 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
815 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
817 player->gapless.start_time[stream_type] += position;
823 static GstPadProbeReturn
824 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
826 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
827 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
828 mm_player_t *player = (mm_player_t *)data;
829 GstCaps *caps = NULL;
830 GstStructure *str = NULL;
831 const gchar *name = NULL;
832 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
833 gboolean caps_ret = TRUE;
835 if (GST_EVENT_IS_DOWNSTREAM(event) &&
836 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
837 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
838 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
839 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
841 } else if (GST_EVENT_IS_UPSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
846 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
850 if (strstr(name, "audio")) {
851 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
852 } else if (strstr(name, "video")) {
853 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
855 /* text track is not supportable */
856 LOGE("invalid name %s", name);
860 switch (GST_EVENT_TYPE(event)) {
863 /* in case of gapless, drop eos event not to send it to sink */
864 if (player->gapless.reconfigure && !player->msg_posted) {
865 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
866 ret = GST_PAD_PROBE_DROP;
870 case GST_EVENT_STREAM_START:
872 __mmplayer_gst_selector_update_start_time(player, stream_type);
875 case GST_EVENT_FLUSH_STOP:
877 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
878 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
879 player->gapless.start_time[stream_type] = 0;
882 case GST_EVENT_SEGMENT:
887 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
888 gst_event_copy_segment(event, &segment);
890 if (segment.format != GST_FORMAT_TIME)
893 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
894 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
895 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
896 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
897 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
898 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
900 /* keep the all the segment ev to cover the seeking */
901 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
902 player->gapless.update_segment[stream_type] = TRUE;
904 if (!player->gapless.running)
907 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
909 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
911 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
912 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
913 gst_event_unref(event);
914 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
920 gdouble proportion = 0.0;
921 GstClockTimeDiff diff = 0;
922 GstClockTime timestamp = 0;
923 gint64 running_time_diff = -1;
925 GstEvent *tmpev = NULL;
927 running_time_diff = player->gapless.segment[stream_type].base;
929 if (running_time_diff <= 0) /* don't need to adjust */
932 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
933 gst_event_unref(event);
935 if (timestamp < running_time_diff) {
936 LOGW("QOS event from previous group");
937 ret = GST_PAD_PROBE_DROP;
941 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
942 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(timestamp),
944 GST_TIME_ARGS(running_time_diff),
945 GST_TIME_ARGS(timestamp - running_time_diff));
947 timestamp -= running_time_diff;
949 /* That case is invalid for QoS events */
950 if (diff < 0 && -diff > timestamp) {
951 LOGW("QOS event from previous group");
952 ret = GST_PAD_PROBE_DROP;
956 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
957 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
967 gst_caps_unref(caps);
971 /* create fakesink for audio or video path witout audiobin or videobin */
973 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
975 GstElement *pipeline = NULL;
976 GstElement *fakesink = NULL;
977 GstPad *sinkpad = NULL;
980 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
982 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
985 fakesink = gst_element_factory_make("fakesink", NULL);
986 if (fakesink == NULL) {
987 LOGE("failed to create fakesink");
991 /* store it as it's sink element */
992 __mmplayer_add_sink(player, fakesink);
994 gst_bin_add(GST_BIN(pipeline), fakesink);
997 sinkpad = gst_element_get_static_pad(fakesink, "sink");
999 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1001 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1002 LOGE("failed to link fakesink");
1003 gst_object_unref(GST_OBJECT(fakesink));
1007 if (strstr(name, "video")) {
1008 if (player->v_stream_caps) {
1009 gst_caps_unref(player->v_stream_caps);
1010 player->v_stream_caps = NULL;
1012 if (player->ini.set_dump_element_flag)
1013 __mmplayer_add_dump_buffer_probe(player, fakesink);
1016 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1017 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1021 gst_object_unref(GST_OBJECT(sinkpad));
1028 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1030 GstElement *pipeline = NULL;
1031 GstElement *selector = NULL;
1032 GstPad *srcpad = NULL;
1035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1037 selector = gst_element_factory_make("input-selector", NULL);
1039 LOGE("failed to create input-selector");
1042 g_object_set(selector, "sync-streams", TRUE, NULL);
1044 player->pipeline->mainbin[elem_idx].id = elem_idx;
1045 player->pipeline->mainbin[elem_idx].gst = selector;
1047 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1049 srcpad = gst_element_get_static_pad(selector, "src");
1051 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1052 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1053 __mmplayer_gst_selector_blocked, NULL, NULL);
1054 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1055 __mmplayer_gst_selector_event_probe, player, NULL);
1057 gst_element_set_state(selector, GST_STATE_PAUSED);
1059 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1060 gst_bin_add(GST_BIN(pipeline), selector);
1067 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1069 mm_player_t *player = (mm_player_t *)data;
1070 GstElement *selector = NULL;
1071 GstCaps *caps = NULL;
1072 GstStructure *str = NULL;
1073 const gchar *name = NULL;
1074 GstPad *sinkpad = NULL;
1075 gboolean first_track = FALSE;
1076 gboolean caps_ret = TRUE;
1078 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1079 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1082 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1083 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1085 LOGD("pad-added signal handling");
1087 /* get mimetype from caps */
1088 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1092 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1093 /* LOGD("detected mimetype : %s", name); */
1095 if (strstr(name, "video")) {
1097 gchar *caps_str = NULL;
1099 caps_str = gst_caps_to_string(caps);
1100 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1101 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1102 player->set_mode.video_zc = true;
1104 MMPLAYER_FREEIF(caps_str);
1106 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1107 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1109 LOGD("surface type : %d", stype);
1111 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1112 __mmplayer_gst_create_sinkbin(elem, pad, player);
1116 /* in case of exporting video frame, it requires the 360 video filter.
1117 * it will be handled in _no_more_pads(). */
1118 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)) {
1119 __mmplayer_gst_make_fakesink(player, pad, name);
1123 LOGD("video selector is required");
1124 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1125 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1126 } else if (strstr(name, "audio")) {
1127 gint samplerate = 0;
1130 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1131 if (player->build_audio_offload)
1132 player->no_more_pad = TRUE; /* remove state holder */
1133 __mmplayer_gst_create_sinkbin(elem, pad, player);
1137 gst_structure_get_int(str, "rate", &samplerate);
1138 gst_structure_get_int(str, "channels", &channels);
1140 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1141 __mmplayer_gst_make_fakesink(player, pad, name);
1145 LOGD("audio selector is required");
1146 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1147 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1149 } else if (strstr(name, "text")) {
1150 LOGD("text selector is required");
1151 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1152 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1154 LOGE("invalid caps info");
1158 /* check selector and create it */
1159 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1160 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1165 LOGD("input-selector is already created.");
1169 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1171 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1173 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1174 LOGE("failed to link selector");
1175 gst_object_unref(GST_OBJECT(selector));
1180 LOGD("this track will be activated");
1181 g_object_set(selector, "active-pad", sinkpad, NULL);
1184 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1190 gst_caps_unref(caps);
1193 gst_object_unref(GST_OBJECT(sinkpad));
1201 __mmplayer_create_sink_path(mm_player_t *player, GstElement *selector, MMPlayerTrackType type)
1203 GstPad *srcpad = NULL;
1206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1208 LOGD("type %d", type);
1211 LOGD("there is no %d track", type);
1215 srcpad = gst_element_get_static_pad(selector, "src");
1217 LOGE("failed to get srcpad from selector");
1221 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1223 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1225 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1226 if (player->selector[type].block_id) {
1227 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1228 player->selector[type].block_id = 0;
1232 gst_object_unref(GST_OBJECT(srcpad));
1241 __mmplayer_set_decode_track_info(mm_player_t *player, MMPlayerTrackType type)
1243 MMHandleType attrs = 0;
1244 gint active_index = 0;
1247 MMPLAYER_RETURN_IF_FAIL(player);
1249 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1251 /* change track to active pad */
1252 active_index = player->selector[type].active_pad_index;
1253 if ((active_index != DEFAULT_TRACK) &&
1254 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1255 LOGW("failed to change %d type track to %d", type, active_index);
1256 player->selector[type].active_pad_index = DEFAULT_TRACK;
1260 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1261 attrs = MMPLAYER_GET_ATTRS(player);
1263 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1264 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1266 if (mm_attrs_commit_all(attrs))
1267 LOGW("failed to commit attrs.");
1269 LOGW("cannot get content attribute");
1278 __mmplayer_create_audio_sink_path(mm_player_t *player, GstElement *audio_selector)
1281 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1283 if (!audio_selector) {
1284 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1286 /* in case the source is changed, output can be changed. */
1287 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1288 LOGD("remove previous audiobin if it exist");
1290 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1291 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1293 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1294 MMPLAYER_FREEIF(player->pipeline->audiobin);
1297 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1298 __mmplayer_pipeline_complete(NULL, player);
1303 /* apply the audio track information */
1304 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1306 /* create audio sink path */
1307 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1308 LOGE("failed to create audio sink path");
1317 __mmplayer_create_text_sink_path(mm_player_t *player, GstElement *text_selector)
1320 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1322 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1323 LOGD("text path is not supproted");
1327 /* apply the text track information */
1328 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1330 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1331 player->has_closed_caption = TRUE;
1333 /* create text decode path */
1334 player->no_more_pad = TRUE;
1336 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1337 LOGE("failed to create text sink path");
1346 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1348 gint64 dur_bytes = 0L;
1351 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1352 player->pipeline->mainbin && player->streamer, FALSE);
1354 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1355 LOGE("fail to get duration.");
1357 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1358 * use file information was already set on Q2 when it was created. */
1359 __mm_player_streaming_set_queue2(player->streamer,
1360 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1361 TRUE, /* use_buffering */
1362 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1363 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1370 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1372 mm_player_t *player = NULL;
1373 GstElement *video_selector = NULL;
1374 GstElement *audio_selector = NULL;
1375 GstElement *text_selector = NULL;
1378 player = (mm_player_t *)data;
1380 LOGD("no-more-pad signal handling");
1382 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1383 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1384 LOGW("player is shutting down");
1388 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1389 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1390 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1391 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1392 LOGE("failed to set queue2 buffering");
1397 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1398 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1399 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1401 if (!video_selector && !audio_selector && !text_selector) {
1402 LOGW("there is no selector");
1403 player->no_more_pad = TRUE;
1407 /* create video path followed by video-select */
1408 if (video_selector && !audio_selector && !text_selector)
1409 player->no_more_pad = TRUE;
1411 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1414 /* create audio path followed by audio-select */
1415 if (audio_selector && !text_selector)
1416 player->no_more_pad = TRUE;
1418 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1421 /* create text path followed by text-select */
1422 __mmplayer_create_text_sink_path(player, text_selector);
1425 if (player->gapless.reconfigure) {
1426 player->gapless.reconfigure = FALSE;
1427 MMPLAYER_PLAYBACK_UNLOCK(player);
1434 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1436 gboolean ret = FALSE;
1437 GstElement *pipeline = NULL;
1438 GstPad *sinkpad = NULL;
1441 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1444 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1446 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1448 LOGE("failed to get pad from sinkbin");
1454 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1455 LOGE("failed to link sinkbin for reusing");
1456 goto EXIT; /* exit either pass or fail */
1460 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1461 LOGE("failed to set state(READY) to sinkbin");
1466 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1467 LOGE("failed to add sinkbin to pipeline");
1472 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1473 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1478 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1479 LOGE("failed to set state(PAUSED) to sinkbin");
1488 gst_object_unref(GST_OBJECT(sinkpad));
1496 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1498 mm_player_t *player = NULL;
1499 GstCaps *caps = NULL;
1500 gchar *caps_str = NULL;
1501 GstStructure *str = NULL;
1502 const gchar *name = NULL;
1503 GstElement *sinkbin = NULL;
1504 gboolean reusing = FALSE;
1505 gboolean caps_ret = TRUE;
1506 gchar *sink_pad_name = "sink";
1509 player = (mm_player_t *)data;
1512 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1513 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1515 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1519 caps_str = gst_caps_to_string(caps);
1521 /* LOGD("detected mimetype : %s", name); */
1522 if (strstr(name, "audio")) {
1523 if (player->pipeline->audiobin == NULL) {
1524 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1525 LOGE("failed to create audiobin. continuing without audio");
1529 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1530 LOGD("creating audiobin success");
1533 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1534 LOGD("reusing audiobin");
1535 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1537 } else if (strstr(name, "video")) {
1538 /* 1. zero copy is updated at _decode_pad_added()
1539 * 2. NULL surface type is handled in _decode_pad_added() */
1540 LOGD("zero copy %d", player->set_mode.video_zc);
1541 if (player->pipeline->videobin == NULL) {
1542 int surface_type = 0;
1543 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1544 LOGD("display_surface_type (%d)", surface_type);
1546 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1547 LOGD("mark video overlay for acquire");
1548 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1549 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1550 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1551 &player->video_overlay_resource)
1552 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1553 LOGE("could not mark video_overlay resource for acquire");
1558 player->interrupted_by_resource = FALSE;
1560 if (mm_resource_manager_commit(player->resource_manager) !=
1561 MM_RESOURCE_MANAGER_ERROR_NONE) {
1562 LOGE("could not acquire resources for video playing");
1566 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1567 LOGE("failed to create videobin. continuing without video");
1571 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1572 LOGD("creating videosink bin success");
1575 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1576 LOGD("re-using videobin");
1577 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1579 } else if (strstr(name, "text")) {
1580 if (player->pipeline->textbin == NULL) {
1581 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1582 LOGE("failed to create text sink bin. continuing without text");
1586 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1587 player->textsink_linked = 1;
1588 LOGD("creating textsink bin success");
1590 if (!player->textsink_linked) {
1591 LOGD("re-using textbin");
1593 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1594 player->textsink_linked = 1;
1596 /* linked textbin exist which means that the external subtitle path exist already */
1597 LOGW("ignoring internal subtutle since external subtitle is available");
1600 sink_pad_name = "text_sink";
1602 LOGW("unknown mime type %s, ignoring it", name);
1606 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1609 LOGD("[handle: %p] success to create and link sink bin", player);
1611 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1612 * streaming task. if the task blocked, then buffer will not flow to the next element
1613 *(autoplugging element). so this is special hack for streaming. please try to remove it
1615 /* dec stream count. we can remove fakesink if it's zero */
1616 if (player->num_dynamic_pad)
1617 player->num_dynamic_pad--;
1619 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1621 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1622 __mmplayer_pipeline_complete(NULL, player);
1626 MMPLAYER_FREEIF(caps_str);
1629 gst_caps_unref(caps);
1635 __mmplayer_get_property_value_for_rotation(mm_player_t *player, int display_angle, int orientation, int *value)
1637 int required_angle = 0; /* Angle required for straight view */
1638 int rotation_angle = 0;
1640 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1641 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1643 /* Counter clockwise */
1644 switch (orientation) {
1649 required_angle = 270;
1652 required_angle = 180;
1655 required_angle = 90;
1659 rotation_angle = display_angle + required_angle;
1660 if (rotation_angle >= 360)
1661 rotation_angle -= 360;
1663 /* chech if supported or not */
1664 if (rotation_angle % 90) {
1665 LOGD("not supported rotation angle = %d", rotation_angle);
1669 switch (rotation_angle) {
1671 *value = MM_DISPLAY_ROTATION_NONE;
1674 *value = MM_DISPLAY_ROTATION_90;
1677 *value = MM_DISPLAY_ROTATION_180;
1680 *value = MM_DISPLAY_ROTATION_270;
1684 LOGD("setting rotation property value : %d", *value);
1690 __mmplayer_video_param_check_video_sink_bin(mm_player_t *player)
1692 /* check video sinkbin is created */
1693 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1695 player->pipeline->videobin &&
1696 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1697 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1698 MM_ERROR_PLAYER_NOT_INITIALIZED);
1700 return MM_ERROR_NONE;
1704 __mmplayer_get_video_angle(mm_player_t *player, int *display_angle, int *orientation)
1706 int display_rotation = 0;
1707 gchar *org_orient = NULL;
1708 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1711 LOGE("cannot get content attribute");
1712 return MM_ERROR_PLAYER_INTERNAL;
1715 if (display_angle) {
1716 /* update user roation */
1717 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1719 /* Counter clockwise */
1720 switch (display_rotation) {
1721 case MM_DISPLAY_ROTATION_NONE:
1724 case MM_DISPLAY_ROTATION_90:
1725 *display_angle = 90;
1727 case MM_DISPLAY_ROTATION_180:
1728 *display_angle = 180;
1730 case MM_DISPLAY_ROTATION_270:
1731 *display_angle = 270;
1734 LOGW("wrong angle type : %d", display_rotation);
1737 LOGD("check user angle: %d", *display_angle);
1741 /* Counter clockwise */
1742 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1745 if (!strcmp(org_orient, "rotate-90"))
1747 else if (!strcmp(org_orient, "rotate-180"))
1749 else if (!strcmp(org_orient, "rotate-270"))
1752 LOGD("original rotation is %s", org_orient);
1754 LOGD("content_video_orientation get fail");
1757 LOGD("check orientation: %d", *orientation);
1760 return MM_ERROR_NONE;
1764 __mmplayer_video_param_set_display_rotation(mm_player_t *player)
1766 int rotation_value = 0;
1767 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1768 int display_angle = 0;
1771 /* check video sinkbin is created */
1772 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1775 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1777 /* get rotation value to set */
1778 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1779 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1780 LOGD("set video param : rotate %d", rotation_value);
1784 __mmplayer_video_param_set_display_visible(mm_player_t *player)
1786 MMHandleType attrs = 0;
1790 /* check video sinkbin is created */
1791 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1794 attrs = MMPLAYER_GET_ATTRS(player);
1795 MMPLAYER_RETURN_IF_FAIL(attrs);
1797 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1798 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1799 LOGD("set video param : visible %d", visible);
1803 __mmplayer_video_param_set_display_method(mm_player_t *player)
1805 MMHandleType attrs = 0;
1806 int display_method = 0;
1809 /* check video sinkbin is created */
1810 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1813 attrs = MMPLAYER_GET_ATTRS(player);
1814 MMPLAYER_RETURN_IF_FAIL(attrs);
1816 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1817 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1818 LOGD("set video param : method %d", display_method);
1822 __mmplayer_video_param_set_video_roi_area(mm_player_t *player)
1824 MMHandleType attrs = 0;
1825 void *handle = NULL;
1828 /* check video sinkbin is created */
1829 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1830 LOGW("There is no video sink");
1834 attrs = MMPLAYER_GET_ATTRS(player);
1835 MMPLAYER_RETURN_IF_FAIL(attrs);
1836 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1838 gst_video_overlay_set_video_roi_area(
1839 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1840 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1841 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1842 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1847 __mmplayer_video_param_set_roi_area(mm_player_t *player)
1849 MMHandleType attrs = 0;
1850 void *handle = NULL;
1854 int win_roi_width = 0;
1855 int win_roi_height = 0;
1858 /* check video sinkbin is created */
1859 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1860 LOGW("There is no video sink");
1864 attrs = MMPLAYER_GET_ATTRS(player);
1865 MMPLAYER_RETURN_IF_FAIL(attrs);
1867 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1870 /* It should be set after setting window */
1871 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1872 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1873 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1874 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1876 /* After setting window handle, set display roi area */
1877 gst_video_overlay_set_display_roi_area(
1878 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1879 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1880 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1881 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1886 __mmplayer_video_param_set_display_overlay(mm_player_t *player)
1888 MMHandleType attrs = 0;
1889 void *handle = NULL;
1891 /* check video sinkbin is created */
1892 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1895 attrs = MMPLAYER_GET_ATTRS(player);
1896 MMPLAYER_RETURN_IF_FAIL(attrs);
1898 /* common case if using overlay surface */
1899 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1902 /* default is using wl_surface_id */
1903 unsigned int wl_surface_id = 0;
1904 wl_surface_id = *(int *)handle;
1905 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1906 gst_video_overlay_set_wl_window_wl_surface_id(
1907 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1910 /* FIXIT : is it error case? */
1911 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1916 __mmplayer_update_wayland_videosink_video_param(mm_player_t *player, char *param_name)
1918 gboolean update_all_param = FALSE;
1921 /* check video sinkbin is created */
1922 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1923 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1925 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1926 LOGE("can not find tizenwlsink");
1927 return MM_ERROR_PLAYER_INTERNAL;
1930 LOGD("param_name : %s", param_name);
1931 if (!g_strcmp0(param_name, "update_all_param"))
1932 update_all_param = TRUE;
1934 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1935 __mmplayer_video_param_set_display_overlay(player);
1936 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1937 __mmplayer_video_param_set_display_method(player);
1938 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1939 __mmplayer_video_param_set_display_visible(player);
1940 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1941 __mmplayer_video_param_set_display_rotation(player);
1942 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1943 __mmplayer_video_param_set_roi_area(player);
1944 if (update_all_param)
1945 __mmplayer_video_param_set_video_roi_area(player);
1947 return MM_ERROR_NONE;
1951 _mmplayer_update_video_param(mm_player_t *player, char *param_name)
1953 MMHandleType attrs = 0;
1954 int surface_type = 0;
1955 int ret = MM_ERROR_NONE;
1959 /* check video sinkbin is created */
1960 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1961 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1963 attrs = MMPLAYER_GET_ATTRS(player);
1965 LOGE("cannot get content attribute");
1966 return MM_ERROR_PLAYER_INTERNAL;
1968 LOGD("param_name : %s", param_name);
1970 /* update display surface */
1971 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1972 LOGD("check display surface type attribute: %d", surface_type);
1974 /* configuring display */
1975 switch (surface_type) {
1976 case MM_DISPLAY_SURFACE_OVERLAY:
1978 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1979 if (ret != MM_ERROR_NONE)
1987 return MM_ERROR_NONE;
1991 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
1993 gboolean disable_overlay = FALSE;
1994 mm_player_t *player = (mm_player_t *)hplayer;
1995 int ret = MM_ERROR_NONE;
1998 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
1999 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2000 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2001 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2003 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2004 LOGW("Display control is not supported");
2005 return MM_ERROR_PLAYER_INTERNAL;
2008 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2010 if (audio_only == (bool)disable_overlay) {
2011 LOGE("It's the same with current setting: (%d)", audio_only);
2012 return MM_ERROR_NONE;
2016 LOGE("disable overlay");
2017 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2019 /* release overlay resource */
2020 if (player->video_overlay_resource != NULL) {
2021 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2022 player->video_overlay_resource);
2023 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2024 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2027 player->video_overlay_resource = NULL;
2030 ret = mm_resource_manager_commit(player->resource_manager);
2031 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2032 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2036 /* mark video overlay for acquire */
2037 if (player->video_overlay_resource == NULL) {
2038 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2039 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2040 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2041 &player->video_overlay_resource);
2042 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2043 LOGE("could not prepare for video_overlay resource");
2048 player->interrupted_by_resource = FALSE;
2049 /* acquire resources for video overlay */
2050 ret = mm_resource_manager_commit(player->resource_manager);
2051 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2052 LOGE("could not acquire resources for video playing");
2056 LOGD("enable overlay");
2057 __mmplayer_video_param_set_display_overlay(player);
2058 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2063 return MM_ERROR_NONE;
2067 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2069 mm_player_t *player = (mm_player_t *)hplayer;
2070 gboolean disable_overlay = FALSE;
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2075 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2077 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2078 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2080 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2081 LOGW("Display control is not supported");
2082 return MM_ERROR_PLAYER_INTERNAL;
2085 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2087 *paudio_only = (bool)disable_overlay;
2089 LOGD("audio_only : %d", *paudio_only);
2093 return MM_ERROR_NONE;
2097 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2099 GList *bucket = element_bucket;
2100 MMPlayerGstElement *element = NULL;
2101 MMPlayerGstElement *prv_element = NULL;
2102 gint successful_link_count = 0;
2106 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2108 prv_element = (MMPlayerGstElement *)bucket->data;
2109 bucket = bucket->next;
2111 for (; bucket; bucket = bucket->next) {
2112 element = (MMPlayerGstElement *)bucket->data;
2114 if (element && element->gst) {
2115 if (prv_element && prv_element->gst) {
2116 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2117 LOGD("linking [%s] to [%s] success",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2120 successful_link_count++;
2122 LOGD("linking [%s] to [%s] failed",
2123 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2124 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2130 prv_element = element;
2135 return successful_link_count;
2139 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2141 GList *bucket = element_bucket;
2142 MMPlayerGstElement *element = NULL;
2143 int successful_add_count = 0;
2147 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2148 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2150 for (; bucket; bucket = bucket->next) {
2151 element = (MMPlayerGstElement *)bucket->data;
2153 if (element && element->gst) {
2154 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2155 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2156 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2157 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2160 successful_add_count++;
2166 return successful_add_count;
2170 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2172 mm_player_t *player = (mm_player_t *)data;
2173 GstCaps *caps = NULL;
2174 GstStructure *str = NULL;
2176 gboolean caps_ret = TRUE;
2180 MMPLAYER_RETURN_IF_FAIL(pad);
2181 MMPLAYER_RETURN_IF_FAIL(unused);
2182 MMPLAYER_RETURN_IF_FAIL(data);
2184 caps = gst_pad_get_current_caps(pad);
2188 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2192 LOGD("name = %s", name);
2194 if (strstr(name, "audio")) {
2195 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2197 if (player->audio_stream_changed_cb) {
2198 LOGE("call the audio stream changed cb");
2199 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2201 } else if (strstr(name, "video")) {
2202 if ((name = gst_structure_get_string(str, "format")))
2203 player->set_mode.video_zc = name[0] == 'S';
2205 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2207 if (player->video_stream_changed_cb) {
2208 LOGE("call the video stream changed cb");
2209 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2212 LOGW("invalid caps info");
2217 gst_caps_unref(caps);
2225 * This function is to create audio pipeline for playing.
2227 * @param player [in] handle of player
2229 * @return This function returns zero on success.
2231 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2233 /* macro for code readability. just for sinkbin-creation functions */
2234 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2236 x_bin[x_id].id = x_id;\
2237 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2238 if (!x_bin[x_id].gst) {\
2239 LOGE("failed to create %s", x_factory);\
2242 if (x_player->ini.set_dump_element_flag)\
2243 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2246 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2250 __mmplayer_audio_stream_clear_buffer(mm_player_t *player, gboolean send_all)
2255 MMPLAYER_RETURN_IF_FAIL(player);
2257 if (player->audio_stream_buff_list) {
2258 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2259 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2262 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2263 __mmplayer_audio_stream_send_data(player, tmp);
2265 MMPLAYER_FREEIF(tmp->pcm_data);
2266 MMPLAYER_FREEIF(tmp);
2269 g_list_free(player->audio_stream_buff_list);
2270 player->audio_stream_buff_list = NULL;
2277 __mmplayer_audio_stream_send_data(mm_player_t *player, mm_player_audio_stream_buff_t *a_buffer)
2279 MMPlayerAudioStreamDataType audio_stream = { 0, };
2282 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2284 audio_stream.bitrate = a_buffer->bitrate;
2285 audio_stream.channel = a_buffer->channel;
2286 audio_stream.depth = a_buffer->depth;
2287 audio_stream.is_little_endian = a_buffer->is_little_endian;
2288 audio_stream.channel_mask = a_buffer->channel_mask;
2289 audio_stream.data_size = a_buffer->data_size;
2290 audio_stream.data = a_buffer->pcm_data;
2292 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2293 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2299 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2301 mm_player_t *player = (mm_player_t *)data;
2305 gint endianness = 0;
2306 guint64 channel_mask = 0;
2307 void *a_data = NULL;
2309 mm_player_audio_stream_buff_t *a_buffer = NULL;
2310 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2314 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2316 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2317 a_data = mapinfo.data;
2318 a_size = mapinfo.size;
2320 GstCaps *caps = gst_pad_get_current_caps(pad);
2321 GstStructure *structure = gst_caps_get_structure(caps, 0);
2323 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2324 gst_structure_get_int(structure, "rate", &rate);
2325 gst_structure_get_int(structure, "channels", &channel);
2326 gst_structure_get_int(structure, "depth", &depth);
2327 gst_structure_get_int(structure, "endianness", &endianness);
2328 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2329 gst_caps_unref(GST_CAPS(caps));
2331 /* In case of the sync is false, use buffer list. *
2332 * The num of buffer list depends on the num of audio channels */
2333 if (player->audio_stream_buff_list) {
2334 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2335 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2337 if (channel_mask == tmp->channel_mask) {
2338 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2339 if (tmp->data_size + a_size < tmp->buff_size) {
2340 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2341 tmp->data_size += a_size;
2343 /* send data to client */
2344 __mmplayer_audio_stream_send_data(player, tmp);
2346 if (a_size > tmp->buff_size) {
2347 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2348 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2349 if (tmp->pcm_data == NULL) {
2350 LOGE("failed to realloc data.");
2353 tmp->buff_size = a_size;
2355 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2356 memcpy(tmp->pcm_data, a_data, a_size);
2357 tmp->data_size = a_size;
2362 LOGE("data is empty in list.");
2368 /* create new audio stream data */
2369 a_buffer = (mm_player_audio_stream_buff_t *)g_try_malloc0(sizeof(mm_player_audio_stream_buff_t));
2370 if (a_buffer == NULL) {
2371 LOGE("failed to alloc data.");
2374 a_buffer->bitrate = rate;
2375 a_buffer->channel = channel;
2376 a_buffer->depth = depth;
2377 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2378 a_buffer->channel_mask = channel_mask;
2379 a_buffer->data_size = a_size;
2381 if (!player->audio_stream_sink_sync) {
2382 /* If sync is FALSE, use buffer list to reduce the IPC. */
2383 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2384 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2385 if (a_buffer->pcm_data == NULL) {
2386 LOGE("failed to alloc data.");
2387 MMPLAYER_FREEIF(a_buffer);
2390 memcpy(a_buffer->pcm_data, a_data, a_size);
2391 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2392 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2394 /* If sync is TRUE, send data directly. */
2395 a_buffer->pcm_data = a_data;
2396 __mmplayer_audio_stream_send_data(player, a_buffer);
2397 MMPLAYER_FREEIF(a_buffer);
2401 gst_buffer_unmap(buffer, &mapinfo);
2406 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2408 mm_player_t *player = (mm_player_t *)data;
2409 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
2410 GstPad *sinkpad = NULL;
2411 GstElement *queue = NULL, *sink = NULL;
2414 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2416 queue = gst_element_factory_make("queue", NULL);
2417 if (queue == NULL) {
2418 LOGD("fail make queue");
2422 sink = gst_element_factory_make("fakesink", NULL);
2424 LOGD("fail make fakesink");
2428 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2430 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2431 LOGW("failed to link queue & sink");
2435 sinkpad = gst_element_get_static_pad(queue, "sink");
2437 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2438 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2442 LOGE("player->audio_stream_sink_sync: %d", player->audio_stream_sink_sync);
2444 gst_object_unref(sinkpad);
2445 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2446 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2448 gst_element_set_state(sink, GST_STATE_PAUSED);
2449 gst_element_set_state(queue, GST_STATE_PAUSED);
2451 __mmplayer_add_signal_connection(player,
2453 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2455 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2462 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2464 gst_object_unref(GST_OBJECT(queue));
2468 gst_object_unref(GST_OBJECT(sink));
2472 gst_object_unref(GST_OBJECT(sinkpad));
2480 __mmplayer_gst_set_pulsesink_property(mm_player_t *player, MMHandleType attrs)
2482 #define MAX_PROPS_LEN 128
2483 gint latency_mode = 0;
2484 gchar *stream_type = NULL;
2485 gchar *latency = NULL;
2487 gchar stream_props[MAX_PROPS_LEN] = {0,};
2488 GstStructure *props = NULL;
2491 * It should be set after player creation through attribute.
2492 * But, it can not be changed during playing.
2495 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2497 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2498 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2501 LOGE("stream_type is null.");
2503 if (player->sound.focus_id)
2504 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2505 stream_type, stream_id, player->sound.focus_id);
2507 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2508 stream_type, stream_id);
2509 props = gst_structure_from_string(stream_props, NULL);
2510 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2511 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2512 stream_type, stream_id, player->sound.focus_id, stream_props);
2513 gst_structure_free(props);
2516 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2518 switch (latency_mode) {
2519 case AUDIO_LATENCY_MODE_LOW:
2520 latency = g_strndup("low", 3);
2522 case AUDIO_LATENCY_MODE_MID:
2523 latency = g_strndup("mid", 3);
2525 case AUDIO_LATENCY_MODE_HIGH:
2526 latency = g_strndup("high", 4);
2530 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2534 LOGD("audiosink property - latency=%s", latency);
2536 MMPLAYER_FREEIF(latency);
2542 __mmplayer_gst_set_openalsink_property(mm_player_t *player)
2544 MMPlayerGstElement *audiobin = NULL;
2547 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2549 audiobin = player->pipeline->audiobin;
2551 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2552 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2555 if (player->video360_yaw_radians <= M_PI &&
2556 player->video360_yaw_radians >= -M_PI &&
2557 player->video360_pitch_radians <= M_PI_2 &&
2558 player->video360_pitch_radians >= -M_PI_2) {
2559 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2560 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2561 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2562 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2563 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2564 "source-orientation-y", player->video360_metadata.init_view_heading,
2565 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2572 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2574 MMPlayerGstElement *audiobin = NULL;
2575 MMHandleType attrs = 0;
2576 GList *element_bucket = NULL;
2577 GstCaps *acaps = NULL;
2578 GstPad *sink_pad = NULL;
2579 int pitch_control = 0;
2580 double pitch_value = 1.0;
2583 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2584 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2586 audiobin = player->pipeline->audiobin;
2587 attrs = MMPLAYER_GET_ATTRS(player);
2589 if (player->build_audio_offload) { /* skip all the audio filters */
2590 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2591 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2593 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2598 mm_attrs_multiple_get(player->attrs, NULL,
2599 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2600 MM_PLAYER_PITCH_VALUE, &pitch_value,
2603 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2604 if (pitch_control && (player->videodec_linked == 0)) {
2605 GstElementFactory *factory;
2607 factory = gst_element_factory_find("pitch");
2609 gst_object_unref(factory);
2612 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2615 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2616 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2618 LOGW("there is no pitch element");
2623 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2625 /* replaygain volume */
2626 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2627 if (player->sound.rg_enable)
2628 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2630 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2635 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2636 gchar *dst_format = NULL;
2638 int dst_samplerate = 0;
2639 int dst_channels = 0;
2640 GstCaps *caps = NULL;
2641 char *caps_str = NULL;
2643 /* get conf. values */
2644 mm_attrs_multiple_get(player->attrs, NULL,
2645 "pcm_audioformat", &dst_format, &dst_len,
2646 "pcm_extraction_samplerate", &dst_samplerate,
2647 "pcm_extraction_channels", &dst_channels,
2650 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2654 caps = gst_caps_new_simple("audio/x-raw",
2655 "format", G_TYPE_STRING, dst_format,
2656 "rate", G_TYPE_INT, dst_samplerate,
2657 "channels", G_TYPE_INT, dst_channels,
2660 caps_str = gst_caps_to_string(caps);
2661 LOGD("new caps : %s", caps_str);
2663 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2666 gst_caps_unref(caps);
2667 MMPLAYER_FREEIF(caps_str);
2669 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2671 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2673 /* raw pad handling signal, audiosink will be added after getting signal */
2674 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2675 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2679 /* normal playback */
2682 /* for logical volume control */
2683 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2684 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2686 if (player->sound.mute) {
2687 LOGD("mute enabled");
2688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2691 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2693 /* audio effect element. if audio effect is enabled */
2694 if ((strcmp(player->ini.audioeffect_element, ""))
2696 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2697 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2699 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2701 if ((!player->bypass_audio_effect)
2702 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2703 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2704 if (!_mmplayer_audio_effect_custom_apply(player))
2705 LOGI("apply audio effect(custom) setting success");
2709 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2710 && (player->set_mode.rich_audio))
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2714 /* create audio sink */
2715 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2716 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2717 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2719 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2720 if (player->is_360_feature_enabled &&
2721 player->is_content_spherical &&
2723 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2724 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2725 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2727 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2729 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2732 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2734 gst_caps_unref(acaps);
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2738 player->is_openal_plugin_used = TRUE;
2740 if (player->is_360_feature_enabled && player->is_content_spherical)
2741 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2745 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2746 (player->videodec_linked && player->ini.use_system_clock)) {
2747 LOGD("system clock will be used.");
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2751 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2752 __mmplayer_gst_set_pulsesink_property(player, attrs);
2753 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2754 __mmplayer_gst_set_openalsink_property(player);
2757 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2758 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2760 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2761 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2762 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2763 gst_object_unref(GST_OBJECT(sink_pad));
2765 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2769 *bucket = element_bucket;
2772 return MM_ERROR_NONE;
2775 g_list_free(element_bucket);
2779 return MM_ERROR_PLAYER_INTERNAL;
2783 __mmplayer_gst_create_audio_sink_bin(mm_player_t *player)
2785 MMPlayerGstElement *first_element = NULL;
2786 MMPlayerGstElement *audiobin = NULL;
2788 GstPad *ghostpad = NULL;
2789 GList *element_bucket = NULL;
2793 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2796 audiobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2798 LOGE("failed to allocate memory for audiobin");
2799 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2803 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2804 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2805 if (!audiobin[MMPLAYER_A_BIN].gst) {
2806 LOGE("failed to create audiobin");
2811 player->pipeline->audiobin = audiobin;
2813 /* create audio filters and audiosink */
2814 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2817 /* adding created elements to bin */
2818 LOGD("adding created elements to bin");
2819 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2822 /* linking elements in the bucket by added order. */
2823 LOGD("Linking elements in the bucket by added order.");
2824 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2827 /* get first element's sinkpad for creating ghostpad */
2828 first_element = (MMPlayerGstElement *)element_bucket->data;
2829 if (!first_element) {
2830 LOGE("failed to get first elem");
2834 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2836 LOGE("failed to get pad from first element of audiobin");
2840 ghostpad = gst_ghost_pad_new("sink", pad);
2842 LOGE("failed to create ghostpad");
2846 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2847 LOGE("failed to add ghostpad to audiobin");
2851 gst_object_unref(pad);
2853 g_list_free(element_bucket);
2856 return MM_ERROR_NONE;
2859 LOGD("ERROR : releasing audiobin");
2862 gst_object_unref(GST_OBJECT(pad));
2865 gst_object_unref(GST_OBJECT(ghostpad));
2868 g_list_free(element_bucket);
2870 /* release element which are not added to bin */
2871 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2872 /* NOTE : skip bin */
2873 if (audiobin[i].gst) {
2874 GstObject *parent = NULL;
2875 parent = gst_element_get_parent(audiobin[i].gst);
2878 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2879 audiobin[i].gst = NULL;
2881 gst_object_unref(GST_OBJECT(parent));
2885 /* release audiobin with it's childs */
2886 if (audiobin[MMPLAYER_A_BIN].gst)
2887 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2889 MMPLAYER_FREEIF(audiobin);
2891 player->pipeline->audiobin = NULL;
2893 return MM_ERROR_PLAYER_INTERNAL;
2897 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2899 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2903 _mmplayer_video_stream_release_bo(mm_player_t *player, void *bo)
2905 int ret = MM_ERROR_NONE;
2907 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2908 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2910 MMPLAYER_VIDEO_BO_LOCK(player);
2912 if (player->video_bo_list) {
2913 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2914 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2915 if (tmp && tmp->bo == bo) {
2917 LOGD("release bo %p", bo);
2918 tbm_bo_unref(tmp->bo);
2919 MMPLAYER_VIDEO_BO_UNLOCK(player);
2920 MMPLAYER_VIDEO_BO_SIGNAL(player);
2925 /* hw codec is running or the list was reset for DRC. */
2926 LOGW("there is no bo list.");
2928 MMPLAYER_VIDEO_BO_UNLOCK(player);
2930 LOGW("failed to find bo %p", bo);
2935 __mmplayer_video_stream_destroy_bo_list(mm_player_t *player)
2940 MMPLAYER_RETURN_IF_FAIL(player);
2942 MMPLAYER_VIDEO_BO_LOCK(player);
2943 if (player->video_bo_list) {
2944 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2945 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2946 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
2949 tbm_bo_unref(tmp->bo);
2953 g_list_free(player->video_bo_list);
2954 player->video_bo_list = NULL;
2956 player->video_bo_size = 0;
2957 MMPLAYER_VIDEO_BO_UNLOCK(player);
2964 __mmplayer_video_stream_get_bo(mm_player_t *player, int size)
2967 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2968 gboolean ret = TRUE;
2970 /* check DRC, if it is, destroy the prev bo list to create again */
2971 if (player->video_bo_size != size) {
2972 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2973 __mmplayer_video_stream_destroy_bo_list(player);
2974 player->video_bo_size = size;
2977 MMPLAYER_VIDEO_BO_LOCK(player);
2979 if ((!player->video_bo_list) ||
2980 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2982 /* create bo list */
2984 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2986 if (player->video_bo_list) {
2987 /* if bo list did not created all, try it again. */
2988 idx = g_list_length(player->video_bo_list);
2989 LOGD("bo list exist(len: %d)", idx);
2992 for (; idx < player->ini.num_of_video_bo; idx++) {
2993 mm_player_video_bo_info_t *bo_info = g_new(mm_player_video_bo_info_t, 1);
2995 LOGE("Fail to alloc bo_info.");
2998 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3000 LOGE("Fail to tbm_bo_alloc.");
3001 MMPLAYER_FREEIF(bo_info);
3004 bo_info->used = FALSE;
3005 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3008 /* update video num buffers */
3009 player->video_num_buffers = idx;
3010 if (idx == player->ini.num_of_video_bo)
3011 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3014 MMPLAYER_VIDEO_BO_UNLOCK(player);
3018 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3022 /* get bo from list*/
3023 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3024 mm_player_video_bo_info_t *tmp = (mm_player_video_bo_info_t *)l->data;
3025 if (tmp && (tmp->used == FALSE)) {
3026 LOGD("found bo %p to use", tmp->bo);
3028 MMPLAYER_VIDEO_BO_UNLOCK(player);
3029 return tbm_bo_ref(tmp->bo);
3033 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3034 MMPLAYER_VIDEO_BO_UNLOCK(player);
3038 if (player->ini.video_bo_timeout <= 0) {
3039 MMPLAYER_VIDEO_BO_WAIT(player);
3041 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3042 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3049 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3051 mm_player_t *player = (mm_player_t *)data;
3053 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3055 /* send prerolled pkt */
3056 player->video_stream_prerolled = false;
3058 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3060 /* not to send prerolled pkt again */
3061 player->video_stream_prerolled = true;
3065 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3067 mm_player_t *player = (mm_player_t *)data;
3068 MMPlayerVideoStreamDataType *stream = NULL;
3069 GstMemory *mem = NULL;
3072 MMPLAYER_RETURN_IF_FAIL(player);
3073 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3075 if (player->video_stream_prerolled) {
3076 player->video_stream_prerolled = false;
3077 LOGD("skip the prerolled pkt not to send it again");
3081 /* clear stream data structure */
3082 stream = __mmplayer_create_stream_from_pad(pad);
3084 LOGE("failed to alloc stream");
3088 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3090 /* set size and timestamp */
3091 mem = gst_buffer_peek_memory(buffer, 0);
3092 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3093 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3095 /* check zero-copy */
3096 if (player->set_mode.video_zc &&
3097 player->set_mode.media_packet_video_stream &&
3098 gst_is_tizen_memory(mem)) {
3099 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3100 stream->internal_buffer = gst_buffer_ref(buffer);
3101 } else { /* sw codec */
3102 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3105 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3109 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3110 LOGE("failed to send video stream data.");
3117 LOGE("release video stream resource.");
3118 if (gst_is_tizen_memory(mem)) {
3120 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3122 tbm_bo_unref(stream->bo[i]);
3125 /* unref gst buffer */
3126 if (stream->internal_buffer)
3127 gst_buffer_unref(stream->internal_buffer);
3130 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3132 MMPLAYER_FREEIF(stream);
3137 __mmplayer_gst_set_video360_property(mm_player_t *player)
3139 MMPlayerGstElement *videobin = NULL;
3142 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3144 videobin = player->pipeline->videobin;
3146 /* Set spatial media metadata and/or user settings to the element.
3148 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3149 "projection-type", player->video360_metadata.projection_type, NULL);
3151 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3152 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3154 if (player->video360_metadata.full_pano_width_pixels &&
3155 player->video360_metadata.full_pano_height_pixels &&
3156 player->video360_metadata.cropped_area_image_width &&
3157 player->video360_metadata.cropped_area_image_height) {
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3160 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3161 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3162 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3163 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3164 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3168 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3169 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3170 "horizontal-fov", player->video360_horizontal_fov,
3171 "vertical-fov", player->video360_vertical_fov, NULL);
3174 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3175 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3176 "zoom", 1.0f / player->video360_zoom, NULL);
3179 if (player->video360_yaw_radians <= M_PI &&
3180 player->video360_yaw_radians >= -M_PI &&
3181 player->video360_pitch_radians <= M_PI_2 &&
3182 player->video360_pitch_radians >= -M_PI_2) {
3183 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3184 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3185 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3186 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3187 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188 "pose-yaw", player->video360_metadata.init_view_heading,
3189 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3192 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3193 "passthrough", !player->is_video360_enabled, NULL);
3200 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3202 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3203 GList *element_bucket = NULL;
3206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3208 /* create video360 filter */
3209 if (player->is_360_feature_enabled && player->is_content_spherical) {
3210 LOGD("create video360 element");
3211 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3212 __mmplayer_gst_set_video360_property(player);
3216 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3217 LOGD("skip creating the videoconv and rotator");
3218 return MM_ERROR_NONE;
3221 /* in case of sw codec & overlay surface type, except 360 playback.
3222 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3223 LOGD("create video converter: %s", video_csc);
3224 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3226 /* set video rotator */
3227 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3230 *bucket = element_bucket;
3232 return MM_ERROR_NONE;
3234 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3235 g_list_free(element_bucket);
3239 return MM_ERROR_PLAYER_INTERNAL;
3243 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3245 gchar *factory_name = NULL;
3247 switch (surface_type) {
3248 case MM_DISPLAY_SURFACE_OVERLAY:
3249 if (strlen(player->ini.videosink_element_overlay) > 0)
3250 factory_name = player->ini.videosink_element_overlay;
3252 case MM_DISPLAY_SURFACE_REMOTE:
3253 case MM_DISPLAY_SURFACE_NULL:
3254 if (strlen(player->ini.videosink_element_fake) > 0)
3255 factory_name = player->ini.videosink_element_fake;
3258 LOGE("unidentified surface type");
3262 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3263 return factory_name;
3267 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3269 gchar *factory_name = NULL;
3270 MMPlayerGstElement *videobin = NULL;
3275 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3277 videobin = player->pipeline->videobin;
3278 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3280 attrs = MMPLAYER_GET_ATTRS(player);
3282 LOGE("cannot get content attribute");
3283 return MM_ERROR_PLAYER_INTERNAL;
3286 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3287 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3288 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3290 /* support shard memory with S/W codec on HawkP */
3291 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3292 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3293 "use-tbm", use_tbm, NULL);
3297 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3298 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3301 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3303 LOGD("disable last-sample");
3304 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3307 if (player->set_mode.media_packet_video_stream) {
3309 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3310 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3311 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3313 __mmplayer_add_signal_connection(player,
3314 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3315 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3317 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3320 __mmplayer_add_signal_connection(player,
3321 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3322 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3324 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3328 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3329 return MM_ERROR_PLAYER_INTERNAL;
3331 if (videobin[MMPLAYER_V_SINK].gst) {
3332 GstPad *sink_pad = NULL;
3333 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3335 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3336 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3337 gst_object_unref(GST_OBJECT(sink_pad));
3339 LOGE("failed to get sink pad from videosink");
3343 return MM_ERROR_NONE;
3348 * - video overlay surface(arm/x86) : tizenwlsink
3351 __mmplayer_gst_create_video_sink_bin(mm_player_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3354 GList *element_bucket = NULL;
3355 MMPlayerGstElement *first_element = NULL;
3356 MMPlayerGstElement *videobin = NULL;
3357 gchar *videosink_factory_name = NULL;
3360 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3363 videobin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3365 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3367 player->pipeline->videobin = videobin;
3370 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3371 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3372 if (!videobin[MMPLAYER_V_BIN].gst) {
3373 LOGE("failed to create videobin");
3377 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3380 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3381 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3383 /* additional setting for sink plug-in */
3384 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3385 LOGE("failed to set video property");
3389 /* store it as it's sink element */
3390 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3392 /* adding created elements to bin */
3393 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3394 LOGE("failed to add elements");
3398 /* Linking elements in the bucket by added order */
3399 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3400 LOGE("failed to link elements");
3404 /* get first element's sinkpad for creating ghostpad */
3405 first_element = (MMPlayerGstElement *)element_bucket->data;
3406 if (!first_element) {
3407 LOGE("failed to get first element from bucket");
3411 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3413 LOGE("failed to get pad from first element");
3417 /* create ghostpad */
3418 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3419 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3420 LOGE("failed to add ghostpad to videobin");
3423 gst_object_unref(pad);
3425 /* done. free allocated variables */
3426 g_list_free(element_bucket);
3430 return MM_ERROR_NONE;
3433 LOGE("ERROR : releasing videobin");
3434 g_list_free(element_bucket);
3437 gst_object_unref(GST_OBJECT(pad));
3439 /* release videobin with it's childs */
3440 if (videobin[MMPLAYER_V_BIN].gst)
3441 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3443 MMPLAYER_FREEIF(videobin);
3444 player->pipeline->videobin = NULL;
3446 return MM_ERROR_PLAYER_INTERNAL;
3450 __mmplayer_gst_create_plain_text_elements(mm_player_t *player)
3452 GList *element_bucket = NULL;
3453 MMPlayerGstElement *textbin = player->pipeline->textbin;
3455 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3456 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3457 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3458 "signal-handoffs", FALSE,
3461 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3462 __mmplayer_add_signal_connection(player,
3463 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3464 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3466 G_CALLBACK(__mmplayer_update_subtitle),
3469 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3470 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3472 if (!player->play_subtitle) {
3473 LOGD("add textbin sink as sink element of whole pipeline.");
3474 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3477 /* adding created elements to bin */
3478 LOGD("adding created elements to bin");
3479 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3480 LOGE("failed to add elements");
3484 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3485 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3486 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3488 /* linking elements in the bucket by added order. */
3489 LOGD("Linking elements in the bucket by added order.");
3490 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3491 LOGE("failed to link elements");
3495 /* done. free allocated variables */
3496 g_list_free(element_bucket);
3498 if (textbin[MMPLAYER_T_QUEUE].gst) {
3500 GstPad *ghostpad = NULL;
3502 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3504 LOGE("failed to get sink pad of text queue");
3508 ghostpad = gst_ghost_pad_new("text_sink", pad);
3509 gst_object_unref(pad);
3512 LOGE("failed to create ghostpad of textbin");
3516 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3517 LOGE("failed to add ghostpad to textbin");
3518 gst_object_unref(ghostpad);
3523 return MM_ERROR_NONE;
3526 g_list_free(element_bucket);
3528 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3529 LOGE("remove textbin sink from sink list");
3530 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3533 /* release element at __mmplayer_gst_create_text_sink_bin */
3534 return MM_ERROR_PLAYER_INTERNAL;
3538 __mmplayer_gst_create_text_sink_bin(mm_player_t *player)
3540 MMPlayerGstElement *textbin = NULL;
3541 GList *element_bucket = NULL;
3542 int surface_type = 0;
3547 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3550 textbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3552 LOGE("failed to allocate memory for textbin");
3553 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3557 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3558 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3559 if (!textbin[MMPLAYER_T_BIN].gst) {
3560 LOGE("failed to create textbin");
3565 player->pipeline->textbin = textbin;
3568 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3569 LOGD("surface type for subtitle : %d", surface_type);
3570 switch (surface_type) {
3571 case MM_DISPLAY_SURFACE_OVERLAY:
3572 case MM_DISPLAY_SURFACE_NULL:
3573 case MM_DISPLAY_SURFACE_REMOTE:
3574 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3575 LOGE("failed to make plain text elements");
3586 return MM_ERROR_NONE;
3590 LOGD("ERROR : releasing textbin");
3592 g_list_free(element_bucket);
3594 /* release signal */
3595 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3597 /* release element which are not added to bin */
3598 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3599 /* NOTE : skip bin */
3600 if (textbin[i].gst) {
3601 GstObject *parent = NULL;
3602 parent = gst_element_get_parent(textbin[i].gst);
3605 gst_object_unref(GST_OBJECT(textbin[i].gst));
3606 textbin[i].gst = NULL;
3608 gst_object_unref(GST_OBJECT(parent));
3613 /* release textbin with it's childs */
3614 if (textbin[MMPLAYER_T_BIN].gst)
3615 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3617 MMPLAYER_FREEIF(player->pipeline->textbin);
3618 player->pipeline->textbin = NULL;
3621 return MM_ERROR_PLAYER_INTERNAL;
3625 __mmplayer_gst_create_text_pipeline(mm_player_t *player)
3627 MMPlayerGstElement *mainbin = NULL;
3628 MMPlayerGstElement *textbin = NULL;
3629 MMHandleType attrs = 0;
3630 GstElement *subsrc = NULL;
3631 GstElement *subparse = NULL;
3632 gchar *subtitle_uri = NULL;
3633 const gchar *charset = NULL;
3639 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3641 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3643 mainbin = player->pipeline->mainbin;
3645 attrs = MMPLAYER_GET_ATTRS(player);
3647 LOGE("cannot get content attribute");
3648 return MM_ERROR_PLAYER_INTERNAL;
3651 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3652 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3653 LOGE("subtitle uri is not proper filepath.");
3654 return MM_ERROR_PLAYER_INVALID_URI;
3657 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3658 LOGE("failed to get storage info of subtitle path");
3659 return MM_ERROR_PLAYER_INVALID_URI;
3662 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3664 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3665 player->subtitle_language_list = NULL;
3666 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3668 /* create the subtitle source */
3669 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3671 LOGE("failed to create filesrc element");
3674 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3676 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3677 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3679 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3680 LOGW("failed to add queue");
3681 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3682 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3683 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3688 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3690 LOGE("failed to create subparse element");
3694 charset = util_get_charset(subtitle_uri);
3696 LOGD("detected charset is %s", charset);
3697 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3700 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3701 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3703 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3704 LOGW("failed to add subparse");
3705 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3706 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3707 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3711 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3712 LOGW("failed to link subsrc and subparse");
3716 player->play_subtitle = TRUE;
3717 player->adjust_subtitle_pos = 0;
3719 LOGD("play subtitle using subtitle file");
3721 if (player->pipeline->textbin == NULL) {
3722 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3723 LOGE("failed to create text sink bin. continuing without text");
3727 textbin = player->pipeline->textbin;
3729 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3730 LOGW("failed to add textbin");
3732 /* release signal */
3733 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3735 /* release textbin with it's childs */
3736 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3737 MMPLAYER_FREEIF(player->pipeline->textbin);
3738 player->pipeline->textbin = textbin = NULL;
3742 LOGD("link text input selector and textbin ghost pad");
3744 player->textsink_linked = 1;
3745 player->external_text_idx = 0;
3746 LOGI("textsink is linked");
3748 textbin = player->pipeline->textbin;
3749 LOGD("text bin has been created. reuse it.");
3750 player->external_text_idx = 1;
3753 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3754 LOGW("failed to link subparse and textbin");
3758 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3760 LOGE("failed to get sink pad from textsink to probe data");
3764 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3765 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3767 gst_object_unref(pad);
3770 /* create dot. for debugging */
3771 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3774 return MM_ERROR_NONE;
3777 /* release text pipeline resource */
3778 player->textsink_linked = 0;
3780 /* release signal */
3781 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3783 if (player->pipeline->textbin) {
3784 LOGE("remove textbin");
3786 /* release textbin with it's childs */
3787 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3788 MMPLAYER_FREEIF(player->pipeline->textbin);
3789 player->pipeline->textbin = NULL;
3793 /* release subtitle elem */
3794 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3795 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3797 return MM_ERROR_PLAYER_INTERNAL;
3801 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3803 mm_player_t *player = (mm_player_t *)data;
3804 MMMessageParamType msg = {0, };
3805 GstClockTime duration = 0;
3806 gpointer text = NULL;
3807 guint text_size = 0;
3808 gboolean ret = TRUE;
3809 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3813 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3814 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3816 if (player->is_subtitle_force_drop) {
3817 LOGW("subtitle is dropped forcedly.");
3821 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3822 text = mapinfo.data;
3823 text_size = mapinfo.size;
3824 duration = GST_BUFFER_DURATION(buffer);
3826 if (player->set_mode.subtitle_off) {
3827 LOGD("subtitle is OFF.");
3831 if (!text || (text_size == 0)) {
3832 LOGD("There is no subtitle to be displayed.");
3836 msg.data = (void *)text;
3837 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3839 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3841 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3842 gst_buffer_unmap(buffer, &mapinfo);
3849 static GstPadProbeReturn
3850 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3852 mm_player_t *player = (mm_player_t *)u_data;
3853 GstClockTime cur_timestamp = 0;
3854 gint64 adjusted_timestamp = 0;
3855 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3857 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3859 if (player->set_mode.subtitle_off) {
3860 LOGD("subtitle is OFF.");
3864 if (player->adjust_subtitle_pos == 0) {
3865 LOGD("nothing to do");
3869 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3870 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3872 if (adjusted_timestamp < 0) {
3873 LOGD("adjusted_timestamp under zero");
3878 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3879 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3880 GST_TIME_ARGS(cur_timestamp),
3881 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3883 return GST_PAD_PROBE_OK;
3887 __mmplayer_gst_adjust_subtitle_position(mm_player_t *player, int format, int position)
3891 /* check player and subtitlebin are created */
3892 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3893 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3895 if (position == 0) {
3896 LOGD("nothing to do");
3898 return MM_ERROR_NONE;
3902 case MM_PLAYER_POS_FORMAT_TIME:
3904 /* check current postion */
3905 player->adjust_subtitle_pos = position;
3907 LOGD("save adjust_subtitle_pos in player") ;
3913 LOGW("invalid format.");
3915 return MM_ERROR_INVALID_ARGUMENT;
3921 return MM_ERROR_NONE;
3925 * This function is to create audio or video pipeline for playing.
3927 * @param player [in] handle of player
3929 * @return This function returns zero on success.
3934 __mmplayer_gst_create_pipeline(mm_player_t *player)
3936 int ret = MM_ERROR_NONE;
3937 MMPlayerGstElement *mainbin = NULL;
3938 MMHandleType attrs = 0;
3941 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3943 /* get profile attribute */
3944 attrs = MMPLAYER_GET_ATTRS(player);
3946 LOGE("failed to get content attribute");
3950 /* create pipeline handles */
3951 if (player->pipeline) {
3952 LOGE("pipeline should be released before create new one");
3956 player->pipeline = (MMPlayerGstPipelineInfo *)g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3957 if (player->pipeline == NULL)
3960 /* create mainbin */
3961 mainbin = (MMPlayerGstElement *)g_try_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3962 if (mainbin == NULL)
3965 /* create pipeline */
3966 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3967 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3968 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3969 LOGE("failed to create pipeline");
3974 player->pipeline->mainbin = mainbin;
3976 /* create the source and decoder elements */
3977 if (MMPLAYER_IS_MS_BUFF_SRC(player))
3978 ret = __mmplayer_gst_build_es_pipeline(player);
3980 ret = __mmplayer_gst_build_pipeline(player);
3982 if (ret != MM_ERROR_NONE) {
3983 LOGE("failed to create some elements");
3987 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3988 if (__mmplayer_check_subtitle(player)
3989 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
3990 LOGE("failed to create text pipeline");
3993 ret = __mmplayer_gst_add_bus_watch(player);
3994 if (ret != MM_ERROR_NONE) {
3995 LOGE("failed to add bus watch");
4000 return MM_ERROR_NONE;
4003 __mmplayer_gst_destroy_pipeline(player);
4004 return MM_ERROR_PLAYER_INTERNAL;
4008 __mmplayer_reset_gapless_state(mm_player_t *player)
4011 MMPLAYER_RETURN_IF_FAIL(player
4013 && player->pipeline->audiobin
4014 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4016 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4023 __mmplayer_gst_destroy_pipeline(mm_player_t *player)
4026 int ret = MM_ERROR_NONE;
4030 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4032 /* cleanup stuffs */
4033 MMPLAYER_FREEIF(player->type);
4034 player->no_more_pad = FALSE;
4035 player->num_dynamic_pad = 0;
4036 player->demux_pad_index = 0;
4038 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4039 player->subtitle_language_list = NULL;
4040 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4042 __mmplayer_reset_gapless_state(player);
4044 if (player->streamer) {
4045 __mm_player_streaming_initialize(player->streamer, FALSE);
4046 __mm_player_streaming_destroy(player->streamer);
4047 player->streamer = NULL;
4050 /* cleanup unlinked mime type */
4051 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4052 MMPLAYER_FREEIF(player->unlinked_video_mime);
4053 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4055 /* cleanup running stuffs */
4056 __mmplayer_cancel_eos_timer(player);
4058 /* cleanup gst stuffs */
4059 if (player->pipeline) {
4060 MMPlayerGstElement *mainbin = player->pipeline->mainbin;
4061 GstTagList *tag_list = player->pipeline->tag_list;
4063 /* first we need to disconnect all signal hander */
4064 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4067 MMPlayerGstElement *audiobin = player->pipeline->audiobin;
4068 MMPlayerGstElement *videobin = player->pipeline->videobin;
4069 MMPlayerGstElement *textbin = player->pipeline->textbin;
4070 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4071 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4072 gst_object_unref(bus);
4074 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4075 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4076 if (ret != MM_ERROR_NONE) {
4077 LOGE("fail to change state to NULL");
4078 return MM_ERROR_PLAYER_INTERNAL;
4081 LOGW("succeeded in changing state to NULL");
4083 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4086 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4087 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4089 /* free avsysaudiosink
4090 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4091 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4093 MMPLAYER_FREEIF(audiobin);
4094 MMPLAYER_FREEIF(videobin);
4095 MMPLAYER_FREEIF(textbin);
4096 MMPLAYER_FREEIF(mainbin);
4100 gst_tag_list_unref(tag_list);
4102 MMPLAYER_FREEIF(player->pipeline);
4104 MMPLAYER_FREEIF(player->album_art);
4106 if (player->v_stream_caps) {
4107 gst_caps_unref(player->v_stream_caps);
4108 player->v_stream_caps = NULL;
4111 if (player->a_stream_caps) {
4112 gst_caps_unref(player->a_stream_caps);
4113 player->a_stream_caps = NULL;
4116 if (player->s_stream_caps) {
4117 gst_caps_unref(player->s_stream_caps);
4118 player->s_stream_caps = NULL;
4120 __mmplayer_track_destroy(player);
4122 if (player->sink_elements)
4123 g_list_free(player->sink_elements);
4124 player->sink_elements = NULL;
4126 if (player->bufmgr) {
4127 tbm_bufmgr_deinit(player->bufmgr);
4128 player->bufmgr = NULL;
4131 LOGW("finished destroy pipeline");
4139 __mmplayer_gst_realize(mm_player_t *player)
4142 int ret = MM_ERROR_NONE;
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4150 ret = __mmplayer_gst_create_pipeline(player);
4152 LOGE("failed to create pipeline");
4156 /* set pipeline state to READY */
4157 /* NOTE : state change to READY must be performed sync. */
4158 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4159 ret = __mmplayer_gst_set_state(player,
4160 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4162 if (ret != MM_ERROR_NONE) {
4163 /* return error if failed to set state */
4164 LOGE("failed to set READY state");
4168 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4170 /* create dot before error-return. for debugging */
4171 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4179 __mmplayer_gst_unrealize(mm_player_t *player)
4181 int ret = MM_ERROR_NONE;
4185 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4187 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4188 MMPLAYER_PRINT_STATE(player);
4190 /* release miscellaneous information */
4191 __mmplayer_release_misc(player);
4193 /* destroy pipeline */
4194 ret = __mmplayer_gst_destroy_pipeline(player);
4195 if (ret != MM_ERROR_NONE) {
4196 LOGE("failed to destory pipeline");
4200 /* release miscellaneous information.
4201 these info needs to be released after pipeline is destroyed. */
4202 __mmplayer_release_misc_post(player);
4204 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4212 __mmplayer_gst_set_message_callback(mm_player_t *player, MMMessageCallback callback, gpointer user_param)
4217 LOGW("set_message_callback is called with invalid player handle");
4218 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4221 player->msg_cb = callback;
4222 player->msg_cb_param = user_param;
4224 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4228 return MM_ERROR_NONE;
4232 __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile *data)
4234 int ret = MM_ERROR_NONE;
4239 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4240 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4241 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4243 memset(data, 0, sizeof(MMPlayerParseProfile));
4245 if (strstr(uri, "es_buff://")) {
4246 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4247 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4248 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4249 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4251 tmp = g_ascii_strdown(uri, strlen(uri));
4252 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4253 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4255 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4257 } else if (strstr(uri, "mms://")) {
4258 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4259 } else if ((path = strstr(uri, "mem://"))) {
4260 ret = __mmplayer_set_mem_uri(data, path, param);
4262 ret = __mmplayer_set_file_uri(data, uri);
4265 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4266 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4267 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4268 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4270 /* dump parse result */
4271 SECURE_LOGW("incoming uri : %s", uri);
4272 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4273 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4281 __mmplayer_can_do_interrupt(mm_player_t *player)
4283 if (!player || !player->pipeline || !player->attrs) {
4284 LOGW("not initialized");
4288 if (player->audio_stream_render_cb) {
4289 LOGW("not support in pcm extraction mode");
4293 /* check if seeking */
4294 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4295 MMMessageParamType msg_param;
4296 memset(&msg_param, 0, sizeof(MMMessageParamType));
4297 msg_param.code = MM_ERROR_PLAYER_SEEK;
4298 player->seek_state = MMPLAYER_SEEK_NONE;
4299 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4303 /* check other thread */
4304 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4305 LOGW("locked already, cmd state : %d", player->cmd);
4307 /* check application command */
4308 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4309 LOGW("playing.. should wait cmd lock then, will be interrupted");
4311 /* lock will be released at mrp_resource_release_cb() */
4312 MMPLAYER_CMD_LOCK(player);
4315 LOGW("nothing to do");
4318 LOGW("can interrupt immediately");
4322 FAILED: /* with CMD UNLOCKED */
4325 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4330 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4333 mm_player_t *player = NULL;
4337 if (user_data == NULL) {
4338 LOGE("- user_data is null");
4341 player = (mm_player_t *)user_data;
4343 /* do something to release resource here.
4344 * player stop and interrupt forwarding */
4345 if (!__mmplayer_can_do_interrupt(player)) {
4346 LOGW("no need to interrupt, so leave");
4348 MMMessageParamType msg = {0, };
4351 player->interrupted_by_resource = TRUE;
4353 /* get last play position */
4354 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4355 LOGW("failed to get play position.");
4357 msg.union_type = MM_MSG_UNION_TIME;
4358 msg.time.elapsed = pos;
4359 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4361 LOGD("video resource conflict so, resource will be freed by unrealizing");
4362 if (_mmplayer_unrealize((MMHandleType)player))
4363 LOGW("failed to unrealize");
4365 /* lock is called in __mmplayer_can_do_interrupt() */
4366 MMPLAYER_CMD_UNLOCK(player);
4369 if (res == player->video_overlay_resource)
4370 player->video_overlay_resource = FALSE;
4372 player->video_decoder_resource = FALSE;
4380 __mmplayer_initialize_video_roi(mm_player_t *player)
4382 player->video_roi.scale_x = 0.0;
4383 player->video_roi.scale_y = 0.0;
4384 player->video_roi.scale_width = 1.0;
4385 player->video_roi.scale_height = 1.0;
4389 _mmplayer_create_player(MMHandleType handle)
4391 int ret = MM_ERROR_PLAYER_INTERNAL;
4392 bool enabled = false;
4394 mm_player_t *player = MM_PLAYER_CAST(handle);
4398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4400 /* initialize player state */
4401 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4402 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4403 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4404 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4406 /* check current state */
4407 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4409 /* construct attributes */
4410 player->attrs = _mmplayer_construct_attribute(handle);
4412 if (!player->attrs) {
4413 LOGE("Failed to construct attributes");
4417 /* initialize gstreamer with configured parameter */
4418 if (!__mmplayer_init_gstreamer(player)) {
4419 LOGE("Initializing gstreamer failed");
4420 _mmplayer_deconstruct_attribute(handle);
4424 /* create lock. note that g_tread_init() has already called in gst_init() */
4425 g_mutex_init(&player->fsink_lock);
4427 /* create update tag lock */
4428 g_mutex_init(&player->update_tag_lock);
4430 /* create gapless play mutex */
4431 g_mutex_init(&player->gapless_play_thread_mutex);
4433 /* create gapless play cond */
4434 g_cond_init(&player->gapless_play_thread_cond);
4436 /* create gapless play thread */
4437 player->gapless_play_thread =
4438 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4439 if (!player->gapless_play_thread) {
4440 LOGE("failed to create gapless play thread");
4441 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4442 g_mutex_clear(&player->gapless_play_thread_mutex);
4443 g_cond_clear(&player->gapless_play_thread_cond);
4447 player->bus_msg_q = g_queue_new();
4448 if (!player->bus_msg_q) {
4449 LOGE("failed to create queue for bus_msg");
4450 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4454 ret = _mmplayer_initialize_video_capture(player);
4455 if (ret != MM_ERROR_NONE) {
4456 LOGE("failed to initialize video capture");
4460 /* initialize resource manager */
4461 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4462 __resource_release_cb, player, &player->resource_manager)
4463 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4464 LOGE("failed to initialize resource manager");
4465 ret = MM_ERROR_PLAYER_INTERNAL;
4469 /* create video bo lock and cond */
4470 g_mutex_init(&player->video_bo_mutex);
4471 g_cond_init(&player->video_bo_cond);
4473 /* create media stream callback mutex */
4474 g_mutex_init(&player->media_stream_cb_lock);
4476 /* create subtitle info lock and cond */
4477 g_mutex_init(&player->subtitle_info_mutex);
4478 g_cond_init(&player->subtitle_info_cond);
4480 player->streaming_type = STREAMING_SERVICE_NONE;
4482 /* give default value of audio effect setting */
4483 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4484 player->sound.rg_enable = false;
4485 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4487 player->play_subtitle = FALSE;
4488 player->has_closed_caption = FALSE;
4489 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4490 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4491 player->pending_resume = FALSE;
4492 if (player->ini.dump_element_keyword[0][0] == '\0')
4493 player->ini.set_dump_element_flag = FALSE;
4495 player->ini.set_dump_element_flag = TRUE;
4497 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4498 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4499 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4501 /* Set video360 settings to their defaults for just-created player.
4504 player->is_360_feature_enabled = FALSE;
4505 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4506 LOGI("spherical feature info: %d", enabled);
4508 player->is_360_feature_enabled = TRUE;
4510 LOGE("failed to get spherical feature info");
4513 player->is_content_spherical = FALSE;
4514 player->is_video360_enabled = TRUE;
4515 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4516 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4517 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4518 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4519 player->video360_zoom = 1.0f;
4520 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4521 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4523 __mmplayer_initialize_video_roi(player);
4525 /* set player state to null */
4526 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4527 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4531 return MM_ERROR_NONE;
4535 g_mutex_clear(&player->fsink_lock);
4536 /* free update tag lock */
4537 g_mutex_clear(&player->update_tag_lock);
4538 g_queue_free(player->bus_msg_q);
4539 /* free gapless play thread */
4540 if (player->gapless_play_thread) {
4541 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4542 player->gapless_play_thread_exit = TRUE;
4543 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4544 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4546 g_thread_join(player->gapless_play_thread);
4547 player->gapless_play_thread = NULL;
4549 g_mutex_clear(&player->gapless_play_thread_mutex);
4550 g_cond_clear(&player->gapless_play_thread_cond);
4553 /* release attributes */
4554 _mmplayer_deconstruct_attribute(handle);
4562 __mmplayer_init_gstreamer(mm_player_t *player)
4564 static gboolean initialized = FALSE;
4565 static const int max_argc = 50;
4567 gchar **argv = NULL;
4568 gchar **argv2 = NULL;
4574 LOGD("gstreamer already initialized.");
4579 argc = malloc(sizeof(int));
4580 argv = malloc(sizeof(gchar *) * max_argc);
4581 argv2 = malloc(sizeof(gchar *) * max_argc);
4583 if (!argc || !argv || !argv2)
4586 memset(argv, 0, sizeof(gchar *) * max_argc);
4587 memset(argv2, 0, sizeof(gchar *) * max_argc);
4591 argv[0] = g_strdup("mmplayer");
4594 for (i = 0; i < 5; i++) {
4595 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4596 if (strlen(player->ini.gst_param[i]) > 0) {
4597 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4602 /* we would not do fork for scanning plugins */
4603 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4606 /* check disable registry scan */
4607 if (player->ini.skip_rescan) {
4608 argv[*argc] = g_strdup("--gst-disable-registry-update");
4612 /* check disable segtrap */
4613 if (player->ini.disable_segtrap) {
4614 argv[*argc] = g_strdup("--gst-disable-segtrap");
4618 LOGD("initializing gstreamer with following parameter");
4619 LOGD("argc : %d", *argc);
4622 for (i = 0; i < arg_count; i++) {
4624 LOGD("argv[%d] : %s", i, argv2[i]);
4627 /* initializing gstreamer */
4628 if (!gst_init_check(argc, &argv, &err)) {
4629 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4636 for (i = 0; i < arg_count; i++) {
4637 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4638 MMPLAYER_FREEIF(argv2[i]);
4641 MMPLAYER_FREEIF(argv);
4642 MMPLAYER_FREEIF(argv2);
4643 MMPLAYER_FREEIF(argc);
4653 for (i = 0; i < arg_count; i++) {
4654 LOGD("free[%d] : %s", i, argv2[i]);
4655 MMPLAYER_FREEIF(argv2[i]);
4658 MMPLAYER_FREEIF(argv);
4659 MMPLAYER_FREEIF(argv2);
4660 MMPLAYER_FREEIF(argc);
4666 __mmplayer_check_async_state_transition(mm_player_t *player)
4668 GstState element_state = GST_STATE_VOID_PENDING;
4669 GstState element_pending_state = GST_STATE_VOID_PENDING;
4670 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4671 GstElement *element = NULL;
4672 gboolean async = FALSE;
4674 /* check player handle */
4675 MMPLAYER_RETURN_IF_FAIL(player &&
4677 player->pipeline->mainbin &&
4678 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4681 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4683 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4684 LOGD("don't need to check the pipeline state");
4688 MMPLAYER_PRINT_STATE(player);
4690 /* wait for state transition */
4691 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4692 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4694 if (ret == GST_STATE_CHANGE_FAILURE) {
4695 LOGE(" [%s] state : %s pending : %s",
4696 GST_ELEMENT_NAME(element),
4697 gst_element_state_get_name(element_state),
4698 gst_element_state_get_name(element_pending_state));
4700 /* dump state of all element */
4701 __mmplayer_dump_pipeline_state(player);
4706 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4711 _mmplayer_destroy(MMHandleType handle)
4713 mm_player_t *player = MM_PLAYER_CAST(handle);
4717 /* check player handle */
4718 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4720 /* destroy can called at anytime */
4721 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4723 /* check async state transition */
4724 __mmplayer_check_async_state_transition(player);
4726 /* release gapless play thread */
4727 if (player->gapless_play_thread) {
4728 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4729 player->gapless_play_thread_exit = TRUE;
4730 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4733 LOGD("waitting for gapless play thread exit");
4734 g_thread_join(player->gapless_play_thread);
4735 g_mutex_clear(&player->gapless_play_thread_mutex);
4736 g_cond_clear(&player->gapless_play_thread_cond);
4737 LOGD("gapless play thread released");
4740 _mmplayer_release_video_capture(player);
4742 /* de-initialize resource manager */
4743 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4744 player->resource_manager))
4745 LOGE("failed to deinitialize resource manager");
4747 /* release pipeline */
4748 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4749 LOGE("failed to destory pipeline");
4750 return MM_ERROR_PLAYER_INTERNAL;
4753 g_queue_free(player->bus_msg_q);
4755 /* release subtitle info lock and cond */
4756 g_mutex_clear(&player->subtitle_info_mutex);
4757 g_cond_clear(&player->subtitle_info_cond);
4759 __mmplayer_release_dump_list(player->dump_list);
4761 /* release miscellaneous information */
4762 __mmplayer_release_misc(player);
4764 /* release miscellaneous information.
4765 these info needs to be released after pipeline is destroyed. */
4766 __mmplayer_release_misc_post(player);
4768 /* release attributes */
4769 _mmplayer_deconstruct_attribute(handle);
4772 g_mutex_clear(&player->fsink_lock);
4775 g_mutex_clear(&player->update_tag_lock);
4777 /* release video bo lock and cond */
4778 g_mutex_clear(&player->video_bo_mutex);
4779 g_cond_clear(&player->video_bo_cond);
4781 /* release media stream callback lock */
4782 g_mutex_clear(&player->media_stream_cb_lock);
4786 return MM_ERROR_NONE;
4790 _mmplayer_realize(MMHandleType hplayer)
4792 mm_player_t *player = (mm_player_t *)hplayer;
4795 MMHandleType attrs = 0;
4796 int ret = MM_ERROR_NONE;
4800 /* check player handle */
4801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4803 /* check current state */
4804 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4806 attrs = MMPLAYER_GET_ATTRS(player);
4808 LOGE("fail to get attributes.");
4809 return MM_ERROR_PLAYER_INTERNAL;
4811 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4812 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4814 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4815 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4817 if (ret != MM_ERROR_NONE) {
4818 LOGE("failed to parse profile");
4823 if (uri && (strstr(uri, "es_buff://"))) {
4824 if (strstr(uri, "es_buff://push_mode"))
4825 player->es_player_push_mode = TRUE;
4827 player->es_player_push_mode = FALSE;
4830 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4831 LOGW("mms protocol is not supported format.");
4832 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4835 if (MMPLAYER_IS_STREAMING(player))
4836 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4838 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4840 player->smooth_streaming = FALSE;
4841 player->videodec_linked = 0;
4842 player->audiodec_linked = 0;
4843 player->textsink_linked = 0;
4844 player->is_external_subtitle_present = FALSE;
4845 player->is_external_subtitle_added_now = FALSE;
4846 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4847 player->video360_metadata.is_spherical = -1;
4848 player->is_openal_plugin_used = FALSE;
4849 player->demux_pad_index = 0;
4850 player->subtitle_language_list = NULL;
4851 player->is_subtitle_force_drop = FALSE;
4852 player->last_multiwin_status = FALSE;
4854 __mmplayer_track_initialize(player);
4855 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4857 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4858 gint prebuffer_ms = 0, rebuffer_ms = 0;
4860 player->streamer = __mm_player_streaming_create();
4861 __mm_player_streaming_initialize(player->streamer, TRUE);
4863 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4864 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4866 if (prebuffer_ms > 0) {
4867 prebuffer_ms = MAX(prebuffer_ms, 1000);
4868 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4871 if (rebuffer_ms > 0) {
4872 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4873 rebuffer_ms = MAX(rebuffer_ms, 1000);
4874 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4877 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4878 player->streamer->buffering_req.rebuffer_time);
4881 /* realize pipeline */
4882 ret = __mmplayer_gst_realize(player);
4883 if (ret != MM_ERROR_NONE)
4884 LOGE("fail to realize the player.");
4886 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4894 _mmplayer_unrealize(MMHandleType hplayer)
4896 mm_player_t *player = (mm_player_t *)hplayer;
4897 int ret = MM_ERROR_NONE;
4901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4903 MMPLAYER_CMD_UNLOCK(player);
4904 /* destroy the gst bus msg thread which is created during realize.
4905 this funct have to be called before getting cmd lock. */
4906 __mmplayer_bus_msg_thread_destroy(player);
4907 MMPLAYER_CMD_LOCK(player);
4909 /* check current state */
4910 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4912 /* check async state transition */
4913 __mmplayer_check_async_state_transition(player);
4915 /* unrealize pipeline */
4916 ret = __mmplayer_gst_unrealize(player);
4918 /* set asm stop if success */
4919 if (MM_ERROR_NONE == ret) {
4920 if (!player->interrupted_by_resource) {
4921 if (player->video_decoder_resource != NULL) {
4922 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4923 player->video_decoder_resource);
4924 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4925 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4927 player->video_decoder_resource = NULL;
4930 if (player->video_overlay_resource != NULL) {
4931 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4932 player->video_overlay_resource);
4933 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4934 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4936 player->video_overlay_resource = NULL;
4939 ret = mm_resource_manager_commit(player->resource_manager);
4940 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4941 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4944 LOGE("failed and don't change asm state to stop");
4952 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4954 mm_player_t *player = (mm_player_t *)hplayer;
4956 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4958 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4962 _mmplayer_get_state(MMHandleType hplayer, int *state)
4964 mm_player_t *player = (mm_player_t *)hplayer;
4966 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4968 *state = MMPLAYER_CURRENT_STATE(player);
4970 return MM_ERROR_NONE;
4975 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
4977 mm_player_t *player = (mm_player_t *)hplayer;
4978 GstElement *vol_element = NULL;
4983 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4985 LOGD("volume [L]=%f:[R]=%f",
4986 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
4988 /* invalid factor range or not */
4989 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
4990 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
4991 LOGE("Invalid factor!(valid factor:0~1.0)");
4992 return MM_ERROR_INVALID_ARGUMENT;
4996 /* not support to set other value into each channel */
4997 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
4998 return MM_ERROR_INVALID_ARGUMENT;
5000 /* Save volume to handle. Currently the first array element will be saved. */
5001 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5003 /* check pipeline handle */
5004 if (!player->pipeline || !player->pipeline->audiobin) {
5005 LOGD("audiobin is not created yet");
5006 LOGD("but, current stored volume will be set when it's created.");
5008 /* NOTE : stored volume will be used in create_audiobin
5009 * returning MM_ERROR_NONE here makes application to able to
5010 * set volume at anytime.
5012 return MM_ERROR_NONE;
5015 /* setting volume to volume element */
5016 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5019 LOGD("volume is set [%f]", player->sound.volume);
5020 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5025 return MM_ERROR_NONE;
5029 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType *volume)
5031 mm_player_t *player = (mm_player_t *)hplayer;
5036 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5037 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5039 /* returning stored volume */
5040 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5041 volume->level[i] = player->sound.volume;
5045 return MM_ERROR_NONE;
5049 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5051 mm_player_t *player = (mm_player_t *)hplayer;
5052 GstElement *vol_element = NULL;
5056 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5058 /* mute value shoud 0 or 1 */
5059 if (mute != 0 && mute != 1) {
5060 LOGE("bad mute value");
5062 /* FIXIT : definitly, we need _BAD_PARAM error code */
5063 return MM_ERROR_INVALID_ARGUMENT;
5066 player->sound.mute = mute;
5068 /* just hold mute value if pipeline is not ready */
5069 if (!player->pipeline || !player->pipeline->audiobin) {
5070 LOGD("pipeline is not ready. holding mute value");
5071 return MM_ERROR_NONE;
5074 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5076 /* NOTE : volume will only created when the bt is enabled */
5078 LOGD("mute : %d", mute);
5079 g_object_set(vol_element, "mute", mute, NULL);
5081 LOGD("volume elemnet is not created. using volume in audiosink");
5085 return MM_ERROR_NONE;
5089 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5091 mm_player_t *player = (mm_player_t *)hplayer;
5095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5096 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5098 /* just hold mute value if pipeline is not ready */
5099 if (!player->pipeline || !player->pipeline->audiobin) {
5100 LOGD("pipeline is not ready. returning stored value");
5101 *pmute = player->sound.mute;
5102 return MM_ERROR_NONE;
5105 *pmute = player->sound.mute;
5109 return MM_ERROR_NONE;
5113 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5115 mm_player_t *player = (mm_player_t *)hplayer;
5119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5121 player->video_stream_changed_cb = callback;
5122 player->video_stream_changed_cb_user_param = user_param;
5123 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5127 return MM_ERROR_NONE;
5131 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5133 mm_player_t *player = (mm_player_t *)hplayer;
5137 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5139 player->audio_stream_changed_cb = callback;
5140 player->audio_stream_changed_cb_user_param = user_param;
5141 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5145 return MM_ERROR_NONE;
5149 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5151 mm_player_t *player = (mm_player_t *)hplayer;
5155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5157 player->audio_stream_render_cb = callback;
5158 player->audio_stream_cb_user_param = user_param;
5159 player->audio_stream_sink_sync = sync;
5160 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5164 return MM_ERROR_NONE;
5168 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5170 mm_player_t *player = (mm_player_t *)hplayer;
5174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5176 if (callback && !player->bufmgr)
5177 player->bufmgr = tbm_bufmgr_init(-1);
5179 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5180 player->video_stream_cb = callback;
5181 player->video_stream_cb_user_param = user_param;
5183 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5187 return MM_ERROR_NONE;
5191 _mmplayer_start(MMHandleType hplayer)
5193 mm_player_t *player = (mm_player_t *)hplayer;
5194 gint ret = MM_ERROR_NONE;
5198 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5200 /* check current state */
5201 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5203 /* start pipeline */
5204 ret = __mmplayer_gst_start(player);
5205 if (ret != MM_ERROR_NONE)
5206 LOGE("failed to start player.");
5208 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5209 LOGD("force playing start even during buffering");
5210 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5218 /* NOTE: post "not supported codec message" to application
5219 * when one codec is not found during AUTOPLUGGING in MSL.
5220 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5221 * And, if any codec is not found, don't send message here.
5222 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5225 __mmplayer_handle_missed_plugin(mm_player_t *player)
5227 MMMessageParamType msg_param;
5228 memset(&msg_param, 0, sizeof(MMMessageParamType));
5229 gboolean post_msg_direct = FALSE;
5233 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5236 player->not_supported_codec, player->can_support_codec);
5238 if (player->not_found_demuxer) {
5239 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5240 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5242 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5243 MMPLAYER_FREEIF(msg_param.data);
5245 return MM_ERROR_NONE;
5248 if (player->not_supported_codec) {
5249 if (player->can_support_codec) {
5250 // There is one codec to play
5251 post_msg_direct = TRUE;
5253 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5254 post_msg_direct = TRUE;
5257 if (post_msg_direct) {
5258 MMMessageParamType msg_param;
5259 memset(&msg_param, 0, sizeof(MMMessageParamType));
5261 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5262 LOGW("not found AUDIO codec, posting error code to application.");
5264 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5265 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5266 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5267 LOGW("not found VIDEO codec, posting error code to application.");
5269 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5270 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5273 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5275 MMPLAYER_FREEIF(msg_param.data);
5277 return MM_ERROR_NONE;
5279 // no any supported codec case
5280 LOGW("not found any codec, posting error code to application.");
5282 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5283 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5284 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5286 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5287 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5290 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5292 MMPLAYER_FREEIF(msg_param.data);
5298 return MM_ERROR_NONE;
5302 __mmplayer_check_pipeline(mm_player_t *player)
5304 GstState element_state = GST_STATE_VOID_PENDING;
5305 GstState element_pending_state = GST_STATE_VOID_PENDING;
5307 int ret = MM_ERROR_NONE;
5309 if (!player->gapless.reconfigure)
5312 LOGW("pipeline is under construction.");
5314 MMPLAYER_PLAYBACK_LOCK(player);
5315 MMPLAYER_PLAYBACK_UNLOCK(player);
5317 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5319 /* wait for state transition */
5320 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5321 if (ret == GST_STATE_CHANGE_FAILURE)
5322 LOGE("failed to change pipeline state within %d sec", timeout);
5325 /* NOTE : it should be able to call 'stop' anytime*/
5327 _mmplayer_stop(MMHandleType hplayer)
5329 mm_player_t *player = (mm_player_t *)hplayer;
5330 int ret = MM_ERROR_NONE;
5334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5336 /* check current state */
5337 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5339 /* check pipline building state */
5340 __mmplayer_check_pipeline(player);
5341 __mmplayer_reset_gapless_state(player);
5343 /* NOTE : application should not wait for EOS after calling STOP */
5344 __mmplayer_cancel_eos_timer(player);
5347 player->seek_state = MMPLAYER_SEEK_NONE;
5350 ret = __mmplayer_gst_stop(player);
5352 if (ret != MM_ERROR_NONE)
5353 LOGE("failed to stop player.");
5361 _mmplayer_pause(MMHandleType hplayer)
5363 mm_player_t *player = (mm_player_t *)hplayer;
5364 gint64 pos_nsec = 0;
5365 gboolean async = FALSE;
5366 gint ret = MM_ERROR_NONE;
5370 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5372 /* check current state */
5373 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5375 /* check pipline building state */
5376 __mmplayer_check_pipeline(player);
5378 switch (MMPLAYER_CURRENT_STATE(player)) {
5379 case MM_PLAYER_STATE_READY:
5381 /* check prepare async or not.
5382 * In the case of streaming playback, it's recommned to avoid blocking wait.
5384 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5385 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5387 /* Changing back sync of rtspsrc to async */
5388 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5389 LOGD("async prepare working mode for rtsp");
5395 case MM_PLAYER_STATE_PLAYING:
5397 /* NOTE : store current point to overcome some bad operation
5398 *(returning zero when getting current position in paused state) of some
5401 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5402 LOGW("getting current position failed in paused");
5404 player->last_position = pos_nsec;
5406 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5407 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5408 This causes problem is position calculation during normal pause resume scenarios also.
5409 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5410 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5411 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5412 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5418 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5419 LOGD("doing async pause in case of ms buff src");
5423 /* pause pipeline */
5424 ret = __mmplayer_gst_pause(player, async);
5426 if (ret != MM_ERROR_NONE)
5427 LOGE("failed to pause player. ret : 0x%x", ret);
5429 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5430 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5431 LOGE("failed to update display_rotation");
5439 /* in case of streaming, pause could take long time.*/
5441 _mmplayer_abort_pause(MMHandleType hplayer)
5443 mm_player_t *player = (mm_player_t *)hplayer;
5444 int ret = MM_ERROR_NONE;
5448 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5450 player->pipeline->mainbin,
5451 MM_ERROR_PLAYER_NOT_INITIALIZED);
5453 LOGD("set the pipeline state to READY");
5455 /* set state to READY */
5456 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5457 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5458 if (ret != MM_ERROR_NONE) {
5459 LOGE("fail to change state to READY");
5460 return MM_ERROR_PLAYER_INTERNAL;
5463 LOGD("succeeded in changing state to READY");
5468 _mmplayer_resume(MMHandleType hplayer)
5470 mm_player_t *player = (mm_player_t *)hplayer;
5471 int ret = MM_ERROR_NONE;
5472 gboolean async = FALSE;
5476 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5478 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5479 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5480 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5484 /* Changing back sync mode rtspsrc to async */
5485 LOGD("async resume for rtsp case");
5489 /* check current state */
5490 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5492 ret = __mmplayer_gst_resume(player, async);
5493 if (ret != MM_ERROR_NONE)
5494 LOGE("failed to resume player.");
5496 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5497 LOGD("force resume even during buffering");
5498 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5507 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5509 mm_player_t *player = (mm_player_t *)hplayer;
5510 gint64 pos_nsec = 0;
5511 int ret = MM_ERROR_NONE;
5513 signed long long start = 0, stop = 0;
5514 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5517 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5518 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5520 /* The sound of video is not supported under 0.0 and over 2.0. */
5521 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5522 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5525 _mmplayer_set_mute(hplayer, mute);
5527 if (player->playback_rate == rate)
5528 return MM_ERROR_NONE;
5530 /* If the position is reached at start potion during fast backward, EOS is posted.
5531 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5533 player->playback_rate = rate;
5535 current_state = MMPLAYER_CURRENT_STATE(player);
5537 if (current_state != MM_PLAYER_STATE_PAUSED)
5538 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5540 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5542 if ((current_state == MM_PLAYER_STATE_PAUSED)
5543 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5544 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5545 pos_nsec = player->last_position;
5550 stop = GST_CLOCK_TIME_NONE;
5552 start = GST_CLOCK_TIME_NONE;
5556 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5557 player->playback_rate,
5559 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5560 GST_SEEK_TYPE_SET, start,
5561 GST_SEEK_TYPE_SET, stop)) {
5562 LOGE("failed to set speed playback");
5563 return MM_ERROR_PLAYER_SEEK;
5566 LOGD("succeeded to set speed playback as %0.1f", rate);
5570 return MM_ERROR_NONE;;
5574 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5576 mm_player_t *player = (mm_player_t *)hplayer;
5577 int ret = MM_ERROR_NONE;
5581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5583 /* check pipline building state */
5584 __mmplayer_check_pipeline(player);
5586 ret = __mmplayer_gst_set_position(player, position, FALSE);
5594 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5596 mm_player_t *player = (mm_player_t *)hplayer;
5597 int ret = MM_ERROR_NONE;
5599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5601 ret = __mmplayer_gst_get_position(player, position);
5607 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5609 mm_player_t *player = (mm_player_t *)hplayer;
5610 int ret = MM_ERROR_NONE;
5612 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5613 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5615 if (g_strrstr(player->type, "video/mpegts"))
5616 __mmplayer_update_duration_value(player);
5618 *duration = player->duration;
5623 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5625 mm_player_t *player = (mm_player_t *)hplayer;
5626 int ret = MM_ERROR_NONE;
5628 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5630 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5636 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5638 mm_player_t *player = (mm_player_t *)hplayer;
5639 int ret = MM_ERROR_NONE;
5643 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5645 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5653 __mmplayer_is_midi_type(gchar *str_caps)
5655 if ((g_strrstr(str_caps, "audio/midi")) ||
5656 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5657 (g_strrstr(str_caps, "application/x-smaf")) ||
5658 (g_strrstr(str_caps, "audio/x-imelody")) ||
5659 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5660 (g_strrstr(str_caps, "audio/xmf")) ||
5661 (g_strrstr(str_caps, "audio/mxmf"))) {
5670 __mmplayer_is_only_mp3_type(gchar *str_caps)
5672 if (g_strrstr(str_caps, "application/x-id3") ||
5673 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5679 __mmplayer_set_audio_attrs(mm_player_t *player, GstCaps *caps)
5681 GstStructure *caps_structure = NULL;
5682 gint samplerate = 0;
5686 MMPLAYER_RETURN_IF_FAIL(player && caps);
5688 caps_structure = gst_caps_get_structure(caps, 0);
5690 /* set stream information */
5691 gst_structure_get_int(caps_structure, "rate", &samplerate);
5692 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5694 gst_structure_get_int(caps_structure, "channels", &channels);
5695 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5697 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5701 __mmplayer_update_content_type_info(mm_player_t *player)
5704 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5706 if (__mmplayer_is_midi_type(player->type)) {
5707 player->bypass_audio_effect = TRUE;
5711 if (!player->streamer) {
5712 LOGD("no need to check streaming type");
5716 if (g_strrstr(player->type, "application/x-hls")) {
5717 /* If it can't know exact type when it parses uri because of redirection case,
5718 * it will be fixed by typefinder or when doing autoplugging.
5720 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5721 player->streamer->is_adaptive_streaming = TRUE;
5722 } else if (g_strrstr(player->type, "application/dash+xml")) {
5723 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5724 player->streamer->is_adaptive_streaming = TRUE;
5727 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5728 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5729 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5731 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5732 if (player->streamer->is_adaptive_streaming)
5733 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5735 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5739 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5744 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5745 GstCaps *caps, gpointer data)
5747 mm_player_t *player = (mm_player_t *)data;
5752 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5754 /* store type string */
5755 MMPLAYER_FREEIF(player->type);
5756 player->type = gst_caps_to_string(caps);
5758 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5759 player, player->type, probability, gst_caps_get_size(caps));
5761 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5762 (g_strrstr(player->type, "audio/x-raw-int"))) {
5763 LOGE("not support media format");
5765 if (player->msg_posted == FALSE) {
5766 MMMessageParamType msg_param;
5767 memset(&msg_param, 0, sizeof(MMMessageParamType));
5769 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5770 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5772 /* don't post more if one was sent already */
5773 player->msg_posted = TRUE;
5778 __mmplayer_update_content_type_info(player);
5780 pad = gst_element_get_static_pad(tf, "src");
5782 LOGE("fail to get typefind src pad.");
5786 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5787 gboolean async = FALSE;
5788 LOGE("failed to autoplug %s", player->type);
5790 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5792 if (async && player->msg_posted == FALSE)
5793 __mmplayer_handle_missed_plugin(player);
5799 gst_object_unref(GST_OBJECT(pad));
5807 __mmplayer_gst_make_decodebin(mm_player_t *player)
5809 GstElement *decodebin = NULL;
5813 /* create decodebin */
5814 decodebin = gst_element_factory_make("decodebin", NULL);
5817 LOGE("fail to create decodebin");
5821 /* raw pad handling signal */
5822 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5823 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5825 /* no-more-pad pad handling signal */
5826 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5827 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5829 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5830 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5832 /* This signal is emitted when a pad for which there is no further possible
5833 decoding is added to the decodebin.*/
5834 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5835 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5837 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5838 before looking for any elements that can handle that stream.*/
5839 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5840 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5842 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5843 before looking for any elements that can handle that stream.*/
5844 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5845 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5847 /* This signal is emitted once decodebin has finished decoding all the data.*/
5848 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5849 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5851 /* This signal is emitted when a element is added to the bin.*/
5852 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5853 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5860 __mmplayer_gst_make_queue2(mm_player_t *player)
5862 GstElement *queue2 = NULL;
5863 gint64 dur_bytes = 0L;
5864 MMPlayerGstElement *mainbin = NULL;
5865 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5868 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5870 mainbin = player->pipeline->mainbin;
5872 queue2 = gst_element_factory_make("queue2", "queue2");
5874 LOGE("failed to create buffering queue element");
5878 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5879 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5881 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5883 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5884 * skip the pull mode(file or ring buffering) setting. */
5885 if (dur_bytes > 0) {
5886 if (!g_strrstr(player->type, "video/mpegts")) {
5887 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5888 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5894 __mm_player_streaming_set_queue2(player->streamer,
5898 (guint64)dur_bytes); /* no meaning at the moment */
5904 __mmplayer_gst_create_decoder(mm_player_t *player, GstPad *srcpad, const GstCaps *caps)
5906 MMPlayerGstElement *mainbin = NULL;
5907 GstElement *decodebin = NULL;
5908 GstElement *queue2 = NULL;
5909 GstPad *sinkpad = NULL;
5910 GstPad *qsrcpad = NULL;
5913 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5915 mainbin = player->pipeline->mainbin;
5917 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5919 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5920 LOGW("need to check: muxed buffer is not null");
5923 queue2 = __mmplayer_gst_make_queue2(player);
5925 LOGE("failed to make queue2");
5929 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5930 LOGE("failed to add buffering queue");
5934 sinkpad = gst_element_get_static_pad(queue2, "sink");
5935 qsrcpad = gst_element_get_static_pad(queue2, "src");
5937 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5938 LOGE("failed to link [%s:%s]-[%s:%s]",
5939 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5943 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5944 LOGE("failed to sync queue2 state with parent");
5948 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5949 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5953 gst_object_unref(GST_OBJECT(sinkpad));
5957 /* create decodebin */
5958 decodebin = __mmplayer_gst_make_decodebin(player);
5960 LOGE("failed to make decodebin");
5964 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5965 LOGE("failed to add decodebin");
5969 /* to force caps on the decodebin element and avoid reparsing stuff by
5970 * typefind. It also avoids a deadlock in the way typefind activates pads in
5971 * the state change */
5972 g_object_set(decodebin, "sink-caps", caps, NULL);
5974 sinkpad = gst_element_get_static_pad(decodebin, "sink");
5976 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
5977 LOGE("failed to link [%s:%s]-[%s:%s]",
5978 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5982 gst_object_unref(GST_OBJECT(sinkpad));
5985 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
5986 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
5988 /* set decodebin property about buffer in streaming playback. *
5989 * in case of HLS/DASH, it does not need to have big buffer *
5990 * because it is kind of adaptive streaming. */
5991 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
5992 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
5993 gint high_percent = 0;
5995 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
5996 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5998 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6000 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6002 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6003 "high-percent", high_percent,
6004 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6005 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6006 "max-size-buffers", 0, NULL); // disable or automatic
6009 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6010 LOGE("failed to sync decodebin state with parent");
6021 gst_object_unref(GST_OBJECT(sinkpad));
6024 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6025 * You need to explicitly set elements to the NULL state before
6026 * dropping the final reference, to allow them to clean up.
6028 gst_element_set_state(queue2, GST_STATE_NULL);
6030 /* And, it still has a parent "player".
6031 * You need to let the parent manage the object instead of unreffing the object directly.
6033 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6034 gst_object_unref(queue2);
6039 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6040 * You need to explicitly set elements to the NULL state before
6041 * dropping the final reference, to allow them to clean up.
6043 gst_element_set_state(decodebin, GST_STATE_NULL);
6045 /* And, it still has a parent "player".
6046 * You need to let the parent manage the object instead of unreffing the object directly.
6049 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6050 gst_object_unref(decodebin);
6058 __mmplayer_check_not_supported_codec(mm_player_t *player, const gchar *factory_class, const gchar *mime)
6062 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6063 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6065 LOGD("class : %s, mime : %s", factory_class, mime);
6067 /* add missing plugin */
6068 /* NOTE : msl should check missing plugin for image mime type.
6069 * Some motion jpeg clips can have playable audio track.
6070 * So, msl have to play audio after displaying popup written video format not supported.
6072 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6073 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6074 LOGD("not found demuxer");
6075 player->not_found_demuxer = TRUE;
6076 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6082 if (!g_strrstr(factory_class, "Demuxer")) {
6083 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6084 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6085 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6087 /* check that clip have multi tracks or not */
6088 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6089 LOGD("video plugin is already linked");
6091 LOGW("add VIDEO to missing plugin");
6092 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6093 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6095 } else if (g_str_has_prefix(mime, "audio")) {
6096 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6097 LOGD("audio plugin is already linked");
6099 LOGW("add AUDIO to missing plugin");
6100 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6101 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6109 return MM_ERROR_NONE;
6113 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6115 mm_player_t *player = (mm_player_t *)data;
6119 MMPLAYER_RETURN_IF_FAIL(player);
6121 /* remove fakesink. */
6122 if (!__mmplayer_gst_remove_fakesink(player,
6123 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6124 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6125 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6126 * source element are not same. To overcome this situation, this function will called
6127 * several places and several times. Therefore, this is not an error case.
6132 LOGD("[handle: %p] pipeline has completely constructed", player);
6134 if ((player->ini.async_start) &&
6135 (player->msg_posted == FALSE) &&
6136 (player->cmd >= MMPLAYER_COMMAND_START))
6137 __mmplayer_handle_missed_plugin(player);
6139 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6143 __mmplayer_check_profile(void)
6146 static int profile_tv = -1;
6148 if (__builtin_expect(profile_tv != -1, 1))
6151 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6152 switch (*profileName) {
6167 __mmplayer_get_next_uri(mm_player_t *player)
6169 MMPlayerParseProfile profile;
6171 guint num_of_list = 0;
6174 num_of_list = g_list_length(player->uri_info.uri_list);
6175 uri_idx = player->uri_info.uri_idx;
6177 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6178 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6179 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6181 LOGW("next uri does not exist");
6185 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6186 LOGE("failed to parse profile");
6190 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6191 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6192 LOGW("uri type is not supported(%d)", profile.uri_type);
6196 LOGD("success to find next uri %d", uri_idx);
6200 if (uri_idx == num_of_list) {
6201 LOGE("failed to find next uri");
6205 player->uri_info.uri_idx = uri_idx;
6206 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6208 if (mm_attrs_commit_all(player->attrs)) {
6209 LOGE("failed to commit");
6213 SECURE_LOGD("next playback uri: %s", uri);
6218 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6220 #define REPEAT_COUNT_INFINITELY -1
6221 #define REPEAT_COUNT_MIN 2
6223 MMHandleType attrs = 0;
6227 guint num_of_list = 0;
6228 int profile_tv = -1;
6232 LOGD("checking for gapless play option");
6234 if (player->pipeline->textbin) {
6235 LOGE("subtitle path is enabled. gapless play is not supported.");
6239 attrs = MMPLAYER_GET_ATTRS(player);
6241 LOGE("fail to get attributes.");
6245 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6247 /* gapless playback is not supported in case of video at TV profile. */
6248 profile_tv = __mmplayer_check_profile();
6249 if (profile_tv && video) {
6250 LOGW("not support video gapless playback");
6254 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6255 LOGE("failed to get play count");
6257 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6258 LOGE("failed to get gapless mode");
6260 /* check repeat count in case of audio */
6262 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6263 LOGW("gapless is disabled");
6267 num_of_list = g_list_length(player->uri_info.uri_list);
6269 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6271 if (num_of_list == 0) {
6272 /* audio looping path */
6273 if (count >= REPEAT_COUNT_MIN) {
6274 /* decrease play count */
6275 /* we succeeded to rewind. update play count and then wait for next EOS */
6277 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6278 /* commit attribute */
6279 if (mm_attrs_commit_all(attrs))
6280 LOGE("failed to commit attribute");
6282 } else if (count != REPEAT_COUNT_INFINITELY) {
6283 LOGD("there is no next uri and no repeat");
6286 LOGD("looping cnt %d", count);
6288 /* gapless playback path */
6289 if (!__mmplayer_get_next_uri(player)) {
6290 LOGE("failed to get next uri");
6297 LOGE("unable to play gapless path. EOS will be posted soon");
6302 __mmplayer_initialize_gapless_play(mm_player_t *player)
6308 player->smooth_streaming = FALSE;
6309 player->videodec_linked = 0;
6310 player->audiodec_linked = 0;
6311 player->textsink_linked = 0;
6312 player->is_external_subtitle_present = FALSE;
6313 player->is_external_subtitle_added_now = FALSE;
6314 player->not_supported_codec = MISSING_PLUGIN_NONE;
6315 player->can_support_codec = FOUND_PLUGIN_NONE;
6316 player->pending_seek.is_pending = false;
6317 player->pending_seek.pos = 0;
6318 player->msg_posted = FALSE;
6319 player->has_many_types = FALSE;
6320 player->no_more_pad = FALSE;
6321 player->not_found_demuxer = 0;
6322 player->seek_state = MMPLAYER_SEEK_NONE;
6323 player->is_subtitle_force_drop = FALSE;
6324 player->play_subtitle = FALSE;
6325 player->adjust_subtitle_pos = 0;
6327 player->total_bitrate = 0;
6328 player->total_maximum_bitrate = 0;
6330 __mmplayer_track_initialize(player);
6331 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6333 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6334 player->bitrate[i] = 0;
6335 player->maximum_bitrate[i] = 0;
6338 if (player->v_stream_caps) {
6339 gst_caps_unref(player->v_stream_caps);
6340 player->v_stream_caps = NULL;
6343 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6345 /* clean found parsers */
6346 if (player->parsers) {
6347 GList *parsers = player->parsers;
6348 for (; parsers; parsers = g_list_next(parsers)) {
6349 gchar *name = parsers->data;
6350 MMPLAYER_FREEIF(name);
6352 g_list_free(player->parsers);
6353 player->parsers = NULL;
6356 /* clean found audio decoders */
6357 if (player->audio_decoders) {
6358 GList *a_dec = player->audio_decoders;
6359 for (; a_dec; a_dec = g_list_next(a_dec)) {
6360 gchar *name = a_dec->data;
6361 MMPLAYER_FREEIF(name);
6363 g_list_free(player->audio_decoders);
6364 player->audio_decoders = NULL;
6371 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6373 MMPlayerGstElement *mainbin = NULL;
6374 MMMessageParamType msg_param = {0,};
6375 GstElement *element = NULL;
6376 MMHandleType attrs = 0;
6378 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6382 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6383 LOGE("player is not initialized");
6387 mainbin = player->pipeline->mainbin;
6388 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6390 attrs = MMPLAYER_GET_ATTRS(player);
6392 LOGE("fail to get attributes");
6396 /* Initialize Player values */
6397 __mmplayer_initialize_gapless_play(player);
6399 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6401 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6402 LOGE("failed to parse profile");
6403 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6407 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6408 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6409 LOGE("dash or hls is not supportable");
6410 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6414 element = __mmplayer_gst_create_source(player);
6416 LOGE("no source element was created");
6420 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6421 LOGE("failed to add source element to pipeline");
6422 gst_object_unref(GST_OBJECT(element));
6427 /* take source element */
6428 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6429 mainbin[MMPLAYER_M_SRC].gst = element;
6433 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6434 if (player->streamer == NULL) {
6435 player->streamer = __mm_player_streaming_create();
6436 __mm_player_streaming_initialize(player->streamer, TRUE);
6439 elem_idx = MMPLAYER_M_TYPEFIND;
6440 element = gst_element_factory_make("typefind", "typefinder");
6441 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6442 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6444 elem_idx = MMPLAYER_M_AUTOPLUG;
6445 element = __mmplayer_gst_make_decodebin(player);
6448 /* check autoplug element is OK */
6450 LOGE("can not create element(%d)", elem_idx);
6454 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6455 LOGE("failed to add sinkbin to pipeline");
6456 gst_object_unref(GST_OBJECT(element));
6461 mainbin[elem_idx].id = elem_idx;
6462 mainbin[elem_idx].gst = element;
6464 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6465 LOGE("Failed to link src - autoplug(or typefind)");
6469 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6470 LOGE("Failed to change state of src element");
6474 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6475 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6476 LOGE("Failed to change state of decodebin");
6480 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6481 LOGE("Failed to change state of src element");
6486 player->gapless.stream_changed = TRUE;
6487 player->gapless.running = TRUE;
6493 MMPLAYER_PLAYBACK_UNLOCK(player);
6495 if (!player->msg_posted) {
6496 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6497 player->msg_posted = TRUE;
6504 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6506 mm_player_selector_t *selector = &player->selector[type];
6507 MMPlayerGstElement *sinkbin = NULL;
6508 enum MainElementID selectorId = MMPLAYER_M_NUM;
6509 enum MainElementID sinkId = MMPLAYER_M_NUM;
6510 GstPad *srcpad = NULL;
6511 GstPad *sinkpad = NULL;
6512 gboolean send_notice = FALSE;
6515 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6517 LOGD("type %d", type);
6520 case MM_PLAYER_TRACK_TYPE_AUDIO:
6521 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6522 sinkId = MMPLAYER_A_BIN;
6523 sinkbin = player->pipeline->audiobin;
6525 case MM_PLAYER_TRACK_TYPE_VIDEO:
6526 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6527 sinkId = MMPLAYER_V_BIN;
6528 sinkbin = player->pipeline->videobin;
6531 case MM_PLAYER_TRACK_TYPE_TEXT:
6532 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6533 sinkId = MMPLAYER_T_BIN;
6534 sinkbin = player->pipeline->textbin;
6537 LOGE("requested type is not supportable");
6542 if (player->pipeline->mainbin[selectorId].gst) {
6545 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6547 if (selector->event_probe_id != 0)
6548 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6549 selector->event_probe_id = 0;
6551 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6552 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6554 if (srcpad && sinkpad) {
6555 /* after getting drained signal there is no data flows, so no need to do pad_block */
6556 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6557 gst_pad_unlink(srcpad, sinkpad);
6559 /* send custom event to sink pad to handle it at video sink */
6561 LOGD("send custom event to sinkpad");
6562 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6563 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6564 gst_pad_send_event(sinkpad, event);
6568 gst_object_unref(sinkpad);
6571 gst_object_unref(srcpad);
6574 LOGD("selector release");
6576 /* release and unref requests pad from the selector */
6577 for (n = 0; n < selector->channels->len; n++) {
6578 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6579 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6581 g_ptr_array_set_size(selector->channels, 0);
6583 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6584 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6586 player->pipeline->mainbin[selectorId].gst = NULL;
6594 __mmplayer_deactivate_old_path(mm_player_t *player)
6597 MMPLAYER_RETURN_IF_FAIL(player);
6599 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6600 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6601 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6602 LOGE("deactivate selector error");
6606 __mmplayer_track_destroy(player);
6607 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6609 if (player->streamer) {
6610 __mm_player_streaming_initialize(player->streamer, FALSE);
6611 __mm_player_streaming_destroy(player->streamer);
6612 player->streamer = NULL;
6615 MMPLAYER_PLAYBACK_LOCK(player);
6616 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6623 if (!player->msg_posted) {
6624 MMMessageParamType msg = {0,};
6627 msg.code = MM_ERROR_PLAYER_INTERNAL;
6628 LOGE("gapless_uri_play> deactivate error");
6630 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6631 player->msg_posted = TRUE;
6637 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6639 int result = MM_ERROR_NONE;
6640 mm_player_t *player = (mm_player_t *)hplayer;
6643 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6645 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6646 if (mm_attrs_commit_all(player->attrs)) {
6647 LOGE("failed to commit the original uri.");
6648 result = MM_ERROR_PLAYER_INTERNAL;
6650 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6651 LOGE("failed to add the original uri in the uri list.");
6659 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6661 mm_player_t *player = (mm_player_t *)hplayer;
6662 guint num_of_list = 0;
6666 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6667 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6669 if (player->pipeline && player->pipeline->textbin) {
6670 LOGE("subtitle path is enabled.");
6671 return MM_ERROR_PLAYER_INVALID_STATE;
6674 num_of_list = g_list_length(player->uri_info.uri_list);
6676 if (is_first_path) {
6677 if (num_of_list == 0) {
6678 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6679 LOGD("add original path : %s", uri);
6681 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6682 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6684 LOGD("change original path : %s", uri);
6687 MMHandleType attrs = 0;
6688 attrs = MMPLAYER_GET_ATTRS(player);
6690 if (num_of_list == 0) {
6691 char *original_uri = NULL;
6694 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6696 if (!original_uri) {
6697 LOGE("there is no original uri.");
6698 return MM_ERROR_PLAYER_INVALID_STATE;
6701 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6702 player->uri_info.uri_idx = 0;
6704 LOGD("add original path at first : %s", original_uri);
6708 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6709 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6713 return MM_ERROR_NONE;
6717 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6719 mm_player_t *player = (mm_player_t *)hplayer;
6720 char *next_uri = NULL;
6721 guint num_of_list = 0;
6724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6726 num_of_list = g_list_length(player->uri_info.uri_list);
6728 if (num_of_list > 0) {
6729 gint uri_idx = player->uri_info.uri_idx;
6731 if (uri_idx < num_of_list-1)
6736 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6737 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6739 *uri = g_strdup(next_uri);
6743 return MM_ERROR_NONE;
6747 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6748 GstCaps *caps, gpointer data)
6750 mm_player_t *player = (mm_player_t *)data;
6751 const gchar *klass = NULL;
6752 const gchar *mime = NULL;
6753 gchar *caps_str = NULL;
6755 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6756 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6757 caps_str = gst_caps_to_string(caps);
6759 LOGW("unknown type of caps : %s from %s",
6760 caps_str, GST_ELEMENT_NAME(elem));
6762 MMPLAYER_FREEIF(caps_str);
6764 /* There is no available codec. */
6765 __mmplayer_check_not_supported_codec(player, klass, mime);
6769 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6770 GstCaps *caps, gpointer data)
6772 mm_player_t *player = (mm_player_t *)data;
6773 const char *mime = NULL;
6774 gboolean ret = TRUE;
6776 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6777 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6779 if (g_str_has_prefix(mime, "audio")) {
6780 GstStructure *caps_structure = NULL;
6781 gint samplerate = 0;
6783 gchar *caps_str = NULL;
6785 caps_structure = gst_caps_get_structure(caps, 0);
6786 gst_structure_get_int(caps_structure, "rate", &samplerate);
6787 gst_structure_get_int(caps_structure, "channels", &channels);
6789 if ((channels > 0 && samplerate == 0)) {
6790 LOGD("exclude audio...");
6794 caps_str = gst_caps_to_string(caps);
6795 /* set it directly because not sent by TAG */
6796 if (g_strrstr(caps_str, "mobile-xmf"))
6797 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6798 MMPLAYER_FREEIF(caps_str);
6799 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6800 MMMessageParamType msg_param;
6801 memset(&msg_param, 0, sizeof(MMMessageParamType));
6802 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6803 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6804 LOGD("video file is not supported on this device");
6806 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6807 LOGD("already video linked");
6810 LOGD("found new stream");
6817 __mmplayer_check_offload_path(mm_player_t *player)
6819 gboolean ret = FALSE;
6820 GstElementFactory *factory = NULL;
6823 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6825 if (strcmp(player->ini.audio_offload_sink_element, "")) {
6826 /* FIXME : 1. need to consider the current audio output path and
6827 player have to know whether it support offload or not.
6828 2. could be added new condition about content length */
6829 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6830 if (!__mmplayer_is_only_mp3_type(player->type))
6833 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6837 LOGD("can setup the audio offload path");
6838 gst_object_unref(factory);
6847 static GstAutoplugSelectResult
6848 __mmplayer_check_codec_info(mm_player_t *player, const char *klass, GstCaps *caps, char *factory_name)
6850 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6852 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6853 int audio_offload = 0;
6855 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6856 mm_attrs_get_int_by_name(player->attrs, "audio_offload", &audio_offload); /* user setting */
6858 if (audio_offload && __mmplayer_check_offload_path(player)) {
6859 LOGD("expose audio path to build offload path");
6860 player->build_audio_offload = TRUE;
6861 /* update codec info */
6862 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6863 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6864 player->audiodec_linked = 1;
6866 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6870 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6872 LOGD("audio codec type: %d", codec_type);
6873 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6874 /* sw codec will be skipped */
6875 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6876 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6877 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6878 ret = GST_AUTOPLUG_SELECT_SKIP;
6882 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6883 /* hw codec will be skipped */
6884 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6885 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6886 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6887 ret = GST_AUTOPLUG_SELECT_SKIP;
6892 /* set stream information */
6893 if (!player->audiodec_linked)
6894 __mmplayer_set_audio_attrs(player, caps);
6896 /* update codec info */
6897 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6898 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6899 player->audiodec_linked = 1;
6901 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6903 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6905 LOGD("video codec type: %d", codec_type);
6906 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6907 /* sw codec is skipped */
6908 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6909 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6910 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6911 ret = GST_AUTOPLUG_SELECT_SKIP;
6915 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6916 /* hw codec is skipped */
6917 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6918 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6919 ret = GST_AUTOPLUG_SELECT_SKIP;
6924 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6925 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6927 /* mark video decoder for acquire */
6928 if (player->video_decoder_resource == NULL) {
6929 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6930 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6931 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6932 &player->video_decoder_resource)
6933 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6934 LOGE("could not mark video_decoder resource for acquire");
6935 ret = GST_AUTOPLUG_SELECT_SKIP;
6939 LOGW("video decoder resource is already acquired, skip it.");
6940 ret = GST_AUTOPLUG_SELECT_SKIP;
6944 player->interrupted_by_resource = FALSE;
6945 /* acquire resources for video playing */
6946 if (mm_resource_manager_commit(player->resource_manager)
6947 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6948 LOGE("could not acquire resources for video decoding");
6949 ret = GST_AUTOPLUG_SELECT_SKIP;
6954 /* update codec info */
6955 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
6956 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
6957 player->videodec_linked = 1;
6965 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
6966 GstCaps *caps, GstElementFactory *factory, gpointer data)
6968 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
6969 mm_player_t *player = (mm_player_t *)data;
6971 gchar *factory_name = NULL;
6972 gchar *caps_str = NULL;
6973 const gchar *klass = NULL;
6976 factory_name = GST_OBJECT_NAME(factory);
6977 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
6978 caps_str = gst_caps_to_string(caps);
6980 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
6982 /* store type string */
6983 if (player->type == NULL) {
6984 player->type = gst_caps_to_string(caps);
6985 __mmplayer_update_content_type_info(player);
6988 /* filtering exclude keyword */
6989 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
6990 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
6991 LOGW("skipping [%s] by exculde keyword [%s]",
6992 factory_name, player->ini.exclude_element_keyword[idx]);
6994 result = GST_AUTOPLUG_SELECT_SKIP;
6999 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7000 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7001 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7002 factory_name, player->ini.unsupported_codec_keyword[idx]);
7003 result = GST_AUTOPLUG_SELECT_SKIP;
7008 /* exclude webm format */
7009 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7010 * because webm format is not supportable.
7011 * If webm is disabled in "autoplug-continue", there is no state change
7012 * failure or error because the decodebin will expose the pad directly.
7013 * It make MSL invoke _prepare_async_callback.
7014 * So, we need to disable webm format in "autoplug-select" */
7015 if (caps_str && strstr(caps_str, "webm")) {
7016 LOGW("webm is not supported");
7017 result = GST_AUTOPLUG_SELECT_SKIP;
7021 /* check factory class for filtering */
7022 /* NOTE : msl don't need to use image plugins.
7023 * So, those plugins should be skipped for error handling.
7025 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7026 LOGD("skipping [%s] by not required", factory_name);
7027 result = GST_AUTOPLUG_SELECT_SKIP;
7031 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7032 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7033 // TO CHECK : subtitle if needed, add subparse exception.
7034 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7035 result = GST_AUTOPLUG_SELECT_SKIP;
7039 if (g_strrstr(factory_name, "mpegpsdemux")) {
7040 LOGD("skipping PS container - not support");
7041 result = GST_AUTOPLUG_SELECT_SKIP;
7045 if (g_strrstr(factory_name, "mssdemux"))
7046 player->smooth_streaming = TRUE;
7048 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7049 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7052 GstStructure *str = NULL;
7053 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7055 /* don't make video because of not required */
7056 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7057 (!player->set_mode.media_packet_video_stream)) {
7058 LOGD("no need video decoding, expose pad");
7059 result = GST_AUTOPLUG_SELECT_EXPOSE;
7063 /* get w/h for omx state-tune */
7064 /* FIXME: deprecated? */
7065 str = gst_caps_get_structure(caps, 0);
7066 gst_structure_get_int(str, "width", &width);
7069 if (player->v_stream_caps) {
7070 gst_caps_unref(player->v_stream_caps);
7071 player->v_stream_caps = NULL;
7074 player->v_stream_caps = gst_caps_copy(caps);
7075 LOGD("take caps for video state tune");
7076 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7080 if (g_strrstr(klass, "Codec/Decoder")) {
7081 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7082 if (result != GST_AUTOPLUG_SELECT_TRY) {
7083 LOGW("skip add decoder");
7089 MMPLAYER_FREEIF(caps_str);
7095 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7098 //mm_player_t *player = (mm_player_t *)data;
7099 GstCaps *caps = NULL;
7101 LOGD("[Decodebin2] pad-removed signal");
7103 caps = gst_pad_query_caps(new_pad, NULL);
7105 LOGW("query caps is NULL");
7109 gchar *caps_str = NULL;
7110 caps_str = gst_caps_to_string(caps);
7112 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7114 MMPLAYER_FREEIF(caps_str);
7115 gst_caps_unref(caps);
7119 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7121 mm_player_t *player = (mm_player_t *)data;
7122 GstIterator *iter = NULL;
7123 GValue item = { 0, };
7125 gboolean done = FALSE;
7126 gboolean is_all_drained = TRUE;
7129 MMPLAYER_RETURN_IF_FAIL(player);
7131 LOGD("__mmplayer_gst_decode_drained");
7133 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7134 LOGW("Fail to get cmd lock");
7138 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7139 !__mmplayer_verify_gapless_play_path(player)) {
7140 LOGD("decoding is finished.");
7141 __mmplayer_reset_gapless_state(player);
7142 MMPLAYER_CMD_UNLOCK(player);
7146 player->gapless.reconfigure = TRUE;
7148 /* check decodebin src pads whether they received EOS or not */
7149 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7152 switch (gst_iterator_next(iter, &item)) {
7153 case GST_ITERATOR_OK:
7154 pad = g_value_get_object(&item);
7155 if (pad && !GST_PAD_IS_EOS(pad)) {
7156 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7157 is_all_drained = FALSE;
7160 g_value_reset(&item);
7162 case GST_ITERATOR_RESYNC:
7163 gst_iterator_resync(iter);
7165 case GST_ITERATOR_ERROR:
7166 case GST_ITERATOR_DONE:
7171 g_value_unset(&item);
7172 gst_iterator_free(iter);
7174 if (!is_all_drained) {
7175 LOGD("Wait util the all pads get EOS.");
7176 MMPLAYER_CMD_UNLOCK(player);
7181 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7182 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7184 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7185 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7186 __mmplayer_deactivate_old_path(player);
7187 MMPLAYER_CMD_UNLOCK(player);
7193 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7195 mm_player_t *player = (mm_player_t *)data;
7196 const gchar *klass = NULL;
7197 gchar *factory_name = NULL;
7199 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7200 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7202 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7204 if (__mmplayer_add_dump_buffer_probe(player, element))
7205 LOGD("add buffer probe");
7208 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7209 gchar *selected = NULL;
7210 selected = g_strdup(GST_ELEMENT_NAME(element));
7211 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7215 if (g_strrstr(klass, "Parser")) {
7216 gchar *selected = NULL;
7218 selected = g_strdup(factory_name);
7219 player->parsers = g_list_append(player->parsers, selected);
7222 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7223 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7224 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7226 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7227 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7229 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7230 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7231 "max-video-width", player->adaptive_info.limit.width,
7232 "max-video-height", player->adaptive_info.limit.height, NULL);
7234 } else if (g_strrstr(klass, "Demuxer")) {
7235 //LOGD("plugged element is demuxer. take it");
7236 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7237 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7240 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7241 int surface_type = 0;
7243 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7246 // to support trust-zone only
7247 if (g_strrstr(factory_name, "asfdemux")) {
7248 LOGD("set file-location %s", player->profile.uri);
7249 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7250 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7251 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7252 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7253 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7254 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7255 (__mmplayer_is_only_mp3_type(player->type))) {
7256 LOGD("[mpegaudioparse] set streaming pull mode.");
7257 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7259 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7260 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7263 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7264 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7265 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7267 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7268 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7270 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7271 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7272 (MMPLAYER_IS_DASH_STREAMING(player))) {
7273 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7274 __mm_player_streaming_set_multiqueue(player->streamer, element);
7275 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7284 __mmplayer_release_misc(mm_player_t *player)
7287 bool cur_mode = player->set_mode.rich_audio;
7290 MMPLAYER_RETURN_IF_FAIL(player);
7292 player->video_stream_cb = NULL;
7293 player->video_stream_cb_user_param = NULL;
7294 player->video_stream_prerolled = false;
7296 player->audio_stream_render_cb = NULL;
7297 player->audio_stream_cb_user_param = NULL;
7298 player->audio_stream_sink_sync = false;
7300 player->video_stream_changed_cb = NULL;
7301 player->video_stream_changed_cb_user_param = NULL;
7303 player->audio_stream_changed_cb = NULL;
7304 player->audio_stream_changed_cb_user_param = NULL;
7306 player->sent_bos = FALSE;
7307 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7309 player->seek_state = MMPLAYER_SEEK_NONE;
7311 player->total_bitrate = 0;
7312 player->total_maximum_bitrate = 0;
7314 player->not_found_demuxer = 0;
7316 player->last_position = 0;
7317 player->duration = 0;
7318 player->http_content_size = 0;
7319 player->not_supported_codec = MISSING_PLUGIN_NONE;
7320 player->can_support_codec = FOUND_PLUGIN_NONE;
7321 player->pending_seek.is_pending = false;
7322 player->pending_seek.pos = 0;
7323 player->msg_posted = FALSE;
7324 player->has_many_types = FALSE;
7325 player->is_subtitle_force_drop = FALSE;
7326 player->play_subtitle = FALSE;
7327 player->adjust_subtitle_pos = 0;
7328 player->last_multiwin_status = FALSE;
7329 player->has_closed_caption = FALSE;
7330 player->set_mode.media_packet_video_stream = false;
7331 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7332 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7334 player->set_mode.rich_audio = cur_mode;
7336 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7337 player->bitrate[i] = 0;
7338 player->maximum_bitrate[i] = 0;
7341 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7343 /* remove media stream cb(appsrc cb) */
7344 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7345 player->media_stream_buffer_status_cb[i] = NULL;
7346 player->media_stream_seek_data_cb[i] = NULL;
7347 player->buffer_cb_user_param[i] = NULL;
7348 player->seek_cb_user_param[i] = NULL;
7350 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7352 /* free memory related to audio effect */
7353 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7355 if (player->adaptive_info.var_list) {
7356 g_list_free_full(player->adaptive_info.var_list, g_free);
7357 player->adaptive_info.var_list = NULL;
7360 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7361 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7362 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7364 /* Reset video360 settings to their defaults in case if the pipeline is to be
7367 player->video360_metadata.is_spherical = -1;
7368 player->is_openal_plugin_used = FALSE;
7370 player->is_content_spherical = FALSE;
7371 player->is_video360_enabled = TRUE;
7372 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7373 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7374 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7375 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7376 player->video360_zoom = 1.0f;
7377 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7378 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7380 player->sound.rg_enable = false;
7382 __mmplayer_initialize_video_roi(player);
7387 __mmplayer_release_misc_post(mm_player_t *player)
7389 char *original_uri = NULL;
7392 /* player->pipeline is already released before. */
7394 MMPLAYER_RETURN_IF_FAIL(player);
7396 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7398 /* clean found parsers */
7399 if (player->parsers) {
7400 GList *parsers = player->parsers;
7401 for (; parsers; parsers = g_list_next(parsers)) {
7402 gchar *name = parsers->data;
7403 MMPLAYER_FREEIF(name);
7405 g_list_free(player->parsers);
7406 player->parsers = NULL;
7409 /* clean found audio decoders */
7410 if (player->audio_decoders) {
7411 GList *a_dec = player->audio_decoders;
7412 for (; a_dec; a_dec = g_list_next(a_dec)) {
7413 gchar *name = a_dec->data;
7414 MMPLAYER_FREEIF(name);
7416 g_list_free(player->audio_decoders);
7417 player->audio_decoders = NULL;
7420 /* clean the uri list except original uri */
7421 if (player->uri_info.uri_list) {
7422 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7424 if (player->attrs) {
7425 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7426 LOGD("restore original uri = %s", original_uri);
7428 if (mm_attrs_commit_all(player->attrs))
7429 LOGE("failed to commit the original uri.");
7432 GList *uri_list = player->uri_info.uri_list;
7433 for (; uri_list; uri_list = g_list_next(uri_list)) {
7434 gchar *uri = uri_list->data;
7435 MMPLAYER_FREEIF(uri);
7437 g_list_free(player->uri_info.uri_list);
7438 player->uri_info.uri_list = NULL;
7441 /* clear the audio stream buffer list */
7442 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7444 /* clear the video stream bo list */
7445 __mmplayer_video_stream_destroy_bo_list(player);
7446 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7448 if (player->profile.input_mem.buf) {
7449 free(player->profile.input_mem.buf);
7450 player->profile.input_mem.buf = NULL;
7452 player->profile.input_mem.len = 0;
7453 player->profile.input_mem.offset = 0;
7455 player->uri_info.uri_idx = 0;
7460 __mmplayer_check_subtitle(mm_player_t *player)
7462 MMHandleType attrs = 0;
7463 char *subtitle_uri = NULL;
7467 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7469 /* get subtitle attribute */
7470 attrs = MMPLAYER_GET_ATTRS(player);
7474 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7475 if (!subtitle_uri || !strlen(subtitle_uri))
7478 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7479 player->is_external_subtitle_present = TRUE;
7487 __mmplayer_cancel_eos_timer(mm_player_t *player)
7489 MMPLAYER_RETURN_IF_FAIL(player);
7491 if (player->eos_timer) {
7492 LOGD("cancel eos timer");
7493 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7494 player->eos_timer = 0;
7501 __mmplayer_add_sink(mm_player_t *player, GstElement *sink)
7505 MMPLAYER_RETURN_IF_FAIL(player);
7506 MMPLAYER_RETURN_IF_FAIL(sink);
7508 player->sink_elements = g_list_append(player->sink_elements, sink);
7514 __mmplayer_del_sink(mm_player_t *player, GstElement *sink)
7518 MMPLAYER_RETURN_IF_FAIL(player);
7519 MMPLAYER_RETURN_IF_FAIL(sink);
7521 player->sink_elements = g_list_remove(player->sink_elements, sink);
7527 __mmplayer_add_signal_connection(mm_player_t *player, GObject *object,
7528 MMPlayerSignalType type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7530 MMPlayerSignalItem *item = NULL;
7533 MMPLAYER_RETURN_IF_FAIL(player);
7535 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7536 LOGE("invalid signal type [%d]", type);
7540 item = (MMPlayerSignalItem *)g_try_malloc(sizeof(MMPlayerSignalItem));
7542 LOGE("cannot connect signal [%s]", signal);
7547 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7548 player->signals[type] = g_list_append(player->signals[type], item);
7554 /* NOTE : be careful with calling this api. please refer to below glib comment
7555 * glib comment : Note that there is a bug in GObject that makes this function much
7556 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7557 * will no longer be called, but, the signal handler is not currently disconnected.
7558 * If the instance is itself being freed at the same time than this doesn't matter,
7559 * since the signal will automatically be removed, but if instance persists,
7560 * then the signal handler will leak. You should not remove the signal yourself
7561 * because in a future versions of GObject, the handler will automatically be
7564 * It's possible to work around this problem in a way that will continue to work
7565 * with future versions of GObject by checking that the signal handler is still
7566 * connected before disconnected it:
7568 * if (g_signal_handler_is_connected(instance, id))
7569 * g_signal_handler_disconnect(instance, id);
7572 __mmplayer_release_signal_connection(mm_player_t *player, MMPlayerSignalType type)
7574 GList *sig_list = NULL;
7575 MMPlayerSignalItem *item = NULL;
7579 MMPLAYER_RETURN_IF_FAIL(player);
7581 LOGD("release signals type : %d", type);
7583 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7584 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7585 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7586 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7587 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7588 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7592 sig_list = player->signals[type];
7594 for (; sig_list; sig_list = sig_list->next) {
7595 item = sig_list->data;
7597 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7598 if (g_signal_handler_is_connected(item->obj, item->sig))
7599 g_signal_handler_disconnect(item->obj, item->sig);
7602 MMPLAYER_FREEIF(item);
7605 g_list_free(player->signals[type]);
7606 player->signals[type] = NULL;
7614 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7616 mm_player_t *player = 0;
7617 int prev_display_surface_type = 0;
7618 void *prev_display_overlay = NULL;
7622 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7623 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7625 player = MM_PLAYER_CAST(handle);
7627 /* check video sinkbin is created */
7628 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7629 LOGE("Videosink is already created");
7630 return MM_ERROR_NONE;
7633 LOGD("videosink element is not yet ready");
7635 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7636 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7638 return MM_ERROR_INVALID_ARGUMENT;
7641 /* load previous attributes */
7642 if (player->attrs) {
7643 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7644 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7645 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7646 if (prev_display_surface_type == surface_type) {
7647 LOGD("incoming display surface type is same as previous one, do nothing..");
7649 return MM_ERROR_NONE;
7652 LOGE("failed to load attributes");
7654 return MM_ERROR_PLAYER_INTERNAL;
7657 /* videobin is not created yet, so we just set attributes related to display surface */
7658 LOGD("store display attribute for given surface type(%d)", surface_type);
7659 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7660 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7661 if (mm_attrs_commit_all(player->attrs)) {
7662 LOGE("failed to commit attribute");
7664 return MM_ERROR_PLAYER_INTERNAL;
7668 return MM_ERROR_NONE;
7671 /* Note : if silent is true, then subtitle would not be displayed. :*/
7673 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7675 mm_player_t *player = (mm_player_t *)hplayer;
7679 /* check player handle */
7680 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7682 player->set_mode.subtitle_off = silent;
7684 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7688 return MM_ERROR_NONE;
7692 _mmplayer_sync_subtitle_pipeline(mm_player_t *player)
7694 MMPlayerGstElement *mainbin = NULL;
7695 MMPlayerGstElement *textbin = NULL;
7696 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7697 GstState current_state = GST_STATE_VOID_PENDING;
7698 GstState element_state = GST_STATE_VOID_PENDING;
7699 GstState element_pending_state = GST_STATE_VOID_PENDING;
7701 GstEvent *event = NULL;
7702 int result = MM_ERROR_NONE;
7704 GstClock *curr_clock = NULL;
7705 GstClockTime base_time, start_time, curr_time;
7710 /* check player handle */
7711 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7713 player->pipeline->mainbin &&
7714 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7716 mainbin = player->pipeline->mainbin;
7717 textbin = player->pipeline->textbin;
7719 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7721 // sync clock with current pipeline
7722 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7723 curr_time = gst_clock_get_time(curr_clock);
7725 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7726 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7728 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7729 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7731 if (current_state > GST_STATE_READY) {
7732 // sync state with current pipeline
7733 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7734 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7735 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7737 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7738 if (GST_STATE_CHANGE_FAILURE == ret) {
7739 LOGE("fail to state change.");
7740 result = MM_ERROR_PLAYER_INTERNAL;
7744 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7745 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7748 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7749 gst_object_unref(curr_clock);
7752 // seek to current position
7753 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7754 result = MM_ERROR_PLAYER_INVALID_STATE;
7755 LOGE("gst_element_query_position failed, invalid state");
7759 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7760 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);
7762 __mmplayer_gst_send_event_to_sink(player, event);
7764 result = MM_ERROR_PLAYER_INTERNAL;
7765 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7769 /* sync state with current pipeline */
7770 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7771 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7772 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7774 return MM_ERROR_NONE;
7777 /* release text pipeline resource */
7778 player->textsink_linked = 0;
7780 /* release signal */
7781 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7783 /* release textbin with it's childs */
7784 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7785 MMPLAYER_FREEIF(player->pipeline->textbin);
7786 player->pipeline->textbin = NULL;
7788 /* release subtitle elem */
7789 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7790 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7796 __mmplayer_change_external_subtitle_language(mm_player_t *player, const char *filepath)
7798 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7799 GstState current_state = GST_STATE_VOID_PENDING;
7801 MMHandleType attrs = 0;
7802 MMPlayerGstElement *mainbin = NULL;
7803 MMPlayerGstElement *textbin = NULL;
7805 gchar *subtitle_uri = NULL;
7806 int result = MM_ERROR_NONE;
7807 const gchar *charset = NULL;
7811 /* check player handle */
7812 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7814 player->pipeline->mainbin &&
7815 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7816 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7818 mainbin = player->pipeline->mainbin;
7819 textbin = player->pipeline->textbin;
7821 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7822 if (current_state < GST_STATE_READY) {
7823 result = MM_ERROR_PLAYER_INVALID_STATE;
7824 LOGE("Pipeline is not in proper state");
7828 attrs = MMPLAYER_GET_ATTRS(player);
7830 LOGE("cannot get content attribute");
7831 result = MM_ERROR_PLAYER_INTERNAL;
7835 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7836 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7837 LOGE("subtitle uri is not proper filepath");
7838 result = MM_ERROR_PLAYER_INVALID_URI;
7842 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7843 LOGE("failed to get storage info of subtitle path");
7844 result = MM_ERROR_PLAYER_INVALID_URI;
7848 LOGD("old subtitle file path is [%s]", subtitle_uri);
7849 LOGD("new subtitle file path is [%s]", filepath);
7851 if (!strcmp(filepath, subtitle_uri)) {
7852 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7855 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7856 if (mm_attrs_commit_all(player->attrs)) {
7857 LOGE("failed to commit.");
7862 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7863 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7864 player->subtitle_language_list = NULL;
7865 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7867 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7868 if (ret != GST_STATE_CHANGE_SUCCESS) {
7869 LOGE("failed to change state of textbin to READY");
7870 result = MM_ERROR_PLAYER_INTERNAL;
7874 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7875 if (ret != GST_STATE_CHANGE_SUCCESS) {
7876 LOGE("failed to change state of subparse to READY");
7877 result = MM_ERROR_PLAYER_INTERNAL;
7881 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7882 if (ret != GST_STATE_CHANGE_SUCCESS) {
7883 LOGE("failed to change state of filesrc to READY");
7884 result = MM_ERROR_PLAYER_INTERNAL;
7888 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7890 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7892 charset = util_get_charset(filepath);
7894 LOGD("detected charset is %s", charset);
7895 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7898 result = _mmplayer_sync_subtitle_pipeline(player);
7905 /* API to switch between external subtitles */
7907 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7909 int result = MM_ERROR_NONE;
7910 mm_player_t *player = (mm_player_t *)hplayer;
7915 /* check player handle */
7916 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7918 /* filepath can be null in idle state */
7920 /* check file path */
7921 if ((path = strstr(filepath, "file://")))
7922 result = util_exist_file_path(path + 7);
7924 result = util_exist_file_path(filepath);
7926 if (result != MM_ERROR_NONE) {
7927 LOGE("invalid subtitle path 0x%X", result);
7928 return result; /* file not found or permission denied */
7932 if (!player->pipeline) {
7934 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7935 if (mm_attrs_commit_all(player->attrs)) {
7936 LOGE("failed to commit"); /* subtitle path will not be created */
7937 return MM_ERROR_PLAYER_INTERNAL;
7940 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7941 /* check filepath */
7942 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7944 if (!__mmplayer_check_subtitle(player)) {
7945 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7946 if (mm_attrs_commit_all(player->attrs)) {
7947 LOGE("failed to commit");
7948 return MM_ERROR_PLAYER_INTERNAL;
7951 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
7952 LOGE("fail to create text pipeline");
7953 return MM_ERROR_PLAYER_INTERNAL;
7956 result = _mmplayer_sync_subtitle_pipeline(player);
7958 result = __mmplayer_change_external_subtitle_language(player, filepath);
7961 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7962 player->is_external_subtitle_added_now = TRUE;
7964 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7965 if (!player->subtitle_language_list) {
7966 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
7967 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
7968 LOGW("subtitle language list is not updated yet");
7970 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7978 __mmplayer_change_selector_pad(mm_player_t *player, MMPlayerTrackType type, int index)
7980 int result = MM_ERROR_NONE;
7981 gchar *change_pad_name = NULL;
7982 GstPad *sinkpad = NULL;
7983 MMPlayerGstElement *mainbin = NULL;
7984 enum MainElementID elem_idx = MMPLAYER_M_NUM;
7985 GstCaps *caps = NULL;
7986 gint total_track_num = 0;
7990 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
7991 MM_ERROR_PLAYER_NOT_INITIALIZED);
7993 LOGD("Change Track(%d) to %d", type, index);
7995 mainbin = player->pipeline->mainbin;
7997 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
7998 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
7999 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8000 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8002 /* Changing Video Track is not supported. */
8003 LOGE("Track Type Error");
8007 if (mainbin[elem_idx].gst == NULL) {
8008 result = MM_ERROR_PLAYER_NO_OP;
8009 LOGD("Req track doesn't exist");
8013 total_track_num = player->selector[type].total_track_num;
8014 if (total_track_num <= 0) {
8015 result = MM_ERROR_PLAYER_NO_OP;
8016 LOGD("Language list is not available");
8020 if ((index < 0) || (index >= total_track_num)) {
8021 result = MM_ERROR_INVALID_ARGUMENT;
8022 LOGD("Not a proper index : %d", index);
8026 /*To get the new pad from the selector*/
8027 change_pad_name = g_strdup_printf("sink_%u", index);
8028 if (change_pad_name == NULL) {
8029 result = MM_ERROR_PLAYER_INTERNAL;
8030 LOGD("Pad does not exists");
8034 LOGD("new active pad name: %s", change_pad_name);
8036 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8037 if (sinkpad == NULL) {
8038 LOGD("sinkpad is NULL");
8039 result = MM_ERROR_PLAYER_INTERNAL;
8043 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8044 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8046 caps = gst_pad_get_current_caps(sinkpad);
8047 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8050 gst_object_unref(sinkpad);
8052 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8053 __mmplayer_set_audio_attrs(player, caps);
8056 MMPLAYER_FREEIF(change_pad_name);
8061 _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8063 int result = MM_ERROR_NONE;
8064 mm_player_t *player = NULL;
8065 MMPlayerGstElement *mainbin = NULL;
8067 gint current_active_index = 0;
8069 GstState current_state = GST_STATE_VOID_PENDING;
8070 GstEvent *event = NULL;
8075 player = (mm_player_t *)hplayer;
8076 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8078 if (!player->pipeline) {
8079 LOGE("Track %d pre setting -> %d", type, index);
8081 player->selector[type].active_pad_index = index;
8085 mainbin = player->pipeline->mainbin;
8087 current_active_index = player->selector[type].active_pad_index;
8089 /*If index is same as running index no need to change the pad*/
8090 if (current_active_index == index)
8093 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8094 result = MM_ERROR_PLAYER_INVALID_STATE;
8098 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8099 if (current_state < GST_STATE_PAUSED) {
8100 result = MM_ERROR_PLAYER_INVALID_STATE;
8101 LOGW("Pipeline not in porper state");
8105 result = __mmplayer_change_selector_pad(player, type, index);
8106 if (result != MM_ERROR_NONE) {
8107 LOGE("change selector pad error");
8111 player->selector[type].active_pad_index = index;
8113 if (current_state == GST_STATE_PLAYING) {
8114 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8115 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8116 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8118 __mmplayer_gst_send_event_to_sink(player, event);
8120 result = MM_ERROR_PLAYER_INTERNAL;
8130 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8132 mm_player_t *player = (mm_player_t *)hplayer;
8136 /* check player handle */
8137 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8139 *silent = player->set_mode.subtitle_off;
8141 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8145 return MM_ERROR_NONE;
8149 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8151 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8152 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8154 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8155 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8159 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8160 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8161 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8162 mm_player_dump_t *dump_s;
8163 dump_s = g_try_malloc(sizeof(mm_player_dump_t));
8164 if (dump_s == NULL) {
8165 LOGE("malloc fail");
8169 dump_s->dump_element_file = NULL;
8170 dump_s->dump_pad = NULL;
8171 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8173 if (dump_s->dump_pad) {
8174 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8175 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]);
8176 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8177 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);
8178 /* add list for removed buffer probe and close FILE */
8179 player->dump_list = g_list_append(player->dump_list, dump_s);
8180 LOGD("%s sink pad added buffer probe for dump", factory_name);
8183 MMPLAYER_FREEIF(dump_s);
8184 LOGE("failed to get %s sink pad added", factory_name);
8191 static GstPadProbeReturn
8192 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8194 FILE *dump_data = (FILE *)u_data;
8196 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8197 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8199 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8201 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8203 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8205 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8207 return GST_PAD_PROBE_OK;
8211 __mmplayer_release_dump_list(GList *dump_list)
8213 GList *d_list = dump_list;
8218 for (; d_list; d_list = g_list_next(d_list)) {
8219 mm_player_dump_t *dump_s = d_list->data;
8220 if (dump_s->dump_pad) {
8221 if (dump_s->probe_handle_id)
8222 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8224 if (dump_s->dump_element_file) {
8225 fclose(dump_s->dump_element_file);
8226 dump_s->dump_element_file = NULL;
8228 MMPLAYER_FREEIF(dump_s);
8230 g_list_free(dump_list);
8235 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8237 mm_player_t *player = (mm_player_t *)hplayer;
8241 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8242 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8244 *exist = (bool)player->has_closed_caption;
8248 return MM_ERROR_NONE;
8252 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8256 // LOGD("unref internal gst buffer %p", buffer);
8257 gst_buffer_unref((GstBuffer *)buffer);
8264 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8266 mm_player_t *player = (mm_player_t *)hplayer;
8270 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8271 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8273 if (MMPLAYER_IS_STREAMING(player))
8274 *timeout = (int)player->ini.live_state_change_timeout;
8276 *timeout = (int)player->ini.localplayback_state_change_timeout;
8278 LOGD("timeout = %d", *timeout);
8281 return MM_ERROR_NONE;
8285 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8287 mm_player_t *player = (mm_player_t *)hplayer;
8291 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8292 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8294 *num = player->video_num_buffers;
8295 *extra_num = player->video_extra_num_buffers;
8297 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8300 return MM_ERROR_NONE;
8304 __mmplayer_initialize_storage_info(mm_player_t *player, MMPlayerPathType path_type)
8308 MMPLAYER_RETURN_IF_FAIL(player);
8310 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8312 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8313 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8314 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8315 player->storage_info[i].id = -1;
8316 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8318 if (path_type != MMPLAYER_PATH_MAX)
8327 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8329 int ret = MM_ERROR_NONE;
8330 mm_player_t *player = (mm_player_t *)hplayer;
8331 MMMessageParamType msg_param = {0, };
8334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8336 LOGW("state changed storage %d:%d", id, state);
8338 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8339 return MM_ERROR_NONE;
8341 /* FIXME: text path should be handled seperately. */
8342 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8343 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8344 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8345 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8346 LOGW("external storage is removed");
8348 if (player->msg_posted == FALSE) {
8349 memset(&msg_param, 0, sizeof(MMMessageParamType));
8350 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8351 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8352 player->msg_posted = TRUE;
8355 /* unrealize the player */
8356 ret = _mmplayer_unrealize(hplayer);
8357 if (ret != MM_ERROR_NONE)
8358 LOGE("failed to unrealize");
8366 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8368 int ret = MM_ERROR_NONE;
8369 mm_player_t *player = (mm_player_t *)hplayer;
8370 int idx = 0, total = 0;
8371 gchar *result = NULL, *tmp = NULL;
8374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8375 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8377 total = *num = g_list_length(player->adaptive_info.var_list);
8379 LOGW("There is no stream variant info.");
8383 result = g_strdup("");
8384 for (idx = 0 ; idx < total ; idx++) {
8385 VariantData *v_data = NULL;
8386 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8389 gchar data[64] = {0};
8390 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8392 tmp = g_strconcat(result, data, NULL);
8396 LOGW("There is no variant data in %d", idx);
8401 *var_info = (char *)result;
8403 LOGD("variant info %d:%s", *num, *var_info);
8409 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8411 int ret = MM_ERROR_NONE;
8412 mm_player_t *player = (mm_player_t *)hplayer;
8415 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8417 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8419 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8420 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8421 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8423 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8424 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8425 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8426 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8428 /* FIXME: seek to current position for applying new variant limitation */
8437 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8439 int ret = MM_ERROR_NONE;
8440 mm_player_t *player = (mm_player_t *)hplayer;
8443 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8444 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8446 *bandwidth = player->adaptive_info.limit.bandwidth;
8447 *width = player->adaptive_info.limit.width;
8448 *height = player->adaptive_info.limit.height;
8450 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8457 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8459 int ret = MM_ERROR_NONE;
8460 mm_player_t *player = (mm_player_t *)hplayer;
8463 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8464 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8465 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8467 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8469 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8470 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8471 else /* live case */
8472 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8474 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8481 _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8483 #define IDX_FIRST_SW_CODEC 0
8484 mm_player_t *player = (mm_player_t *)hplayer;
8485 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8486 MMHandleType attrs = 0;
8489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8491 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8492 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8493 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8495 switch (stream_type) {
8496 case MM_PLAYER_STREAM_TYPE_AUDIO:
8497 /* to support audio codec selection, codec info have to be added in ini file as below.
8498 audio codec element hw = xxxx
8499 audio codec element sw = avdec */
8500 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8501 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8502 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8503 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8504 LOGE("There is no audio codec info for codec_type %d", codec_type);
8505 return MM_ERROR_PLAYER_NO_OP;
8508 case MM_PLAYER_STREAM_TYPE_VIDEO:
8509 /* to support video codec selection, codec info have to be added in ini file as below.
8510 video codec element hw = omx
8511 video codec element sw = avdec */
8512 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8513 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8514 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8515 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8516 LOGE("There is no video codec info for codec_type %d", codec_type);
8517 return MM_ERROR_PLAYER_NO_OP;
8521 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8522 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8526 LOGD("update %s codec_type to %d", attr_name, codec_type);
8528 attrs = MMPLAYER_GET_ATTRS(player);
8529 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8531 if (mm_attrs_commit_all(player->attrs)) {
8532 LOGE("failed to commit codec_type attributes");
8533 return MM_ERROR_PLAYER_INTERNAL;
8537 return MM_ERROR_NONE;
8541 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8543 mm_player_t *player = (mm_player_t *)hplayer;
8544 GstElement *rg_vol_element = NULL;
8548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8550 player->sound.rg_enable = enabled;
8552 /* just hold rgvolume enable value if pipeline is not ready */
8553 if (!player->pipeline || !player->pipeline->audiobin) {
8554 LOGD("pipeline is not ready. holding rgvolume enable value");
8555 return MM_ERROR_NONE;
8558 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8560 if (!rg_vol_element) {
8561 LOGD("rgvolume element is not created");
8562 return MM_ERROR_PLAYER_INTERNAL;
8566 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8568 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8572 return MM_ERROR_NONE;
8576 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8578 mm_player_t *player = (mm_player_t *)hplayer;
8579 GstElement *rg_vol_element = NULL;
8580 gboolean enable = FALSE;
8584 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8585 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8587 /* just hold enable_rg value if pipeline is not ready */
8588 if (!player->pipeline || !player->pipeline->audiobin) {
8589 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8590 *enabled = player->sound.rg_enable;
8591 return MM_ERROR_NONE;
8594 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8596 if (!rg_vol_element) {
8597 LOGD("rgvolume element is not created");
8598 return MM_ERROR_PLAYER_INTERNAL;
8601 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8602 *enabled = (bool)enable;
8606 return MM_ERROR_NONE;
8610 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8612 mm_player_t *player = (mm_player_t *)hplayer;
8613 MMHandleType attrs = 0;
8614 void *handle = NULL;
8615 int ret = MM_ERROR_NONE;
8619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8621 attrs = MMPLAYER_GET_ATTRS(player);
8622 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8624 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8626 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8627 return MM_ERROR_PLAYER_INTERNAL;
8630 player->video_roi.scale_x = scale_x;
8631 player->video_roi.scale_y = scale_y;
8632 player->video_roi.scale_width = scale_width;
8633 player->video_roi.scale_height = scale_height;
8635 /* check video sinkbin is created */
8636 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8637 return MM_ERROR_NONE;
8639 if (!gst_video_overlay_set_video_roi_area(
8640 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8641 scale_x, scale_y, scale_width, scale_height))
8642 ret = MM_ERROR_PLAYER_INTERNAL;
8644 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8645 scale_x, scale_y, scale_width, scale_height);
8653 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8655 mm_player_t *player = (mm_player_t *)hplayer;
8656 int ret = MM_ERROR_NONE;
8660 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8661 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8663 *scale_x = player->video_roi.scale_x;
8664 *scale_y = player->video_roi.scale_y;
8665 *scale_width = player->video_roi.scale_width;
8666 *scale_height = player->video_roi.scale_height;
8668 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8669 *scale_x, *scale_y, *scale_width, *scale_height);
8675 __mmplayer_update_duration_value(mm_player_t *player)
8677 gboolean ret = FALSE;
8678 gint64 dur_nsec = 0;
8679 LOGD("try to update duration");
8681 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8682 player->duration = dur_nsec;
8683 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8687 if (player->duration < 0) {
8688 LOGW("duration is Non-Initialized !!!");
8689 player->duration = 0;
8692 /* update streaming service type */
8693 player->streaming_type = __mmplayer_get_stream_service_type(player);
8695 /* check duration is OK */
8696 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8697 /* FIXIT : find another way to get duration here. */
8698 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8704 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8706 /* update audio params
8707 NOTE : We need original audio params and it can be only obtained from src pad of audio
8708 decoder. Below code only valid when we are not using 'resampler' just before
8709 'audioconverter'. */
8710 GstCaps *caps_a = NULL;
8712 gint samplerate = 0, channels = 0;
8713 GstStructure *p = NULL;
8715 LOGD("try to update audio attrs");
8717 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8718 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8720 pad = gst_element_get_static_pad(
8721 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8724 LOGW("failed to get pad from audiosink");
8728 caps_a = gst_pad_get_current_caps(pad);
8730 LOGW("not ready to get audio caps");
8731 gst_object_unref(pad);
8735 p = gst_caps_get_structure(caps_a, 0);
8737 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8739 gst_structure_get_int(p, "rate", &samplerate);
8740 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8742 gst_structure_get_int(p, "channels", &channels);
8743 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8745 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8747 gst_caps_unref(caps_a);
8748 gst_object_unref(pad);
8754 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8756 LOGD("try to update video attrs");
8758 GstCaps *caps_v = NULL;
8762 GstStructure *p = NULL;
8764 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8765 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8767 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8769 LOGD("no videosink sink pad");
8773 caps_v = gst_pad_get_current_caps(pad);
8774 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8775 if (!caps_v && player->v_stream_caps) {
8776 caps_v = player->v_stream_caps;
8777 gst_caps_ref(caps_v);
8781 LOGD("no negitiated caps from videosink");
8782 gst_object_unref(pad);
8786 p = gst_caps_get_structure(caps_v, 0);
8787 gst_structure_get_int(p, "width", &width);
8788 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8790 gst_structure_get_int(p, "height", &height);
8791 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8793 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8795 SECURE_LOGD("width : %d height : %d", width, height);
8797 gst_caps_unref(caps_v);
8798 gst_object_unref(pad);
8801 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8802 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8809 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8811 gboolean ret = FALSE;
8812 guint64 data_size = 0;
8816 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8817 if (!player->duration)
8820 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8821 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8822 if (stat(path, &sb) == 0)
8823 data_size = (guint64)sb.st_size;
8825 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8826 data_size = player->http_content_size;
8829 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8832 guint64 bitrate = 0;
8833 guint64 msec_dur = 0;
8835 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8837 bitrate = data_size * 8 * 1000 / msec_dur;
8838 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8839 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8843 LOGD("player duration is less than 0");
8847 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8848 if (player->total_bitrate) {
8849 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8858 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile *data, const char *uri, int uri_type)
8860 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8861 data->uri_type = uri_type;
8865 __mmplayer_set_mem_uri(MMPlayerParseProfile *data, char *path, void *param)
8867 int ret = MM_ERROR_PLAYER_INVALID_URI;
8869 char *buffer = NULL;
8870 char *seperator = strchr(path, ',');
8871 char ext[100] = {0,}, size[100] = {0,};
8874 if ((buffer = strstr(path, "ext="))) {
8875 buffer += strlen("ext=");
8877 if (strlen(buffer)) {
8878 strncpy(ext, buffer, 99);
8880 if ((seperator = strchr(ext, ','))
8881 || (seperator = strchr(ext, ' '))
8882 || (seperator = strchr(ext, '\0'))) {
8883 seperator[0] = '\0';
8888 if ((buffer = strstr(path, "size="))) {
8889 buffer += strlen("size=");
8891 if (strlen(buffer) > 0) {
8892 strncpy(size, buffer, 99);
8894 if ((seperator = strchr(size, ','))
8895 || (seperator = strchr(size, ' '))
8896 || (seperator = strchr(size, '\0'))) {
8897 seperator[0] = '\0';
8900 mem_size = atoi(size);
8905 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8907 if (mem_size && param) {
8908 if (data->input_mem.buf)
8909 free(data->input_mem.buf);
8910 data->input_mem.buf = malloc(mem_size);
8912 if (data->input_mem.buf) {
8913 memcpy(data->input_mem.buf, param, mem_size);
8914 data->input_mem.len = mem_size;
8915 ret = MM_ERROR_NONE;
8917 LOGE("failed to alloc mem %d", mem_size);
8918 ret = MM_ERROR_PLAYER_INTERNAL;
8921 data->input_mem.offset = 0;
8922 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8929 __mmplayer_set_file_uri(MMPlayerParseProfile *data, const char *uri)
8931 gchar *location = NULL;
8934 int ret = MM_ERROR_NONE;
8936 if ((path = strstr(uri, "file://"))) {
8937 location = g_filename_from_uri(uri, NULL, &err);
8938 if (!location || (err != NULL)) {
8939 LOGE("Invalid URI '%s' for filesrc: %s", path,
8940 (err != NULL) ? err->message : "unknown error");
8944 MMPLAYER_FREEIF(location);
8946 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8947 return MM_ERROR_PLAYER_INVALID_URI;
8949 LOGD("path from uri: %s", location);
8952 path = (location != NULL) ? (location) : ((char *)uri);
8955 ret = util_exist_file_path(path);
8957 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
8958 if (ret == MM_ERROR_NONE) {
8959 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
8960 if (util_is_sdp_file(path)) {
8961 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
8962 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
8964 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
8966 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
8967 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
8969 LOGE("invalid uri, could not play..");
8970 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8973 MMPLAYER_FREEIF(location);
8978 static MMPlayerVideoStreamDataType *
8979 __mmplayer_create_stream_from_pad(GstPad *pad)
8981 GstCaps *caps = NULL;
8982 GstStructure *structure = NULL;
8983 unsigned int fourcc = 0;
8984 const gchar *string_format = NULL;
8985 MMPlayerVideoStreamDataType *stream = NULL;
8987 MMPixelFormatType format;
8989 caps = gst_pad_get_current_caps(pad);
8991 LOGE("Caps is NULL.");
8995 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
8996 structure = gst_caps_get_structure(caps, 0);
8997 gst_structure_get_int(structure, "width", &width);
8998 gst_structure_get_int(structure, "height", &height);
8999 string_format = gst_structure_get_string(structure, "format");
9001 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9002 format = util_get_pixtype(fourcc);
9003 gst_caps_unref(caps);
9006 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9007 LOGE("Wrong condition!!");
9011 stream = (MMPlayerVideoStreamDataType *)g_try_malloc0(sizeof(MMPlayerVideoStreamDataType));
9013 LOGE("failed to alloc mem for video data");
9017 stream->width = width;
9018 stream->height = height;
9019 stream->format = format;
9025 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9027 unsigned int pitch = 0;
9029 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9031 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9032 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9033 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9034 stream->stride[index] = pitch;
9035 stream->elevation[index] = stream->height;
9040 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9042 if (stream->format == MM_PIXEL_FORMAT_I420) {
9043 int ret = TBM_SURFACE_ERROR_NONE;
9044 tbm_surface_h surface;
9045 tbm_surface_info_s info;
9047 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9049 ret = tbm_surface_get_info(surface, &info);
9050 if (ret != TBM_SURFACE_ERROR_NONE) {
9051 tbm_surface_destroy(surface);
9055 tbm_surface_destroy(surface);
9056 stream->stride[0] = info.planes[0].stride;
9057 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9058 stream->stride[1] = info.planes[1].stride;
9059 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9060 stream->stride[2] = info.planes[2].stride;
9061 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9062 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9063 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9064 stream->stride[0] = stream->width * 4;
9065 stream->elevation[0] = stream->height;
9066 stream->bo_size = stream->stride[0] * stream->height;
9068 LOGE("Not support format %d", stream->format);
9076 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9078 tbm_bo_handle thandle;
9080 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9081 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9082 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9086 unsigned char *src = NULL;
9087 unsigned char *dest = NULL;
9088 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9090 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9092 LOGE("fail to gst_memory_map");
9096 if (!mapinfo.data) {
9097 LOGE("data pointer is wrong");
9101 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9102 if (!stream->bo[0]) {
9103 LOGE("Fail to tbm_bo_alloc!!");
9107 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9109 LOGE("thandle pointer is wrong");
9113 if (stream->format == MM_PIXEL_FORMAT_I420) {
9114 src_stride[0] = GST_ROUND_UP_4(stream->width);
9115 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9116 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9117 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9120 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9121 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9123 for (i = 0; i < 3; i++) {
9124 src = mapinfo.data + src_offset[i];
9125 dest = thandle.ptr + dest_offset[i];
9130 for (j = 0; j < stream->height >> k; j++) {
9131 memcpy(dest, src, stream->width>>k);
9132 src += src_stride[i];
9133 dest += stream->stride[i];
9136 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9137 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9139 LOGE("Not support format %d", stream->format);
9143 tbm_bo_unmap(stream->bo[0]);
9144 gst_memory_unmap(mem, &mapinfo);
9150 tbm_bo_unmap(stream->bo[0]);
9153 gst_memory_unmap(mem, &mapinfo);
9159 __mmplayer_set_pause_state(mm_player_t *player)
9161 if (player->sent_bos)
9164 /* rtsp case, get content attrs by GstMessage */
9165 if (MMPLAYER_IS_RTSP_STREAMING(player))
9168 /* it's first time to update all content attrs. */
9169 __mmplayer_update_content_attrs(player, ATTR_ALL);
9173 __mmplayer_set_playing_state(mm_player_t *player)
9175 gchar *audio_codec = NULL;
9177 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9178 /* initialize because auto resume is done well. */
9179 player->resumed_by_rewind = FALSE;
9180 player->playback_rate = 1.0;
9183 if (player->sent_bos)
9186 /* try to get content metadata */
9188 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9189 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9190 * legacy mmfw-player api
9192 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9194 if ((player->cmd == MMPLAYER_COMMAND_START)
9195 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9196 __mmplayer_handle_missed_plugin(player);
9199 /* check audio codec field is set or not
9200 * we can get it from typefinder or codec's caps.
9202 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9204 /* The codec format can't be sent for audio only case like amr, mid etc.
9205 * Because, parser don't make related TAG.
9206 * So, if it's not set yet, fill it with found data.
9209 if (g_strrstr(player->type, "audio/midi"))
9210 audio_codec = "MIDI";
9211 else if (g_strrstr(player->type, "audio/x-amr"))
9212 audio_codec = "AMR";
9213 else if (g_strrstr(player->type, "audio/mpeg")
9214 && !g_strrstr(player->type, "mpegversion= (int)1"))
9215 audio_codec = "AAC";
9217 audio_codec = "unknown";
9219 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9221 if (mm_attrs_commit_all(player->attrs))
9222 LOGE("failed to update attributes");
9224 LOGD("set audio codec type with caps");