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 MMPLAYER_USE_FILE_FOR_BUFFERING(player) \
93 (((player)->profile.uri_type != MM_PLAYER_URI_TYPE_HLS) && \
94 (player->ini.http_use_file_buffer) && \
95 (player->http_file_buffering_path) && \
96 (strlen(player->http_file_buffering_path) > 0))
98 #define PLAYER_DISPLAY_MODE_DST_ROI 5
100 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
103 #define PLAYER_PD_EXT_MAX_SIZE_BYTE 1024 * 1024 * 3
104 #define PLAYER_PD_STATE_CHANGE_TIME 20 /* sec */
106 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
107 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
108 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
109 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
111 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
112 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
114 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
116 /*---------------------------------------------------------------------------
117 | LOCAL CONSTANT DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
120 /*---------------------------------------------------------------------------
121 | LOCAL DATA TYPE DEFINITIONS: |
122 ---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------
125 | GLOBAL VARIABLE DEFINITIONS: |
126 ---------------------------------------------------------------------------*/
128 /*---------------------------------------------------------------------------
129 | LOCAL VARIABLE DEFINITIONS: |
130 ---------------------------------------------------------------------------*/
131 static sound_stream_info_h stream_info;
133 /*---------------------------------------------------------------------------
134 | LOCAL FUNCTION PROTOTYPES: |
135 ---------------------------------------------------------------------------*/
136 static int __mmplayer_gst_create_pipeline(mm_player_t* player);
137 static int __mmplayer_gst_destroy_pipeline(mm_player_t* player);
138 static int __mmplayer_gst_create_text_pipeline(mm_player_t* player);
139 static int __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps *caps, MMDisplaySurfaceType surface_type);
140 static int __mmplayer_gst_create_audio_sink_bin(mm_player_t* player);
141 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player);
143 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data);
144 static void __mmplayer_gst_decode_no_more_pads(GstElement* elem, gpointer data);
145 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
146 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad, GstCaps *caps, gpointer data);
147 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad, GstCaps * caps, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
151 static gboolean __mmplayer_is_midi_type(gchar* str_caps);
152 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
153 static void __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps);
155 static gboolean __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_release_misc(mm_player_t* player);
157 static void __mmplayer_release_misc_post(mm_player_t* player);
158 static gboolean __mmplayer_init_gstreamer(mm_player_t* player);
159 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
160 static void __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
162 static int __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index);
164 static gboolean __mmplayer_check_subtitle(mm_player_t* player);
165 static int __mmplayer_handle_missed_plugin(mm_player_t* player);
166 static int __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime);
167 static void __mmplayer_add_sink(mm_player_t* player, GstElement* sink);
168 static void __mmplayer_del_sink(mm_player_t* player, GstElement* sink);
169 static void __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type);
170 static gpointer __mmplayer_gapless_play_thread(gpointer data);
171 static gboolean __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element);
172 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
173 static void __mmplayer_release_dump_list(GList *dump_list);
174 static int __mmplayer_gst_realize(mm_player_t* player);
175 static int __mmplayer_gst_unrealize(mm_player_t* player);
176 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position);
177 static int __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param);
180 static int __mmplayer_realize_streaming_ext(mm_player_t* player);
181 static int __mmplayer_unrealize_streaming_ext(mm_player_t *player);
182 static int __mmplayer_start_streaming_ext(mm_player_t *player);
183 static int __mmplayer_destroy_streaming_ext(mm_player_t* player);
184 static gboolean __mmplayer_verify_gapless_play_path(mm_player_t *player);
185 static void __mmplayer_activate_next_source(mm_player_t *player, GstState target);
186 static void __mmplayer_check_pipeline(mm_player_t* player);
187 static gboolean __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type);
188 static void __mmplayer_deactivate_old_path(mm_player_t *player);
189 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player);
190 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name);
191 static void __mmplayer_gst_caps_notify_cb(GstPad * pad, GParamSpec * unused, gpointer data);
192 static void __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer);
193 static void __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type);
194 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
195 static gboolean __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs);
196 static gboolean __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs);
197 static gboolean __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs);
198 static gboolean __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs);
200 static void __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type);
201 static int __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param);
202 static int __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri);
204 static MMPlayerVideoStreamDataType* __mmplayer_create_stream_from_pad(GstPad *pad);
205 static void __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem);
206 static gboolean __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream);
207 static gboolean __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem);
209 static void __mmplayer_set_pause_state(mm_player_t *player);
210 static void __mmplayer_set_playing_state(mm_player_t *player);
211 /*===========================================================================================
213 | FUNCTION DEFINITIONS |
215 ========================================================================================== */
219 print_tag(const GstTagList * list, const gchar * tag, gpointer unused)
223 count = gst_tag_list_get_tag_size(list, tag);
225 LOGD("count = %d", count);
227 for (i = 0; i < count; i++) {
230 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
231 if (!gst_tag_list_get_string_index(list, tag, i, &str))
232 g_assert_not_reached();
234 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
237 g_print(" %15s: %s\n", gst_tag_get_nick(tag), str);
239 g_print(" : %s\n", str);
246 /* This function should be called after the pipeline goes PAUSED or higher
249 __mmplayer_update_content_attrs(mm_player_t* player, enum content_attr_flag flag)
251 static gboolean has_duration = FALSE;
252 static gboolean has_video_attrs = FALSE;
253 static gboolean has_audio_attrs = FALSE;
254 static gboolean has_bitrate = FALSE;
255 gboolean missing_only = FALSE;
256 gboolean all = FALSE;
257 MMHandleType attrs = 0;
261 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
263 /* check player state here */
264 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
265 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
266 /* give warning now only */
267 LOGW("be careful. content attributes may not available in this state ");
270 /* get content attribute first */
271 attrs = MMPLAYER_GET_ATTRS(player);
273 LOGE("cannot get content attribute");
277 /* get update flag */
279 if (flag & ATTR_MISSING_ONLY) {
281 LOGD("updating missed attr only");
284 if (flag & ATTR_ALL) {
286 has_duration = FALSE;
287 has_video_attrs = FALSE;
288 has_audio_attrs = FALSE;
291 LOGD("updating all attrs");
294 if (missing_only && all) {
295 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
296 missing_only = FALSE;
299 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
300 has_duration = __mmplayer_update_duration_attrs(player, attrs);
302 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
303 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
305 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
306 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
308 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
309 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
312 if (mm_attrs_commit_all(attrs)) {
313 LOGE("failed to update attributes\n");
322 MMStreamingType __mmplayer_get_stream_service_type(mm_player_t* player)
324 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
328 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
330 player->pipeline->mainbin &&
331 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
332 STREAMING_SERVICE_NONE);
334 /* streaming service type if streaming */
335 if (!MMPLAYER_IS_STREAMING(player))
336 return STREAMING_SERVICE_NONE;
338 streaming_type = (player->duration == 0) ?
339 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
341 switch (streaming_type) {
342 case STREAMING_SERVICE_LIVE:
343 LOGD("it's live streaming");
345 case STREAMING_SERVICE_VOD:
346 LOGD("it's vod streaming");
349 LOGE("should not get here");
355 return streaming_type;
359 /* this function sets the player state and also report
360 * it to applicaton by calling callback function
363 __mmplayer_set_state(mm_player_t *player, int state)
365 MMMessageParamType msg = {0, };
367 MMPLAYER_RETURN_IF_FAIL(player);
369 if (MMPLAYER_CURRENT_STATE(player) == state) {
370 LOGW("already same state(%s)\n", MMPLAYER_STATE_GET_NAME(state));
371 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
375 /* update player states */
376 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
377 MMPLAYER_CURRENT_STATE(player) = state;
379 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
380 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
383 MMPLAYER_PRINT_STATE(player);
385 switch (MMPLAYER_CURRENT_STATE(player)) {
386 case MM_PLAYER_STATE_NULL:
387 case MM_PLAYER_STATE_READY:
389 case MM_PLAYER_STATE_PAUSED:
390 __mmplayer_set_pause_state(player);
392 case MM_PLAYER_STATE_PLAYING:
393 __mmplayer_set_playing_state(player);
395 case MM_PLAYER_STATE_NONE:
397 LOGW("invalid target state, there is nothing to do.\n");
402 /* post message to application */
403 if (MMPLAYER_TARGET_STATE(player) == state) {
404 /* fill the message with state of player */
405 msg.union_type = MM_MSG_UNION_STATE;
406 msg.state.previous = MMPLAYER_PREV_STATE(player);
407 msg.state.current = MMPLAYER_CURRENT_STATE(player);
409 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
411 /* state changed by resource callback */
412 if (player->interrupted_by_resource) {
413 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
414 } else { /* state changed by usecase */
415 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
418 LOGD("intermediate state, do nothing.\n");
419 MMPLAYER_PRINT_STATE(player);
423 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
424 && !player->sent_bos) {
425 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
426 player->sent_bos = TRUE;
433 __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command)
435 MMPlayerStateType current_state = MM_PLAYER_STATE_NUM;
436 MMPlayerStateType pending_state = MM_PLAYER_STATE_NUM;
438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
440 //LOGD("incomming command : %d \n", command);
442 current_state = MMPLAYER_CURRENT_STATE(player);
443 pending_state = MMPLAYER_PENDING_STATE(player);
445 MMPLAYER_PRINT_STATE(player);
448 case MMPLAYER_COMMAND_CREATE:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
452 if (current_state == MM_PLAYER_STATE_NULL ||
453 current_state == MM_PLAYER_STATE_READY ||
454 current_state == MM_PLAYER_STATE_PAUSED ||
455 current_state == MM_PLAYER_STATE_PLAYING)
460 case MMPLAYER_COMMAND_DESTROY:
462 /* destroy can called anytime */
464 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
468 case MMPLAYER_COMMAND_REALIZE:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (pending_state != MM_PLAYER_STATE_NONE) {
475 /* need ready state to realize */
476 if (current_state == MM_PLAYER_STATE_READY)
479 if (current_state != MM_PLAYER_STATE_NULL)
485 case MMPLAYER_COMMAND_UNREALIZE:
487 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
489 if (current_state == MM_PLAYER_STATE_NULL)
494 case MMPLAYER_COMMAND_START:
496 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
498 if (pending_state == MM_PLAYER_STATE_NONE) {
499 if (current_state == MM_PLAYER_STATE_PLAYING)
501 else if (current_state != MM_PLAYER_STATE_READY &&
502 current_state != MM_PLAYER_STATE_PAUSED)
504 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
506 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
507 LOGD("player is going to paused state, just change the pending state as playing");
513 case MMPLAYER_COMMAND_STOP:
515 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
517 if (current_state == MM_PLAYER_STATE_READY)
520 /* need playing/paused state to stop */
521 if (current_state != MM_PLAYER_STATE_PLAYING &&
522 current_state != MM_PLAYER_STATE_PAUSED)
527 case MMPLAYER_COMMAND_PAUSE:
529 if (MMPLAYER_IS_LIVE_STREAMING(player))
532 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
533 goto NOT_COMPLETED_SEEK;
535 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
537 if (pending_state == MM_PLAYER_STATE_NONE) {
538 if (current_state == MM_PLAYER_STATE_PAUSED)
540 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
542 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
544 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
545 if (current_state == MM_PLAYER_STATE_PAUSED)
546 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
553 case MMPLAYER_COMMAND_RESUME:
555 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
556 goto NOT_COMPLETED_SEEK;
558 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
560 if (pending_state == MM_PLAYER_STATE_NONE) {
561 if (current_state == MM_PLAYER_STATE_PLAYING)
563 else if (current_state != MM_PLAYER_STATE_PAUSED)
565 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
567 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
568 LOGD("player is going to paused state, just change the pending state as playing");
577 player->cmd = command;
579 return MM_ERROR_NONE;
582 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
583 MMPLAYER_STATE_GET_NAME(current_state), command);
584 return MM_ERROR_PLAYER_INVALID_STATE;
587 LOGW("not completed seek");
588 return MM_ERROR_PLAYER_DOING_SEEK;
591 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
592 return MM_ERROR_PLAYER_NO_OP;
595 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
596 return MM_ERROR_PLAYER_NO_OP;
599 static gpointer __mmplayer_gapless_play_thread(gpointer data)
601 mm_player_t* player = (mm_player_t*) data;
602 MMPlayerGstElement *mainbin = NULL;
604 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
606 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
607 while (!player->gapless_play_thread_exit) {
608 LOGD("gapless play thread started. waiting for signal.\n");
609 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
611 LOGD("reconfigure pipeline for gapless play.\n");
613 if (player->gapless_play_thread_exit) {
614 if (player->gapless.reconfigure) {
615 player->gapless.reconfigure = false;
616 MMPLAYER_PLAYBACK_UNLOCK(player);
618 LOGD("exiting gapless play thread\n");
622 mainbin = player->pipeline->mainbin;
624 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
625 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
626 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
627 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
628 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
630 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
632 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
638 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
640 GSource *source = NULL;
644 source = g_main_context_find_source_by_id(context, source_id);
646 if (source != NULL) {
647 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
648 g_source_destroy(source);
654 void __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
656 mm_player_t* player = (mm_player_t*)hplayer;
657 GstMessage *msg = NULL;
658 GQueue *queue = NULL;
661 MMPLAYER_RETURN_IF_FAIL(player);
663 /* disconnecting bus watch */
664 if (player->bus_watcher)
665 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
666 player->bus_watcher = 0;
668 /* destroy the gst bus msg thread */
669 if (player->bus_msg_thread) {
670 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
671 player->bus_msg_thread_exit = TRUE;
672 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
673 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
675 LOGD("gst bus msg thread exit.");
676 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
677 player->bus_msg_thread = NULL;
679 g_mutex_clear(&player->bus_msg_thread_mutex);
680 g_cond_clear(&player->bus_msg_thread_cond);
683 g_mutex_lock(&player->bus_msg_q_lock);
684 queue = player->bus_msg_q;
685 while (!g_queue_is_empty(queue)) {
686 msg = (GstMessage *)g_queue_pop_head(queue);
691 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
692 gst_message_unref(msg);
694 g_mutex_unlock(&player->bus_msg_q_lock);
700 __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink)
702 GstElement* parent = NULL;
704 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
706 /* if we have no fakesink. this meas we are using decodebin which doesn'
707 t need to add extra fakesink */
708 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
711 MMPLAYER_FSINK_LOCK(player);
716 /* get parent of fakesink */
717 parent = (GstElement*)gst_object_get_parent((GstObject*)fakesink->gst);
719 LOGD("fakesink already removed\n");
723 gst_element_set_locked_state(fakesink->gst, TRUE);
725 /* setting the state to NULL never returns async
726 * so no need to wait for completion of state transiton
728 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
729 LOGE("fakesink state change failure!\n");
730 /* FIXIT : should I return here? or try to proceed to next? */
733 /* remove fakesink from it's parent */
734 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
735 LOGE("failed to remove fakesink\n");
737 gst_object_unref(parent);
742 gst_object_unref(parent);
744 LOGD("state-holder removed\n");
746 gst_element_set_locked_state(fakesink->gst, FALSE);
748 MMPLAYER_FSINK_UNLOCK(player);
753 gst_element_set_locked_state(fakesink->gst, FALSE);
755 MMPLAYER_FSINK_UNLOCK(player);
759 static GstPadProbeReturn
760 __mmplayer_gst_selector_blocked(GstPad* pad, GstPadProbeInfo *info, gpointer data)
762 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
763 return GST_PAD_PROBE_OK;
767 __mmplayer_gst_selector_update_start_time(mm_player_t* player, MMPlayerTrackType stream_type)
769 gint64 stop_running_time = 0;
770 gint64 position_running_time = 0;
774 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
775 if ((player->gapless.update_segment[idx] == TRUE) ||
776 !(player->selector[idx].event_probe_id)) {
777 /* LOGW("[%d] skip", idx); */
781 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
783 gst_segment_to_running_time(&player->gapless.segment[idx],
784 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
785 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
787 gst_segment_to_running_time(&player->gapless.segment[idx],
788 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
790 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
792 gst_segment_to_running_time(&player->gapless.segment[idx],
793 GST_FORMAT_TIME, player->duration);
796 position_running_time =
797 gst_segment_to_running_time(&player->gapless.segment[idx],
798 GST_FORMAT_TIME, player->gapless.segment[idx].position);
800 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
801 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
803 GST_TIME_ARGS(stop_running_time),
804 GST_TIME_ARGS(position_running_time),
805 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
806 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
808 position_running_time = MAX(position_running_time, stop_running_time);
809 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
810 GST_FORMAT_TIME, player->gapless.segment[idx].start);
811 position_running_time = MAX(0, position_running_time);
812 position = MAX(position, position_running_time);
816 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
817 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
818 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
820 player->gapless.start_time[stream_type] += position;
826 static GstPadProbeReturn
827 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
829 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
830 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
831 mm_player_t *player = (mm_player_t*)data;
832 GstCaps *caps = NULL;
833 GstStructure *str = NULL;
834 const gchar *name = NULL;
835 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
836 gboolean caps_ret = TRUE;
838 if (GST_EVENT_IS_DOWNSTREAM(event) &&
839 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
840 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
841 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
842 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
844 } else if (GST_EVENT_IS_UPSTREAM(event) &&
845 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
849 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
853 if (strstr(name, "audio")) {
854 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
855 } else if (strstr(name, "video")) {
856 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
858 /* text track is not supportable */
859 LOGE("invalid name %s", name);
863 switch (GST_EVENT_TYPE(event)) {
866 /* in case of gapless, drop eos event not to send it to sink */
867 if (player->gapless.reconfigure && !player->msg_posted) {
868 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
869 ret = GST_PAD_PROBE_DROP;
873 case GST_EVENT_STREAM_START:
875 __mmplayer_gst_selector_update_start_time(player, stream_type);
878 case GST_EVENT_FLUSH_STOP:
880 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
881 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
882 player->gapless.start_time[stream_type] = 0;
885 case GST_EVENT_SEGMENT:
890 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
891 gst_event_copy_segment(event, &segment);
893 if (segment.format != GST_FORMAT_TIME)
896 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
897 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
898 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
899 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
900 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
901 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
903 /* keep the all the segment ev to cover the seeking */
904 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
905 player->gapless.update_segment[stream_type] = TRUE;
907 if (!player->gapless.running)
910 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
912 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
914 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
915 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
916 gst_event_unref(event);
917 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
923 gdouble proportion = 0.0;
924 GstClockTimeDiff diff = 0;
925 GstClockTime timestamp = 0;
926 gint64 running_time_diff = -1;
928 GstEvent *tmpev = NULL;
930 running_time_diff = player->gapless.segment[stream_type].base;
932 if (running_time_diff <= 0) /* don't need to adjust */
935 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
936 gst_event_unref(event);
938 if (timestamp < running_time_diff) {
939 LOGW("QOS event from previous group");
940 ret = GST_PAD_PROBE_DROP;
944 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
945 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
946 stream_type, GST_TIME_ARGS(timestamp),
947 GST_TIME_ARGS(running_time_diff),
948 GST_TIME_ARGS(timestamp - running_time_diff));
950 timestamp -= running_time_diff;
952 /* That case is invalid for QoS events */
953 if (diff < 0 && -diff > timestamp) {
954 LOGW("QOS event from previous group");
955 ret = GST_PAD_PROBE_DROP;
959 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
960 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
970 gst_caps_unref(caps);
974 /* create fakesink for audio or video path witout audiobin or videobin */
976 __mmplayer_gst_make_fakesink(mm_player_t *player, GstPad *pad, const gchar *name)
978 GstElement *pipeline = NULL;
979 GstElement *fakesink = NULL;
980 GstPad *sinkpad = NULL;
983 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
985 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
988 fakesink = gst_element_factory_make("fakesink", NULL);
989 if (fakesink == NULL) {
990 LOGE("failed to create fakesink");
994 /* store it as it's sink element */
995 __mmplayer_add_sink(player, fakesink);
997 gst_bin_add(GST_BIN(pipeline), fakesink);
1000 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1002 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1004 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1005 LOGE("failed to link fakesink");
1006 gst_object_unref(GST_OBJECT(fakesink));
1010 if (strstr(name, "video")) {
1011 player->video_fakesink = fakesink;
1013 if (player->v_stream_caps) {
1014 gst_caps_unref(player->v_stream_caps);
1015 player->v_stream_caps = NULL;
1018 if (player->ini.set_dump_element_flag)
1019 __mmplayer_add_dump_buffer_probe(player, fakesink);
1022 if (player->set_mode.media_packet_video_stream) { /* export video decoded frame */
1023 g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
1025 __mmplayer_add_signal_connection(player,
1027 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1029 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
1032 __mmplayer_add_signal_connection(player,
1034 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
1036 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
1041 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1042 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1046 gst_object_unref(GST_OBJECT(sinkpad));
1053 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1055 GstElement *pipeline = NULL;
1056 GstElement *selector = NULL;
1057 GstPad *srcpad = NULL;
1060 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1062 selector = gst_element_factory_make("input-selector", NULL);
1064 LOGE("failed to create input-selector");
1067 g_object_set(selector, "sync-streams", TRUE, NULL);
1069 player->pipeline->mainbin[elem_idx].id = elem_idx;
1070 player->pipeline->mainbin[elem_idx].gst = selector;
1072 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1074 srcpad = gst_element_get_static_pad(selector, "src");
1076 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1077 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1078 __mmplayer_gst_selector_blocked, NULL, NULL);
1079 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1080 __mmplayer_gst_selector_event_probe, player, NULL);
1082 gst_element_set_state(selector, GST_STATE_PAUSED);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1085 gst_bin_add(GST_BIN(pipeline), selector);
1092 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1094 mm_player_t *player = NULL;
1095 GstElement *selector = NULL;
1096 GstCaps *caps = NULL;
1097 GstStructure *str = NULL;
1098 const gchar *name = NULL;
1099 GstPad *sinkpad = NULL;
1100 GstPad *srcpad = NULL;
1101 gboolean first_track = FALSE;
1102 gboolean caps_ret = TRUE;
1104 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1105 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1108 player = (mm_player_t*)data;
1111 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1112 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1114 LOGD("pad-added signal handling");
1116 /* get mimetype from caps */
1117 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1121 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1122 /* LOGD("detected mimetype : %s", name); */
1124 if (strstr(name, "video")) {
1126 gchar *caps_str = NULL;
1128 caps_str = gst_caps_to_string(caps);
1129 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1130 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1131 player->set_mode.video_zc = TRUE;
1133 MMPLAYER_FREEIF(caps_str);
1135 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1136 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1138 LOGD("surface type : %d", stype);
1140 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1141 __mmplayer_gst_create_sinkbin(elem, pad, player);
1145 if (stype == MM_DISPLAY_SURFACE_NULL) {
1146 __mmplayer_gst_make_fakesink(player, pad, name);
1150 LOGD("video selector is required");
1151 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1152 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1153 } else if (strstr(name, "audio")) {
1154 gint samplerate = 0;
1157 gst_structure_get_int(str, "rate", &samplerate);
1158 gst_structure_get_int(str, "channels", &channels);
1160 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1161 __mmplayer_gst_create_sinkbin(elem, pad, player);
1165 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1166 __mmplayer_gst_make_fakesink(player, pad, name);
1170 LOGD("audio selector is required");
1171 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1172 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1174 } else if (strstr(name, "text")) {
1175 LOGD("text selector is required");
1176 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1177 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1179 LOGE("invalid caps info");
1183 /* check selector and create it */
1184 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1185 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1190 LOGD("input-selector is already created.");
1194 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1196 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1198 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1199 LOGE("failed to link selector");
1200 gst_object_unref(GST_OBJECT(selector));
1205 LOGD("this track will be activated");
1206 g_object_set(selector, "active-pad", sinkpad, NULL);
1209 __mmplayer_track_update_info(player, stream_type, sinkpad);
1215 gst_caps_unref(caps);
1218 gst_object_unref(GST_OBJECT(sinkpad));
1223 gst_object_unref(GST_OBJECT(srcpad));
1230 static gboolean __mmplayer_create_sink_path(mm_player_t* player, GstElement* selector, MMPlayerTrackType type)
1232 GstPad* srcpad = NULL;
1235 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1237 LOGD("type %d", type);
1240 LOGD("there is no %d track", type);
1244 srcpad = gst_element_get_static_pad(selector, "src");
1246 LOGE("failed to get srcpad from selector");
1250 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1252 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1254 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1255 if (player->selector[type].block_id) {
1256 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1257 player->selector[type].block_id = 0;
1261 gst_object_unref(GST_OBJECT(srcpad));
1269 static void __mmplayer_set_decode_track_info(mm_player_t* player, MMPlayerTrackType type)
1271 MMHandleType attrs = 0;
1272 gint active_index = 0;
1273 gchar *attr_name = NULL;
1276 MMPLAYER_RETURN_IF_FAIL(player);
1278 LOGD("type %d", type);
1280 /* change track to active pad */
1281 active_index = player->selector[type].active_pad_index;
1282 if ((active_index != DEFAULT_TRACK) &&
1283 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1284 LOGW("failed to change %d type track to %d", type, active_index);
1285 player->selector[type].active_pad_index = DEFAULT_TRACK;
1288 LOGD("Total num of tracks = %d", player->selector[type].total_track_num);
1290 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
1291 attr_name = "content_audio_track_num";
1292 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1293 attr_name = "content_text_track_num";
1295 LOGE("invalid type info %d", type);
1299 attrs = MMPLAYER_GET_ATTRS(player);
1301 mm_attrs_set_int_by_name(attrs, attr_name, (gint)player->selector[type].total_track_num);
1302 if (mm_attrs_commit_all(attrs))
1303 LOGW("failed to commit attrs.");
1305 LOGW("cannot get content attribute");
1312 static gboolean __mmplayer_create_audio_sink_path(mm_player_t* player, GstElement* audio_selector)
1315 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1317 if (!audio_selector) {
1318 LOGD("there is no audio track");
1320 /* in case the source is changed, output can be changed. */
1321 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1322 LOGD("remove previous audiobin if it exist");
1324 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1325 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1327 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1328 MMPLAYER_FREEIF(player->pipeline->audiobin);
1331 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1332 __mmplayer_pipeline_complete(NULL, player);
1337 /* apply the audio track information */
1338 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1340 /* create audio sink path */
1341 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1342 LOGE("failed to create audio sink path");
1350 static gboolean __mmplayer_create_text_sink_path(mm_player_t* player, GstElement* text_selector)
1353 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1355 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1356 LOGD("text path is not supproted");
1360 /* apply the text track information */
1361 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1363 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1364 player->has_closed_caption = TRUE;
1366 /* create text decode path */
1367 player->no_more_pad = TRUE;
1369 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1370 LOGE("failed to create text sink path");
1379 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1381 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1383 gint init_buffering_time = 0;
1384 guint buffer_bytes = 0;
1385 gint64 dur_bytes = 0L;
1388 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1389 player->pipeline->mainbin && player->streamer, FALSE);
1391 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1392 buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1394 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1395 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1397 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1399 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1400 LOGE("fail to get duration.");
1402 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1403 * use file information was already set on Q2 when it was created. */
1404 __mm_player_streaming_set_queue2(player->streamer,
1405 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1406 TRUE, /* use_buffering */
1408 init_buffering_time,
1409 1.0, /* low percent */
1410 player->ini.http_buffering_limit, /* high percent */
1411 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1413 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1420 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1422 mm_player_t *player = NULL;
1423 GstElement *video_selector = NULL;
1424 GstElement *audio_selector = NULL;
1425 GstElement *text_selector = NULL;
1428 player = (mm_player_t*) data;
1430 LOGD("no-more-pad signal handling");
1432 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1433 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1434 LOGW("player is shutting down");
1438 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
1439 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
1440 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1441 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1442 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1443 LOGE("failed to set queue2 buffering");
1448 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1449 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1450 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1452 /* create video path followed by video-select */
1453 if (video_selector && !audio_selector && !text_selector)
1454 player->no_more_pad = TRUE;
1456 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1459 /* create audio path followed by audio-select */
1460 if (audio_selector && !text_selector)
1461 player->no_more_pad = TRUE;
1463 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1467 /* create text path followed by text-select */
1468 __mmplayer_create_text_sink_path(player, text_selector);
1471 if (player->gapless.reconfigure) {
1472 player->gapless.reconfigure = FALSE;
1473 MMPLAYER_PLAYBACK_UNLOCK(player);
1480 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1482 gboolean ret = FALSE;
1483 GstElement *pipeline = NULL;
1484 GstPad *sinkpad = NULL;
1487 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1488 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1490 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1492 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1494 LOGE("failed to get pad from sinkbin");
1500 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1501 LOGE("failed to link sinkbin for reusing");
1502 goto EXIT; /* exit either pass or fail */
1506 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1507 LOGE("failed to set state(READY) to sinkbin");
1512 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1513 LOGE("failed to add sinkbin to pipeline");
1518 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1519 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1524 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1525 LOGE("failed to set state(PAUSED) to sinkbin");
1534 gst_object_unref(GST_OBJECT(sinkpad));
1541 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1543 mm_player_t *player = NULL;
1544 MMHandleType attrs = 0;
1545 GstCaps *caps = NULL;
1546 gchar *caps_str = NULL;
1547 GstStructure *str = NULL;
1548 const gchar *name = NULL;
1549 GstElement *sinkbin = NULL;
1550 gboolean reusing = FALSE;
1551 gboolean caps_ret = TRUE;
1552 gchar *sink_pad_name = "sink";
1555 player = (mm_player_t*) data;
1558 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1559 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1561 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1565 caps_str = gst_caps_to_string(caps);
1567 /* LOGD("detected mimetype : %s", name); */
1568 if (strstr(name, "audio")) {
1569 if (player->pipeline->audiobin == NULL) {
1570 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1571 LOGE("failed to create audiobin. continuing without audio");
1575 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1576 LOGD("creating audiobin success");
1579 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1580 LOGD("reusing audiobin");
1581 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1583 } else if (strstr(name, "video")) {
1584 /* 1. zero copy is updated at _decode_pad_added()
1585 * 2. NULL surface type is handled in _decode_pad_added() */
1586 LOGD("zero copy %d", player->set_mode.video_zc);
1587 if (player->pipeline->videobin == NULL) {
1588 int surface_type = 0;
1589 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1590 LOGD("display_surface_type (%d)", surface_type);
1592 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1593 LOGD("mark video overlay for acquire");
1594 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1595 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1596 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1597 &player->video_overlay_resource)
1598 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1599 LOGE("could not mark video_overlay resource for acquire");
1604 player->interrupted_by_resource = FALSE;
1606 if (mm_resource_manager_commit(player->resource_manager) !=
1607 MM_RESOURCE_MANAGER_ERROR_NONE) {
1608 LOGE("could not acquire resources for video playing");
1612 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1613 LOGE("failed to create videobin. continuing without video");
1617 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1618 LOGD("creating videosink bin success");
1621 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1622 LOGD("re-using videobin");
1623 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1625 } else if (strstr(name, "text")) {
1626 if (player->pipeline->textbin == NULL) {
1627 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1628 LOGE("failed to create text sink bin. continuing without text");
1632 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1633 LOGD("creating textsink bin success");
1635 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
1636 player->textsink_linked = 1;
1639 if (!player->textsink_linked) {
1640 LOGD("re-using textbin");
1642 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1643 player->textsink_linked = 1;
1645 /* linked textbin exist which means that the external subtitle path exist already */
1646 LOGW("ignoring internal subtutle since external subtitle is available");
1649 sink_pad_name = "text_sink";
1651 LOGW("unknown mime type %s, ignoring it", name);
1655 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1658 LOGD("[handle: %p] success to create and link sink bin", player);
1660 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1661 * streaming task. if the task blocked, then buffer will not flow to the next element
1662 *(autoplugging element). so this is special hack for streaming. please try to remove it
1664 /* dec stream count. we can remove fakesink if it's zero */
1665 if (player->num_dynamic_pad)
1666 player->num_dynamic_pad--;
1668 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1670 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1671 __mmplayer_pipeline_complete(NULL, player);
1675 MMPLAYER_FREEIF(caps_str);
1678 gst_caps_unref(caps);
1680 /* flusing out new attributes */
1681 if (mm_attrs_commit_all(attrs))
1682 LOGE("failed to comit attributes");
1688 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1690 int required_angle = 0; /* Angle required for straight view */
1691 int rotation_angle = 0;
1693 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1694 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1696 /* Counter clockwise */
1697 switch (orientation) {
1702 required_angle = 270;
1705 required_angle = 180;
1708 required_angle = 90;
1712 rotation_angle = display_angle + required_angle;
1713 if (rotation_angle >= 360)
1714 rotation_angle -= 360;
1716 /* chech if supported or not */
1717 if (rotation_angle % 90) {
1718 LOGD("not supported rotation angle = %d", rotation_angle);
1722 switch (rotation_angle) {
1724 *value = MM_DISPLAY_ROTATION_NONE;
1727 *value = MM_DISPLAY_ROTATION_90;
1730 *value = MM_DISPLAY_ROTATION_180;
1733 *value = MM_DISPLAY_ROTATION_270;
1737 LOGD("setting rotation property value : %d", value);
1743 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1745 /* check video sinkbin is created */
1746 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1748 player->pipeline->videobin &&
1749 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1750 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1751 MM_ERROR_PLAYER_NOT_INITIALIZED);
1753 return MM_ERROR_NONE;
1757 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1759 int display_rotation = 0;
1760 gchar *org_orient = NULL;
1761 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1764 LOGE("cannot get content attribute");
1765 return MM_ERROR_PLAYER_INTERNAL;
1768 if (display_angle) {
1769 /* update user roation */
1770 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1772 /* Counter clockwise */
1773 switch (display_rotation) {
1774 case MM_DISPLAY_ROTATION_NONE:
1777 case MM_DISPLAY_ROTATION_90:
1778 *display_angle = 90;
1780 case MM_DISPLAY_ROTATION_180:
1781 *display_angle = 180;
1783 case MM_DISPLAY_ROTATION_270:
1784 *display_angle = 270;
1787 LOGW("wrong angle type : %d", display_rotation);
1790 LOGD("check user angle: %d", *display_angle);
1794 /* Counter clockwise */
1795 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1798 if (!strcmp(org_orient, "rotate-90"))
1800 else if (!strcmp(org_orient, "rotate-180"))
1802 else if (!strcmp(org_orient, "rotate-270"))
1805 LOGD("original rotation is %s", org_orient);
1807 LOGD("content_video_orientation get fail");
1810 LOGD("check orientation: %d", *orientation);
1813 return MM_ERROR_NONE;
1817 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1819 int rotation_value = 0;
1820 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1821 int display_angle = 0;
1824 /* check video sinkbin is created */
1825 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1828 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1830 /* get rotation value to set */
1831 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1832 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1833 LOGD("set video param : rotate %d", rotation_value);
1837 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1839 MMHandleType attrs = 0;
1843 /* check video sinkbin is created */
1844 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1847 attrs = MMPLAYER_GET_ATTRS(player);
1848 MMPLAYER_RETURN_IF_FAIL(attrs);
1850 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1851 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1852 LOGD("set video param : visible %d", visible);
1856 __mmplayer_video_param_set_display_method(mm_player_t* player)
1858 MMHandleType attrs = 0;
1859 int display_method = 0;
1862 /* check video sinkbin is created */
1863 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1866 attrs = MMPLAYER_GET_ATTRS(player);
1867 MMPLAYER_RETURN_IF_FAIL(attrs);
1869 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1870 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1871 LOGD("set video param : method %d", display_method);
1874 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1876 MMHandleType attrs = 0;
1877 void *handle = NULL;
1880 /* check video sinkbin is created */
1881 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1882 LOGW("There is no video sink");
1886 attrs = MMPLAYER_GET_ATTRS(player);
1887 MMPLAYER_RETURN_IF_FAIL(attrs);
1888 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1890 gst_video_overlay_set_video_roi_area(
1891 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1892 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1893 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1894 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1899 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1901 MMHandleType attrs = 0;
1902 void *handle = NULL;
1906 int win_roi_width = 0;
1907 int win_roi_height = 0;
1910 /* check video sinkbin is created */
1911 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1912 LOGW("There is no video sink");
1916 attrs = MMPLAYER_GET_ATTRS(player);
1917 MMPLAYER_RETURN_IF_FAIL(attrs);
1919 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1922 /* It should be set after setting window */
1923 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1924 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1925 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1926 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1928 /* After setting window handle, set display roi area */
1929 gst_video_overlay_set_display_roi_area(
1930 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1931 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1932 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1933 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1937 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1939 MMHandleType attrs = 0;
1940 void *handle = NULL;
1942 /* check video sinkbin is created */
1943 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1946 attrs = MMPLAYER_GET_ATTRS(player);
1947 MMPLAYER_RETURN_IF_FAIL(attrs);
1949 /* common case if using overlay surface */
1950 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1953 /* default is using wl_surface_id */
1954 unsigned int wl_surface_id = 0;
1955 wl_surface_id = *(int*)handle;
1956 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
1957 gst_video_overlay_set_wl_window_wl_surface_id(
1958 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1961 /* FIXIT : is it error case? */
1962 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1967 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
1969 bool update_all_param = FALSE;
1972 /* check video sinkbin is created */
1973 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1974 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1976 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1977 LOGE("can not find tizenwlsink");
1978 return MM_ERROR_PLAYER_INTERNAL;
1981 LOGD("param_name : %s", param_name);
1982 if (!g_strcmp0(param_name, "update_all_param"))
1983 update_all_param = TRUE;
1985 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1986 __mmplayer_video_param_set_display_overlay(player);
1987 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1988 __mmplayer_video_param_set_display_method(player);
1989 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1990 __mmplayer_video_param_set_display_visible(player);
1991 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1992 __mmplayer_video_param_set_display_rotation(player);
1993 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1994 __mmplayer_video_param_set_roi_area(player);
1995 if (update_all_param)
1996 __mmplayer_video_param_set_video_roi_area(player);
1998 return MM_ERROR_NONE;
2002 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
2004 MMHandleType attrs = 0;
2005 int surface_type = 0;
2006 int ret = MM_ERROR_NONE;
2010 /* check video sinkbin is created */
2011 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2012 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2014 attrs = MMPLAYER_GET_ATTRS(player);
2016 LOGE("cannot get content attribute");
2017 return MM_ERROR_PLAYER_INTERNAL;
2019 LOGD("param_name : %s", param_name);
2021 /* update display surface */
2022 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2023 LOGD("check display surface type attribute: %d", surface_type);
2025 /* configuring display */
2026 switch (surface_type) {
2027 case MM_DISPLAY_SURFACE_OVERLAY:
2029 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2030 if (ret != MM_ERROR_NONE)
2038 return MM_ERROR_NONE;
2042 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2044 gboolean disable_overlay = FALSE;
2045 mm_player_t* player = (mm_player_t*) hplayer;
2046 int ret = MM_ERROR_NONE;
2049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2050 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2051 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2052 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2054 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2055 LOGW("Display control is not supported");
2056 return MM_ERROR_PLAYER_INTERNAL;
2059 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2061 if (audio_only == (bool)disable_overlay) {
2062 LOGE("It's the same with current setting: (%d)", audio_only);
2063 return MM_ERROR_NONE;
2067 LOGE("disable overlay");
2068 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2070 /* release overlay resource */
2071 if (player->video_overlay_resource != NULL) {
2072 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2073 player->video_overlay_resource);
2074 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2075 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2078 player->video_overlay_resource = NULL;
2081 ret = mm_resource_manager_commit(player->resource_manager);
2082 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2083 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2087 /* mark video overlay for acquire */
2088 if (player->video_overlay_resource == NULL) {
2089 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2090 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2091 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2092 &player->video_overlay_resource);
2093 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2094 LOGE("could not prepare for video_overlay resource\n");
2099 player->interrupted_by_resource = FALSE;
2100 /* acquire resources for video overlay */
2101 ret = mm_resource_manager_commit(player->resource_manager);
2102 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2103 LOGE("could not acquire resources for video playing\n");
2107 LOGD("enable overlay");
2108 __mmplayer_video_param_set_display_overlay(player);
2109 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2114 return MM_ERROR_NONE;
2118 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2120 mm_player_t* player = (mm_player_t*) hplayer;
2121 gboolean disable_overlay = FALSE;
2125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2126 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2127 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2128 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2129 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2131 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2132 LOGW("Display control is not supported");
2133 return MM_ERROR_PLAYER_INTERNAL;
2136 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2138 *paudio_only = (bool)(disable_overlay);
2140 LOGD("audio_only : %d", *paudio_only);
2144 return MM_ERROR_NONE;
2148 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2150 GList* bucket = element_bucket;
2151 MMPlayerGstElement* element = NULL;
2152 MMPlayerGstElement* prv_element = NULL;
2153 gint successful_link_count = 0;
2157 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2159 prv_element = (MMPlayerGstElement*)bucket->data;
2160 bucket = bucket->next;
2162 for (; bucket; bucket = bucket->next) {
2163 element = (MMPlayerGstElement*)bucket->data;
2165 if (element && element->gst) {
2166 if (prv_element && prv_element->gst) {
2167 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2168 LOGD("linking [%s] to [%s] success\n",
2169 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2170 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2171 successful_link_count++;
2173 LOGD("linking [%s] to [%s] failed\n",
2174 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2175 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2181 prv_element = element;
2186 return successful_link_count;
2190 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2192 GList* bucket = element_bucket;
2193 MMPlayerGstElement* element = NULL;
2194 int successful_add_count = 0;
2198 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2199 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2201 for (; bucket; bucket = bucket->next) {
2202 element = (MMPlayerGstElement*)bucket->data;
2204 if (element && element->gst) {
2205 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2206 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2207 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2208 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2211 successful_add_count++;
2217 return successful_add_count;
2220 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2222 mm_player_t *player = (mm_player_t*) data;
2223 GstCaps *caps = NULL;
2224 GstStructure *str = NULL;
2226 gboolean caps_ret = TRUE;
2230 MMPLAYER_RETURN_IF_FAIL(pad);
2231 MMPLAYER_RETURN_IF_FAIL(unused);
2232 MMPLAYER_RETURN_IF_FAIL(data);
2234 caps = gst_pad_get_current_caps(pad);
2238 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2242 LOGD("name = %s", name);
2244 if (strstr(name, "audio")) {
2245 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2247 if (player->audio_stream_changed_cb) {
2248 LOGE("call the audio stream changed cb");
2249 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2251 } else if (strstr(name, "video")) {
2252 if ((name = gst_structure_get_string(str, "format")))
2253 player->set_mode.video_zc = name[0] == 'S';
2255 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2257 if (player->video_stream_changed_cb) {
2258 LOGE("call the video stream changed cb");
2259 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2262 LOGW("invalid caps info");
2267 gst_caps_unref(caps);
2277 * This function is to create audio pipeline for playing.
2279 * @param player [in] handle of player
2281 * @return This function returns zero on success.
2283 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2285 /* macro for code readability. just for sinkbin-creation functions */
2286 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2288 x_bin[x_id].id = x_id;\
2289 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2290 if (!x_bin[x_id].gst) {\
2291 LOGE("failed to create %s \n", x_factory);\
2294 if (x_player->ini.set_dump_element_flag)\
2295 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2298 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2302 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2307 MMPLAYER_RETURN_IF_FAIL(player);
2309 if (player->audio_stream_buff_list) {
2310 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2311 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2314 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2315 __mmplayer_audio_stream_send_data(player, tmp);
2318 g_free(tmp->pcm_data);
2322 g_list_free(player->audio_stream_buff_list);
2323 player->audio_stream_buff_list = NULL;
2330 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2332 MMPlayerAudioStreamDataType audio_stream = { 0, };
2335 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2337 audio_stream.bitrate = a_buffer->bitrate;
2338 audio_stream.channel = a_buffer->channel;
2339 audio_stream.depth = a_buffer->depth;
2340 audio_stream.is_little_endian = a_buffer->is_little_endian;
2341 audio_stream.channel_mask = a_buffer->channel_mask;
2342 audio_stream.data_size = a_buffer->data_size;
2343 audio_stream.data = a_buffer->pcm_data;
2345 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2346 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2352 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2354 mm_player_t* player = (mm_player_t*) data;
2359 gint endianness = 0;
2360 guint64 channel_mask = 0;
2361 void *a_data = NULL;
2363 mm_player_audio_stream_buff_t *a_buffer = NULL;
2364 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2368 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2370 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2371 a_data = mapinfo.data;
2372 a_size = mapinfo.size;
2374 GstCaps *caps = gst_pad_get_current_caps(pad);
2375 GstStructure *structure = gst_caps_get_structure(caps, 0);
2377 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2378 gst_structure_get_int(structure, "rate", &rate);
2379 gst_structure_get_int(structure, "channels", &channel);
2380 gst_structure_get_int(structure, "depth", &depth);
2381 gst_structure_get_int(structure, "endianness", &endianness);
2382 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2383 gst_caps_unref(GST_CAPS(caps));
2385 /* In case of the sync is false, use buffer list. *
2386 * The num of buffer list depends on the num of audio channels */
2387 if (player->audio_stream_buff_list) {
2388 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2389 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2391 if (channel_mask == tmp->channel_mask) {
2392 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2393 if (tmp->data_size + a_size < tmp->buff_size) {
2394 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2395 tmp->data_size += a_size;
2397 /* send data to client */
2398 __mmplayer_audio_stream_send_data(player, tmp);
2400 if (a_size > tmp->buff_size) {
2401 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2402 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2403 if (tmp->pcm_data == NULL) {
2404 LOGE("failed to realloc data.");
2407 tmp->buff_size = a_size;
2409 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2410 memcpy(tmp->pcm_data, a_data, a_size);
2411 tmp->data_size = a_size;
2416 LOGE("data is empty in list.");
2422 /* create new audio stream data */
2423 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2424 if (a_buffer == NULL) {
2425 LOGE("failed to alloc data.");
2428 a_buffer->bitrate = rate;
2429 a_buffer->channel = channel;
2430 a_buffer->depth = depth;
2431 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2432 a_buffer->channel_mask = channel_mask;
2433 a_buffer->data_size = a_size;
2435 if (!player->audio_stream_sink_sync) {
2436 /* If sync is FALSE, use buffer list to reduce the IPC. */
2437 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2438 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2439 if (a_buffer->pcm_data == NULL) {
2440 LOGE("failed to alloc data.");
2444 memcpy(a_buffer->pcm_data, a_data, a_size);
2445 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2446 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2448 /* If sync is TRUE, send data directly. */
2449 a_buffer->pcm_data = a_data;
2450 __mmplayer_audio_stream_send_data(player, a_buffer);
2455 gst_buffer_unmap(buffer, &mapinfo);
2460 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2462 mm_player_t* player = (mm_player_t*)data;
2463 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2464 GstPad* sinkpad = NULL;
2465 GstElement *queue = NULL, *sink = NULL;
2468 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2470 queue = gst_element_factory_make("queue", NULL);
2471 if (queue == NULL) {
2472 LOGD("fail make queue\n");
2476 sink = gst_element_factory_make("fakesink", NULL);
2478 LOGD("fail make fakesink\n");
2482 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2484 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2485 LOGW("failed to link queue & sink\n");
2489 sinkpad = gst_element_get_static_pad(queue, "sink");
2491 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2492 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2496 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2498 gst_object_unref(sinkpad);
2499 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2500 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2502 gst_element_set_state(sink, GST_STATE_PAUSED);
2503 gst_element_set_state(queue, GST_STATE_PAUSED);
2505 __mmplayer_add_signal_connection(player,
2507 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2509 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2516 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2518 gst_object_unref(GST_OBJECT(queue));
2522 gst_object_unref(GST_OBJECT(sink));
2526 gst_object_unref(GST_OBJECT(sinkpad));
2533 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2535 #define MAX_PROPS_LEN 128
2536 gint latency_mode = 0;
2537 gchar *stream_type = NULL;
2538 gchar *latency = NULL;
2540 gchar stream_props[MAX_PROPS_LEN] = {0,};
2541 GstStructure *props = NULL;
2544 * It should be set after player creation through attribute.
2545 * But, it can not be changed during playing.
2548 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2550 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2551 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2554 LOGE("stream_type is null.");
2556 if (player->sound.focus_id)
2557 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2558 stream_type, stream_id, player->sound.focus_id);
2560 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2561 stream_type, stream_id);
2562 props = gst_structure_from_string(stream_props, NULL);
2563 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2564 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2565 stream_type, stream_id, player->sound.focus_id, stream_props);
2566 gst_structure_free(props);
2569 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2571 switch (latency_mode) {
2572 case AUDIO_LATENCY_MODE_LOW:
2573 latency = g_strndup("low", 3);
2575 case AUDIO_LATENCY_MODE_MID:
2576 latency = g_strndup("mid", 3);
2578 case AUDIO_LATENCY_MODE_HIGH:
2579 latency = g_strndup("high", 4);
2583 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2587 LOGD("audiosink property - latency=%s", latency);
2594 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2596 MMPlayerGstElement *audiobin = NULL;
2599 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2601 audiobin = player->pipeline->audiobin;
2603 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2604 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2605 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2607 if (player->video360_yaw_radians <= M_PI &&
2608 player->video360_yaw_radians >= -M_PI &&
2609 player->video360_pitch_radians <= M_PI_2 &&
2610 player->video360_pitch_radians >= -M_PI_2) {
2611 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2612 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2613 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2614 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2615 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2616 "source-orientation-y", player->video360_metadata.init_view_heading,
2617 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2624 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2626 MMPlayerGstElement *audiobin = NULL;
2627 MMHandleType attrs = 0;
2628 GList *element_bucket = NULL;
2629 GstCaps *acaps = NULL;
2630 GstPad *sink_pad = NULL;
2633 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2634 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2636 audiobin = player->pipeline->audiobin;
2637 attrs = MMPLAYER_GET_ATTRS(player);
2640 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2642 /* replaygain volume */
2643 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2644 if (player->sound.rg_enable)
2645 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2652 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2653 gchar *dst_format = NULL;
2655 int dst_samplerate = 0;
2656 int dst_channels = 0;
2657 GstCaps *caps = NULL;
2658 char *caps_str = NULL;
2660 /* get conf. values */
2661 mm_attrs_multiple_get(player->attrs, NULL,
2662 "pcm_audioformat", &dst_format, &dst_len,
2663 "pcm_extraction_samplerate", &dst_samplerate,
2664 "pcm_extraction_channels", &dst_channels,
2667 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2671 caps = gst_caps_new_simple("audio/x-raw",
2672 "format", G_TYPE_STRING, dst_format,
2673 "rate", G_TYPE_INT, dst_samplerate,
2674 "channels", G_TYPE_INT, dst_channels,
2677 caps_str = gst_caps_to_string(caps);
2678 LOGD("new caps : %s", caps_str);
2680 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2683 gst_caps_unref(caps);
2684 MMPLAYER_FREEIF(caps_str);
2686 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2688 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2690 /* raw pad handling signal, audiosink will be added after getting signal */
2691 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2692 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2696 /* normal playback */
2699 /* for logical volume control */
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2701 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2703 if (player->sound.mute) {
2704 LOGD("mute enabled");
2705 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2708 /* check if multi-channels */
2709 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
2710 GstPad *srcpad = NULL;
2711 GstCaps *caps = NULL;
2713 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
2714 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
2715 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2716 GstStructure *str = gst_caps_get_structure(caps, 0);
2718 gst_structure_get_int(str, "channels", &channels);
2719 gst_caps_unref(caps);
2721 gst_object_unref(srcpad);
2725 /* audio effect element. if audio effect is enabled */
2726 if ((strcmp(player->ini.audioeffect_element, ""))
2728 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2729 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2731 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2733 if ((!player->bypass_audio_effect)
2734 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2735 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2736 if (!_mmplayer_audio_effect_custom_apply(player))
2737 LOGI("apply audio effect(custom) setting success");
2741 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2742 && (player->set_mode.rich_audio))
2743 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2746 /* create audio sink */
2747 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2748 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2749 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2751 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2752 if (player->is_360_feature_enabled &&
2753 player->is_content_spherical &&
2755 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2756 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2757 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2759 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2761 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2763 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2764 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2765 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2766 gst_caps_unref(acaps);
2768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2770 player->is_openal_plugin_used = TRUE;
2772 if (player->is_360_feature_enabled && player->is_content_spherical)
2773 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2774 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2777 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2778 (player->videodec_linked && player->ini.use_system_clock)) {
2779 LOGD("system clock will be used.");
2780 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2783 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2784 __mmplayer_gst_set_pulsesink_property(player, attrs);
2785 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2786 __mmplayer_gst_set_openalsink_property(player);
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2790 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2792 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2793 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2794 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2795 gst_object_unref(GST_OBJECT(sink_pad));
2797 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2800 *bucket = element_bucket;
2803 return MM_ERROR_NONE;
2806 g_list_free(element_bucket);
2810 return MM_ERROR_PLAYER_INTERNAL;
2814 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2816 MMPlayerGstElement *first_element = NULL;
2817 MMPlayerGstElement *audiobin = NULL;
2819 GstPad *ghostpad = NULL;
2820 GList *element_bucket = NULL;
2824 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2827 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2829 LOGE("failed to allocate memory for audiobin");
2830 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2834 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2835 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2836 if (!audiobin[MMPLAYER_A_BIN].gst) {
2837 LOGE("failed to create audiobin");
2842 player->pipeline->audiobin = audiobin;
2844 /* create audio filters and audiosink */
2845 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2848 /* adding created elements to bin */
2849 LOGD("adding created elements to bin");
2850 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2853 /* linking elements in the bucket by added order. */
2854 LOGD("Linking elements in the bucket by added order.");
2855 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2858 /* get first element's sinkpad for creating ghostpad */
2859 first_element = (MMPlayerGstElement *)element_bucket->data;
2860 if (!first_element) {
2861 LOGE("failed to get first elem");
2865 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2867 LOGE("failed to get pad from first element of audiobin");
2871 ghostpad = gst_ghost_pad_new("sink", pad);
2873 LOGE("failed to create ghostpad");
2877 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2878 LOGE("failed to add ghostpad to audiobin");
2882 gst_object_unref(pad);
2884 g_list_free(element_bucket);
2887 return MM_ERROR_NONE;
2890 LOGD("ERROR : releasing audiobin");
2893 gst_object_unref(GST_OBJECT(pad));
2896 gst_object_unref(GST_OBJECT(ghostpad));
2899 g_list_free(element_bucket);
2901 /* release element which are not added to bin */
2902 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2903 /* NOTE : skip bin */
2904 if (audiobin[i].gst) {
2905 GstObject* parent = NULL;
2906 parent = gst_element_get_parent(audiobin[i].gst);
2909 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2910 audiobin[i].gst = NULL;
2912 gst_object_unref(GST_OBJECT(parent));
2916 /* release audiobin with it's childs */
2917 if (audiobin[MMPLAYER_A_BIN].gst)
2918 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2920 MMPLAYER_FREEIF(audiobin);
2922 player->pipeline->audiobin = NULL;
2924 return MM_ERROR_PLAYER_INTERNAL;
2927 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2929 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2932 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2934 int ret = MM_ERROR_NONE;
2936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2937 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2939 MMPLAYER_VIDEO_BO_LOCK(player);
2941 if (player->video_bo_list) {
2942 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2943 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2944 if (tmp && tmp->bo == bo) {
2946 LOGD("release bo %p", bo);
2947 tbm_bo_unref(tmp->bo);
2948 MMPLAYER_VIDEO_BO_UNLOCK(player);
2949 MMPLAYER_VIDEO_BO_SIGNAL(player);
2954 /* hw codec is running or the list was reset for DRC. */
2955 LOGW("there is no bo list.");
2957 MMPLAYER_VIDEO_BO_UNLOCK(player);
2959 LOGW("failed to find bo %p", bo);
2964 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2969 MMPLAYER_RETURN_IF_FAIL(player);
2971 MMPLAYER_VIDEO_BO_LOCK(player);
2972 if (player->video_bo_list) {
2973 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2974 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2975 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2978 tbm_bo_unref(tmp->bo);
2982 g_list_free(player->video_bo_list);
2983 player->video_bo_list = NULL;
2985 player->video_bo_size = 0;
2986 MMPLAYER_VIDEO_BO_UNLOCK(player);
2993 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2996 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2997 gboolean ret = TRUE;
2999 /* check DRC, if it is, destroy the prev bo list to create again */
3000 if (player->video_bo_size != size) {
3001 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3002 __mmplayer_video_stream_destroy_bo_list(player);
3003 player->video_bo_size = size;
3006 MMPLAYER_VIDEO_BO_LOCK(player);
3008 if ((!player->video_bo_list) ||
3009 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3011 /* create bo list */
3013 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3015 if (player->video_bo_list) {
3016 /* if bo list did not created all, try it again. */
3017 idx = g_list_length(player->video_bo_list);
3018 LOGD("bo list exist(len: %d)", idx);
3021 for (; idx < player->ini.num_of_video_bo; idx++) {
3022 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3024 LOGE("Fail to alloc bo_info.");
3027 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3029 LOGE("Fail to tbm_bo_alloc.");
3033 bo_info->used = FALSE;
3034 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3037 /* update video num buffers */
3038 player->video_num_buffers = idx;
3039 if (idx == player->ini.num_of_video_bo)
3040 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3043 MMPLAYER_VIDEO_BO_UNLOCK(player);
3047 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3051 /* get bo from list*/
3052 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3053 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3054 if (tmp && (tmp->used == FALSE)) {
3055 LOGD("found bo %p to use", tmp->bo);
3057 MMPLAYER_VIDEO_BO_UNLOCK(player);
3058 return tbm_bo_ref(tmp->bo);
3062 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3063 MMPLAYER_VIDEO_BO_UNLOCK(player);
3067 if (player->ini.video_bo_timeout <= 0) {
3068 MMPLAYER_VIDEO_BO_WAIT(player);
3070 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3071 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3078 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3080 mm_player_t* player = (mm_player_t*)data;
3082 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3084 /* send prerolled pkt */
3085 player->video_stream_prerolled = FALSE;
3087 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3089 /* not to send prerolled pkt again */
3090 player->video_stream_prerolled = TRUE;
3094 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3096 mm_player_t* player = (mm_player_t*)data;
3097 MMPlayerVideoStreamDataType *stream = NULL;
3098 GstMemory *mem = NULL;
3101 MMPLAYER_RETURN_IF_FAIL(player);
3102 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3104 if (player->video_stream_prerolled) {
3105 player->video_stream_prerolled = FALSE;
3106 LOGD("skip the prerolled pkt not to send it again");
3110 /* clear stream data structure */
3111 stream = __mmplayer_create_stream_from_pad(pad);
3113 LOGE("failed to alloc stream");
3117 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3119 /* set size and timestamp */
3120 mem = gst_buffer_peek_memory(buffer, 0);
3121 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3122 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3124 /* check zero-copy */
3125 if (player->set_mode.video_zc &&
3126 player->set_mode.media_packet_video_stream &&
3127 gst_is_tizen_memory(mem)) {
3128 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3129 stream->internal_buffer = gst_buffer_ref(buffer);
3130 } else { /* sw codec */
3131 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3134 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3138 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3139 LOGE("failed to send video stream data.");
3146 LOGE("release video stream resource.");
3147 if (gst_is_tizen_memory(mem)) {
3149 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3151 tbm_bo_unref(stream->bo[i]);
3154 /* unref gst buffer */
3155 if (stream->internal_buffer)
3156 gst_buffer_unref(stream->internal_buffer);
3159 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3166 __mmplayer_gst_set_video360_property(mm_player_t *player)
3168 MMPlayerGstElement *videobin = NULL;
3171 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3173 videobin = player->pipeline->videobin;
3175 /* Set spatial media metadata and/or user settings to the element.
3177 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3178 "projection-type", player->video360_metadata.projection_type, NULL);
3180 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3181 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3183 if (player->video360_metadata.full_pano_width_pixels &&
3184 player->video360_metadata.full_pano_height_pixels &&
3185 player->video360_metadata.cropped_area_image_width &&
3186 player->video360_metadata.cropped_area_image_height) {
3187 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3188 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3189 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3190 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3191 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3192 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3193 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3197 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3198 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3199 "horizontal-fov", player->video360_horizontal_fov,
3200 "vertical-fov", player->video360_vertical_fov, NULL);
3203 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3204 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3205 "zoom", 1.0f / player->video360_zoom, NULL);
3208 if (player->video360_yaw_radians <= M_PI &&
3209 player->video360_yaw_radians >= -M_PI &&
3210 player->video360_pitch_radians <= M_PI_2 &&
3211 player->video360_pitch_radians >= -M_PI_2) {
3212 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3213 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3214 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3215 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3216 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3217 "pose-yaw", player->video360_metadata.init_view_heading,
3218 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3221 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3222 "passthrough", !player->is_video360_enabled, NULL);
3229 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3231 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3232 GList *element_bucket = NULL;
3235 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3237 /* create video360 filter */
3238 if (player->is_360_feature_enabled && player->is_content_spherical) {
3239 LOGD("create video360 element");
3240 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3241 __mmplayer_gst_set_video360_property(player);
3245 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3246 LOGD("skip creating the videoconv and rotator");
3247 return MM_ERROR_NONE;
3250 /* in case of sw codec & overlay surface type, except 360 playback.
3251 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3252 LOGD("create video converter: %s", video_csc);
3253 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3255 /* set video rotator */
3256 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3259 *bucket = element_bucket;
3261 return MM_ERROR_NONE;
3263 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3264 g_list_free(element_bucket);
3268 return MM_ERROR_PLAYER_INTERNAL;
3272 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3274 gchar *factory_name = NULL;
3276 switch (surface_type) {
3277 case MM_DISPLAY_SURFACE_OVERLAY:
3278 if (strlen(player->ini.videosink_element_overlay) > 0)
3279 factory_name = player->ini.videosink_element_overlay;
3281 case MM_DISPLAY_SURFACE_REMOTE:
3282 if (strlen(player->ini.videosink_element_fake) > 0)
3283 factory_name = player->ini.videosink_element_fake;
3285 case MM_DISPLAY_SURFACE_NULL:
3286 LOGE("null surface type have to be handled in _decode_pad_added()");
3289 LOGE("unidentified surface type");
3293 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3294 return factory_name;
3298 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3300 gchar *factory_name = NULL;
3301 MMPlayerGstElement *videobin = NULL;
3305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3307 videobin = player->pipeline->videobin;
3308 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3310 attrs = MMPLAYER_GET_ATTRS(player);
3312 LOGE("cannot get content attribute");
3313 return MM_ERROR_PLAYER_INTERNAL;
3316 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_REMOTE) {
3319 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3320 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3321 LOGD("OVERLAY: selected videosink is %s", factory_name);
3324 /* support shard memory with S/W codec on HawkP */
3325 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3326 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3327 "use-tbm", use_tbm, NULL);
3331 LOGE("REMOTE : add data probe at videosink");
3332 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3333 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3336 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3338 LOGD("disable last-sample");
3339 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3342 if (player->set_mode.media_packet_video_stream) {
3344 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3345 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE))
3346 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3348 __mmplayer_add_signal_connection(player,
3349 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3350 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3352 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3355 __mmplayer_add_signal_connection(player,
3356 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3357 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3359 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3364 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3365 return MM_ERROR_PLAYER_INTERNAL;
3367 if (videobin[MMPLAYER_V_SINK].gst) {
3368 GstPad *sink_pad = NULL;
3369 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3371 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3372 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3373 gst_object_unref(GST_OBJECT(sink_pad));
3375 LOGE("failed to get sink pad from videosink");
3379 return MM_ERROR_NONE;
3384 * - video overlay surface(arm/x86) : tizenwlsink
3387 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3390 GList *element_bucket = NULL;
3391 MMPlayerGstElement *first_element = NULL;
3392 MMPlayerGstElement *videobin = NULL;
3393 gchar *videosink_factory_name = NULL;
3396 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3399 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3401 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3403 player->pipeline->videobin = videobin;
3406 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3407 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3408 if (!videobin[MMPLAYER_V_BIN].gst) {
3409 LOGE("failed to create videobin");
3413 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3416 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3417 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3419 /* additional setting for sink plug-in */
3420 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3421 LOGE("failed to set video property");
3425 /* store it as it's sink element */
3426 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3428 /* adding created elements to bin */
3429 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3430 LOGE("failed to add elements");
3434 /* Linking elements in the bucket by added order */
3435 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3436 LOGE("failed to link elements");
3440 /* get first element's sinkpad for creating ghostpad */
3441 first_element = (MMPlayerGstElement *)element_bucket->data;
3442 if (!first_element) {
3443 LOGE("failed to get first element from bucket");
3447 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3449 LOGE("failed to get pad from first element");
3453 /* create ghostpad */
3454 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3455 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3456 LOGE("failed to add ghostpad to videobin");
3459 gst_object_unref(pad);
3461 /* done. free allocated variables */
3462 g_list_free(element_bucket);
3466 return MM_ERROR_NONE;
3469 LOGE("ERROR : releasing videobin");
3470 g_list_free(element_bucket);
3473 gst_object_unref(GST_OBJECT(pad));
3475 /* release videobin with it's childs */
3476 if (videobin[MMPLAYER_V_BIN].gst)
3477 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3479 MMPLAYER_FREEIF(videobin);
3480 player->pipeline->videobin = NULL;
3482 return MM_ERROR_PLAYER_INTERNAL;
3485 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3487 GList *element_bucket = NULL;
3488 MMPlayerGstElement *textbin = player->pipeline->textbin;
3490 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3491 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3492 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3493 "signal-handoffs", FALSE,
3496 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3497 __mmplayer_add_signal_connection(player,
3498 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3499 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3501 G_CALLBACK(__mmplayer_update_subtitle),
3504 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3505 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3507 if (!player->play_subtitle) {
3508 LOGD("add textbin sink as sink element of whole pipeline.\n");
3509 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3512 /* adding created elements to bin */
3513 LOGD("adding created elements to bin\n");
3514 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3515 LOGE("failed to add elements\n");
3519 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3520 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3521 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3523 /* linking elements in the bucket by added order. */
3524 LOGD("Linking elements in the bucket by added order.\n");
3525 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3526 LOGE("failed to link elements\n");
3530 /* done. free allocated variables */
3531 g_list_free(element_bucket);
3533 if (textbin[MMPLAYER_T_QUEUE].gst) {
3535 GstPad *ghostpad = NULL;
3537 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3539 LOGE("failed to get sink pad of text queue");
3543 ghostpad = gst_ghost_pad_new("text_sink", pad);
3544 gst_object_unref(pad);
3547 LOGE("failed to create ghostpad of textbin\n");
3551 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3552 LOGE("failed to add ghostpad to textbin\n");
3553 gst_object_unref(ghostpad);
3558 return MM_ERROR_NONE;
3561 g_list_free(element_bucket);
3563 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3564 LOGE("remove textbin sink from sink list");
3565 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3568 /* release element at __mmplayer_gst_create_text_sink_bin */
3569 return MM_ERROR_PLAYER_INTERNAL;
3572 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3574 MMPlayerGstElement *textbin = NULL;
3575 GList *element_bucket = NULL;
3576 int surface_type = 0;
3581 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3584 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3586 LOGE("failed to allocate memory for textbin\n");
3587 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3591 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3592 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3593 if (!textbin[MMPLAYER_T_BIN].gst) {
3594 LOGE("failed to create textbin\n");
3599 player->pipeline->textbin = textbin;
3602 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3603 LOGD("surface type for subtitle : %d", surface_type);
3604 switch (surface_type) {
3605 case MM_DISPLAY_SURFACE_OVERLAY:
3606 case MM_DISPLAY_SURFACE_NULL:
3607 case MM_DISPLAY_SURFACE_REMOTE:
3608 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3609 LOGE("failed to make plain text elements\n");
3620 return MM_ERROR_NONE;
3624 LOGD("ERROR : releasing textbin\n");
3626 g_list_free(element_bucket);
3628 /* release signal */
3629 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3631 /* release element which are not added to bin */
3632 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3633 /* NOTE : skip bin */
3634 if (textbin[i].gst) {
3635 GstObject* parent = NULL;
3636 parent = gst_element_get_parent(textbin[i].gst);
3639 gst_object_unref(GST_OBJECT(textbin[i].gst));
3640 textbin[i].gst = NULL;
3642 gst_object_unref(GST_OBJECT(parent));
3647 /* release textbin with it's childs */
3648 if (textbin[MMPLAYER_T_BIN].gst)
3649 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3651 MMPLAYER_FREEIF(player->pipeline->textbin);
3652 player->pipeline->textbin = NULL;
3655 return MM_ERROR_PLAYER_INTERNAL;
3660 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3662 MMPlayerGstElement* mainbin = NULL;
3663 MMPlayerGstElement* textbin = NULL;
3664 MMHandleType attrs = 0;
3665 GstElement *subsrc = NULL;
3666 GstElement *subparse = NULL;
3667 gchar *subtitle_uri = NULL;
3668 const gchar *charset = NULL;
3674 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3676 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3678 mainbin = player->pipeline->mainbin;
3680 attrs = MMPLAYER_GET_ATTRS(player);
3682 LOGE("cannot get content attribute\n");
3683 return MM_ERROR_PLAYER_INTERNAL;
3686 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3687 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3688 LOGE("subtitle uri is not proper filepath.\n");
3689 return MM_ERROR_PLAYER_INVALID_URI;
3692 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3693 LOGE("failed to get storage info of subtitle path");
3694 return MM_ERROR_PLAYER_INVALID_URI;
3697 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3699 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3700 player->subtitle_language_list = NULL;
3701 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3703 /* create the subtitle source */
3704 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3706 LOGE("failed to create filesrc element\n");
3709 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3711 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3712 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3714 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3715 LOGW("failed to add queue\n");
3716 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3717 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3718 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3723 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3725 LOGE("failed to create subparse element\n");
3729 charset = util_get_charset(subtitle_uri);
3731 LOGD("detected charset is %s\n", charset);
3732 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3735 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3736 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3738 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3739 LOGW("failed to add subparse\n");
3740 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3741 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3742 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3746 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3747 LOGW("failed to link subsrc and subparse\n");
3751 player->play_subtitle = TRUE;
3752 player->adjust_subtitle_pos = 0;
3754 LOGD("play subtitle using subtitle file\n");
3756 if (player->pipeline->textbin == NULL) {
3757 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3758 LOGE("failed to create text sink bin. continuing without text\n");
3762 textbin = player->pipeline->textbin;
3764 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3765 LOGW("failed to add textbin\n");
3767 /* release signal */
3768 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3770 /* release textbin with it's childs */
3771 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3772 MMPLAYER_FREEIF(player->pipeline->textbin);
3773 player->pipeline->textbin = textbin = NULL;
3777 LOGD("link text input selector and textbin ghost pad");
3779 player->textsink_linked = 1;
3780 player->external_text_idx = 0;
3781 LOGI("player->textsink_linked set to 1\n");
3783 textbin = player->pipeline->textbin;
3784 LOGD("text bin has been created. reuse it.");
3785 player->external_text_idx = 1;
3788 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3789 LOGW("failed to link subparse and textbin\n");
3793 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3795 LOGE("failed to get sink pad from textsink to probe data");
3799 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3800 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3802 gst_object_unref(pad);
3805 /* create dot. for debugging */
3806 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3809 return MM_ERROR_NONE;
3812 /* release text pipeline resource */
3813 player->textsink_linked = 0;
3815 /* release signal */
3816 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3818 if (player->pipeline->textbin) {
3819 LOGE("remove textbin");
3821 /* release textbin with it's childs */
3822 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3823 MMPLAYER_FREEIF(player->pipeline->textbin);
3824 player->pipeline->textbin = NULL;
3828 /* release subtitle elem */
3829 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3830 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3832 return MM_ERROR_PLAYER_INTERNAL;
3836 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3838 mm_player_t* player = (mm_player_t*) data;
3839 MMMessageParamType msg = {0, };
3840 GstClockTime duration = 0;
3841 gpointer text = NULL;
3842 guint text_size = 0;
3843 gboolean ret = TRUE;
3844 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3848 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3849 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3851 if (player->is_subtitle_force_drop) {
3852 LOGW("subtitle is dropped forcedly.");
3856 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3857 text = mapinfo.data;
3858 text_size = mapinfo.size;
3859 duration = GST_BUFFER_DURATION(buffer);
3861 if (player->set_mode.subtitle_off) {
3862 LOGD("subtitle is OFF.\n");
3866 if (!text || (text_size == 0)) {
3867 LOGD("There is no subtitle to be displayed.\n");
3871 msg.data = (void *) text;
3872 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3874 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3876 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3877 gst_buffer_unmap(buffer, &mapinfo);
3884 static GstPadProbeReturn
3885 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3887 mm_player_t *player = (mm_player_t *) u_data;
3888 GstClockTime cur_timestamp = 0;
3889 gint64 adjusted_timestamp = 0;
3890 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3892 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3894 if (player->set_mode.subtitle_off) {
3895 LOGD("subtitle is OFF.\n");
3899 if (player->adjust_subtitle_pos == 0) {
3900 LOGD("nothing to do");
3904 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3905 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3907 if (adjusted_timestamp < 0) {
3908 LOGD("adjusted_timestamp under zero");
3913 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3914 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3915 GST_TIME_ARGS(cur_timestamp),
3916 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3918 return GST_PAD_PROBE_OK;
3920 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3924 /* check player and subtitlebin are created */
3925 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3926 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3928 if (position == 0) {
3929 LOGD("nothing to do\n");
3931 return MM_ERROR_NONE;
3935 case MM_PLAYER_POS_FORMAT_TIME:
3937 /* check current postion */
3938 player->adjust_subtitle_pos = position;
3940 LOGD("save adjust_subtitle_pos in player") ;
3946 LOGW("invalid format.\n");
3948 return MM_ERROR_INVALID_ARGUMENT;
3954 return MM_ERROR_NONE;
3958 * This function is to create audio or video pipeline for playing.
3960 * @param player [in] handle of player
3962 * @return This function returns zero on success.
3967 __mmplayer_gst_create_pipeline(mm_player_t* player)
3969 int ret = MM_ERROR_NONE;
3970 MMPlayerGstElement *mainbin = NULL;
3971 MMHandleType attrs = 0;
3972 gint mode = MM_PLAYER_PD_MODE_NONE;
3975 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3977 /* get profile attribute */
3978 attrs = MMPLAYER_GET_ATTRS(player);
3980 LOGE("failed to get content attribute");
3984 /* create pipeline handles */
3985 if (player->pipeline) {
3986 LOGE("pipeline should be released before create new one");
3990 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3991 if (player->pipeline == NULL)
3994 /* create mainbin */
3995 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3996 if (mainbin == NULL)
3999 /* create pipeline */
4000 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4001 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4002 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4003 LOGE("failed to create pipeline");
4008 player->pipeline->mainbin = mainbin;
4011 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
4012 player->pd_mode = mode;
4014 /* create the source and decoder elements */
4015 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4016 ret = __mmplayer_gst_build_es_pipeline(player);
4017 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
4018 ret = __mmplayer_gst_build_pd_pipeline(player);
4020 ret = __mmplayer_gst_build_pipeline(player);
4023 if (ret != MM_ERROR_NONE) {
4024 LOGE("failed to create some elements");
4028 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4029 if (__mmplayer_check_subtitle(player)) {
4030 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
4031 LOGE("failed to create text pipeline");
4035 ret = __mmplayer_gst_add_bus_watch(player);
4036 if (ret != MM_ERROR_NONE) {
4037 LOGE("failed to add bus watch");
4042 return MM_ERROR_NONE;
4045 __mmplayer_gst_destroy_pipeline(player);
4046 return MM_ERROR_PLAYER_INTERNAL;
4050 __mmplayer_reset_gapless_state(mm_player_t* player)
4053 MMPLAYER_RETURN_IF_FAIL(player
4055 && player->pipeline->audiobin
4056 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4058 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4065 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4068 int ret = MM_ERROR_NONE;
4072 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4074 /* cleanup stuffs */
4075 MMPLAYER_FREEIF(player->type);
4076 player->no_more_pad = FALSE;
4077 player->num_dynamic_pad = 0;
4078 player->demux_pad_index = 0;
4080 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4081 player->subtitle_language_list = NULL;
4082 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4084 __mmplayer_reset_gapless_state(player);
4086 if (player->streamer) {
4087 __mm_player_streaming_deinitialize(player->streamer);
4088 __mm_player_streaming_destroy(player->streamer);
4089 player->streamer = NULL;
4092 /* cleanup unlinked mime type */
4093 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4094 MMPLAYER_FREEIF(player->unlinked_video_mime);
4095 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4097 /* cleanup running stuffs */
4098 __mmplayer_cancel_eos_timer(player);
4100 /* cleanup gst stuffs */
4101 if (player->pipeline) {
4102 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4103 GstTagList* tag_list = player->pipeline->tag_list;
4105 /* first we need to disconnect all signal hander */
4106 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4109 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4110 MMPlayerGstElement* videobin = player->pipeline->videobin;
4111 MMPlayerGstElement* textbin = player->pipeline->textbin;
4112 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4113 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4114 gst_object_unref(bus);
4116 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4117 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4118 if (ret != MM_ERROR_NONE) {
4119 LOGE("fail to change state to NULL\n");
4120 return MM_ERROR_PLAYER_INTERNAL;
4123 LOGW("succeeded in changing state to NULL\n");
4125 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4128 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4129 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4131 /* free avsysaudiosink
4132 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4133 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4135 MMPLAYER_FREEIF(audiobin);
4136 MMPLAYER_FREEIF(videobin);
4137 MMPLAYER_FREEIF(textbin);
4138 MMPLAYER_FREEIF(mainbin);
4142 gst_tag_list_free(tag_list);
4144 MMPLAYER_FREEIF(player->pipeline);
4146 MMPLAYER_FREEIF(player->album_art);
4148 if (player->v_stream_caps) {
4149 gst_caps_unref(player->v_stream_caps);
4150 player->v_stream_caps = NULL;
4152 if (player->a_stream_caps) {
4153 gst_caps_unref(player->a_stream_caps);
4154 player->a_stream_caps = NULL;
4157 if (player->s_stream_caps) {
4158 gst_caps_unref(player->s_stream_caps);
4159 player->s_stream_caps = NULL;
4161 __mmplayer_track_destroy(player);
4163 if (player->sink_elements)
4164 g_list_free(player->sink_elements);
4165 player->sink_elements = NULL;
4167 if (player->bufmgr) {
4168 tbm_bufmgr_deinit(player->bufmgr);
4169 player->bufmgr = NULL;
4172 LOGW("finished destroy pipeline\n");
4179 static int __mmplayer_gst_realize(mm_player_t* player)
4182 int ret = MM_ERROR_NONE;
4186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4188 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4190 ret = __mmplayer_gst_create_pipeline(player);
4192 LOGE("failed to create pipeline\n");
4196 /* set pipeline state to READY */
4197 /* NOTE : state change to READY must be performed sync. */
4198 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4199 ret = __mmplayer_gst_set_state(player,
4200 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4202 if (ret != MM_ERROR_NONE) {
4203 /* return error if failed to set state */
4204 LOGE("failed to set READY state");
4208 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4210 /* create dot before error-return. for debugging */
4211 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4218 static int __mmplayer_gst_unrealize(mm_player_t* player)
4220 int ret = MM_ERROR_NONE;
4224 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4226 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4227 MMPLAYER_PRINT_STATE(player);
4229 /* release miscellaneous information */
4230 __mmplayer_release_misc(player);
4232 /* destroy pipeline */
4233 ret = __mmplayer_gst_destroy_pipeline(player);
4234 if (ret != MM_ERROR_NONE) {
4235 LOGE("failed to destory pipeline\n");
4239 /* release miscellaneous information.
4240 these info needs to be released after pipeline is destroyed. */
4241 __mmplayer_release_misc_post(player);
4243 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4251 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4256 LOGW("set_message_callback is called with invalid player handle\n");
4257 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4260 player->msg_cb = callback;
4261 player->msg_cb_param = user_param;
4263 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4267 return MM_ERROR_NONE;
4270 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4272 int ret = MM_ERROR_NONE;
4277 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
4278 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
4279 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
4281 memset(data, 0, sizeof(MMPlayerParseProfile));
4283 if (strstr(uri, "es_buff://")) {
4284 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4285 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4286 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4287 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4289 tmp = g_ascii_strdown(uri, strlen(uri));
4290 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4291 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4293 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4295 } else if (strstr(uri, "mms://")) {
4296 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4297 } else if ((path = strstr(uri, "mem://"))) {
4298 ret = __mmplayer_set_mem_uri(data, path, param);
4300 ret = __mmplayer_set_file_uri(data, uri);
4303 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4304 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4305 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4306 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4308 /* dump parse result */
4309 SECURE_LOGW("incoming uri : %s\n", uri);
4310 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4311 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4319 __mmplayer_can_do_interrupt(mm_player_t *player)
4321 if (!player || !player->pipeline || !player->attrs) {
4322 LOGW("not initialized");
4326 if (player->audio_stream_render_cb) {
4327 LOGW("not support in pcm extraction mode");
4331 /* check if seeking */
4332 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4333 MMMessageParamType msg_param;
4334 memset(&msg_param, 0, sizeof(MMMessageParamType));
4335 msg_param.code = MM_ERROR_PLAYER_SEEK;
4336 player->seek_state = MMPLAYER_SEEK_NONE;
4337 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4341 /* check other thread */
4342 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4343 LOGW("locked already, cmd state : %d", player->cmd);
4345 /* check application command */
4346 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4347 LOGW("playing.. should wait cmd lock then, will be interrupted");
4349 /* lock will be released at mrp_resource_release_cb() */
4350 MMPLAYER_CMD_LOCK(player);
4353 LOGW("nothing to do");
4356 LOGW("can interrupt immediately");
4360 FAILED: /* with CMD UNLOCKED */
4363 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4368 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4371 mm_player_t *player = NULL;
4375 if (user_data == NULL) {
4376 LOGE("- user_data is null\n");
4379 player = (mm_player_t *)user_data;
4381 /* do something to release resource here.
4382 * player stop and interrupt forwarding */
4383 if (!__mmplayer_can_do_interrupt(player)) {
4384 LOGW("no need to interrupt, so leave");
4386 MMMessageParamType msg = {0, };
4389 player->interrupted_by_resource = TRUE;
4391 /* get last play position */
4392 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4393 LOGW("failed to get play position.");
4395 msg.union_type = MM_MSG_UNION_TIME;
4396 msg.time.elapsed = pos;
4397 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4399 LOGD("video resource conflict so, resource will be freed by unrealizing");
4400 if (_mmplayer_unrealize((MMHandleType)player))
4401 LOGW("failed to unrealize");
4403 /* lock is called in __mmplayer_can_do_interrupt() */
4404 MMPLAYER_CMD_UNLOCK(player);
4407 if (res == player->video_overlay_resource)
4408 player->video_overlay_resource = FALSE;
4410 player->video_decoder_resource = FALSE;
4418 __mmplayer_initialize_video_roi(mm_player_t *player)
4420 player->video_roi.scale_x = 0.0;
4421 player->video_roi.scale_y = 0.0;
4422 player->video_roi.scale_width = 1.0;
4423 player->video_roi.scale_height = 1.0;
4427 _mmplayer_create_player(MMHandleType handle)
4429 int ret = MM_ERROR_PLAYER_INTERNAL;
4430 bool enabled = false;
4432 mm_player_t* player = MM_PLAYER_CAST(handle);
4436 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4438 /* initialize player state */
4439 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4440 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4441 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4442 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4444 /* check current state */
4445 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4447 /* construct attributes */
4448 player->attrs = _mmplayer_construct_attribute(handle);
4450 if (!player->attrs) {
4451 LOGE("Failed to construct attributes\n");
4455 /* initialize gstreamer with configured parameter */
4456 if (!__mmplayer_init_gstreamer(player)) {
4457 LOGE("Initializing gstreamer failed\n");
4458 _mmplayer_deconstruct_attribute(handle);
4462 /* create lock. note that g_tread_init() has already called in gst_init() */
4463 g_mutex_init(&player->fsink_lock);
4465 /* create update tag lock */
4466 g_mutex_init(&player->update_tag_lock);
4468 /* create gapless play mutex */
4469 g_mutex_init(&player->gapless_play_thread_mutex);
4471 /* create gapless play cond */
4472 g_cond_init(&player->gapless_play_thread_cond);
4474 /* create gapless play thread */
4475 player->gapless_play_thread =
4476 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4477 if (!player->gapless_play_thread) {
4478 LOGE("failed to create gapless play thread");
4479 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4480 g_mutex_clear(&player->gapless_play_thread_mutex);
4481 g_cond_clear(&player->gapless_play_thread_cond);
4485 player->bus_msg_q = g_queue_new();
4486 if (!player->bus_msg_q) {
4487 LOGE("failed to create queue for bus_msg");
4488 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4492 ret = _mmplayer_initialize_video_capture(player);
4493 if (ret != MM_ERROR_NONE) {
4494 LOGE("failed to initialize video capture\n");
4498 /* initialize resource manager */
4499 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4500 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4501 &player->resource_manager)) {
4502 LOGE("failed to initialize resource manager\n");
4503 ret = MM_ERROR_PLAYER_INTERNAL;
4507 if (MMPLAYER_IS_HTTP_PD(player)) {
4508 player->pd_downloader = NULL;
4509 player->pd_file_save_path = NULL;
4512 /* create video bo lock and cond */
4513 g_mutex_init(&player->video_bo_mutex);
4514 g_cond_init(&player->video_bo_cond);
4516 /* create media stream callback mutex */
4517 g_mutex_init(&player->media_stream_cb_lock);
4519 /* create subtitle info lock and cond */
4520 g_mutex_init(&player->subtitle_info_mutex);
4521 g_cond_init(&player->subtitle_info_cond);
4523 player->streaming_type = STREAMING_SERVICE_NONE;
4525 /* give default value of audio effect setting */
4526 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4527 player->sound.rg_enable = false;
4528 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4530 player->play_subtitle = FALSE;
4531 player->has_closed_caption = FALSE;
4532 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4533 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4534 player->pending_resume = FALSE;
4535 if (player->ini.dump_element_keyword[0][0] == '\0')
4536 player->ini.set_dump_element_flag = FALSE;
4538 player->ini.set_dump_element_flag = TRUE;
4540 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4541 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4542 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4544 /* Set video360 settings to their defaults for just-created player.
4547 player->is_360_feature_enabled = FALSE;
4548 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4549 LOGI("spherical feature info: %d", enabled);
4551 player->is_360_feature_enabled = TRUE;
4553 LOGE("failed to get spherical feature info");
4556 player->is_content_spherical = FALSE;
4557 player->is_video360_enabled = TRUE;
4558 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4559 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4560 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4561 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4562 player->video360_zoom = 1.0f;
4563 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4564 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4566 __mmplayer_initialize_video_roi(player);
4568 /* set player state to null */
4569 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4570 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4572 return MM_ERROR_NONE;
4576 g_mutex_clear(&player->fsink_lock);
4578 /* free update tag lock */
4579 g_mutex_clear(&player->update_tag_lock);
4581 g_queue_free(player->bus_msg_q);
4583 /* free gapless play thread */
4584 if (player->gapless_play_thread) {
4585 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4586 player->gapless_play_thread_exit = TRUE;
4587 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4588 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4590 g_thread_join(player->gapless_play_thread);
4591 player->gapless_play_thread = NULL;
4593 g_mutex_clear(&player->gapless_play_thread_mutex);
4594 g_cond_clear(&player->gapless_play_thread_cond);
4597 /* release attributes */
4598 _mmplayer_deconstruct_attribute(handle);
4606 __mmplayer_init_gstreamer(mm_player_t* player)
4608 static gboolean initialized = FALSE;
4609 static const int max_argc = 50;
4611 gchar** argv = NULL;
4612 gchar** argv2 = NULL;
4618 LOGD("gstreamer already initialized.\n");
4623 argc = malloc(sizeof(int));
4624 argv = malloc(sizeof(gchar*) * max_argc);
4625 argv2 = malloc(sizeof(gchar*) * max_argc);
4627 if (!argc || !argv || !argv2)
4630 memset(argv, 0, sizeof(gchar*) * max_argc);
4631 memset(argv2, 0, sizeof(gchar*) * max_argc);
4635 argv[0] = g_strdup("mmplayer");
4638 for (i = 0; i < 5; i++) {
4639 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4640 if (strlen(player->ini.gst_param[i]) > 0) {
4641 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4646 /* we would not do fork for scanning plugins */
4647 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4650 /* check disable registry scan */
4651 if (player->ini.skip_rescan) {
4652 argv[*argc] = g_strdup("--gst-disable-registry-update");
4656 /* check disable segtrap */
4657 if (player->ini.disable_segtrap) {
4658 argv[*argc] = g_strdup("--gst-disable-segtrap");
4662 LOGD("initializing gstreamer with following parameter\n");
4663 LOGD("argc : %d\n", *argc);
4666 for (i = 0; i < arg_count; i++) {
4668 LOGD("argv[%d] : %s\n", i, argv2[i]);
4671 /* initializing gstreamer */
4672 if (!gst_init_check(argc, &argv, &err)) {
4673 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4680 for (i = 0; i < arg_count; i++) {
4681 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4682 MMPLAYER_FREEIF(argv2[i]);
4685 MMPLAYER_FREEIF(argv);
4686 MMPLAYER_FREEIF(argv2);
4687 MMPLAYER_FREEIF(argc);
4697 for (i = 0; i < arg_count; i++) {
4698 LOGD("free[%d] : %s\n", i, argv2[i]);
4699 MMPLAYER_FREEIF(argv2[i]);
4702 MMPLAYER_FREEIF(argv);
4703 MMPLAYER_FREEIF(argv2);
4704 MMPLAYER_FREEIF(argc);
4710 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4712 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4714 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4715 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4716 MMPLAYER_FREEIF(player->pd_file_save_path);
4719 return MM_ERROR_NONE;
4723 __mmplayer_check_async_state_transition(mm_player_t* player)
4725 GstState element_state = GST_STATE_VOID_PENDING;
4726 GstState element_pending_state = GST_STATE_VOID_PENDING;
4727 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4728 GstElement * element = NULL;
4729 gboolean async = FALSE;
4731 /* check player handle */
4732 MMPLAYER_RETURN_IF_FAIL(player &&
4734 player->pipeline->mainbin &&
4735 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4738 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4740 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4741 LOGD("don't need to check the pipeline state");
4745 MMPLAYER_PRINT_STATE(player);
4747 /* wait for state transition */
4748 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4749 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4751 if (ret == GST_STATE_CHANGE_FAILURE) {
4752 LOGE(" [%s] state : %s pending : %s \n",
4753 GST_ELEMENT_NAME(element),
4754 gst_element_state_get_name(element_state),
4755 gst_element_state_get_name(element_pending_state));
4757 /* dump state of all element */
4758 __mmplayer_dump_pipeline_state(player);
4763 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4768 _mmplayer_destroy(MMHandleType handle)
4770 mm_player_t* player = MM_PLAYER_CAST(handle);
4774 /* check player handle */
4775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4777 /* destroy can called at anytime */
4778 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4780 /* check async state transition */
4781 __mmplayer_check_async_state_transition(player);
4783 __mmplayer_destroy_streaming_ext(player);
4785 /* release gapless play thread */
4786 if (player->gapless_play_thread) {
4787 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4788 player->gapless_play_thread_exit = TRUE;
4789 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4790 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4792 LOGD("waitting for gapless play thread exit\n");
4793 g_thread_join(player->gapless_play_thread);
4794 g_mutex_clear(&player->gapless_play_thread_mutex);
4795 g_cond_clear(&player->gapless_play_thread_cond);
4796 LOGD("gapless play thread released\n");
4799 _mmplayer_release_video_capture(player);
4801 /* de-initialize resource manager */
4802 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4803 player->resource_manager))
4804 LOGE("failed to deinitialize resource manager\n");
4806 /* release pipeline */
4807 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4808 LOGE("failed to destory pipeline\n");
4809 return MM_ERROR_PLAYER_INTERNAL;
4812 g_queue_free(player->bus_msg_q);
4814 /* release subtitle info lock and cond */
4815 g_mutex_clear(&player->subtitle_info_mutex);
4816 g_cond_clear(&player->subtitle_info_cond);
4818 __mmplayer_release_dump_list(player->dump_list);
4820 /* release miscellaneous information */
4821 __mmplayer_release_misc(player);
4823 /* release miscellaneous information.
4824 these info needs to be released after pipeline is destroyed. */
4825 __mmplayer_release_misc_post(player);
4827 /* release attributes */
4828 _mmplayer_deconstruct_attribute(handle);
4831 g_mutex_clear(&player->fsink_lock);
4834 g_mutex_clear(&player->update_tag_lock);
4836 /* release video bo lock and cond */
4837 g_mutex_clear(&player->video_bo_mutex);
4838 g_cond_clear(&player->video_bo_cond);
4840 /* release media stream callback lock */
4841 g_mutex_clear(&player->media_stream_cb_lock);
4845 return MM_ERROR_NONE;
4849 __mmplayer_realize_streaming_ext(mm_player_t* player)
4851 int ret = MM_ERROR_NONE;
4854 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4856 if (MMPLAYER_IS_HTTP_PD(player)) {
4857 gboolean bret = FALSE;
4859 player->pd_downloader = _mmplayer_create_pd_downloader();
4860 if (!player->pd_downloader) {
4861 LOGE("Unable to create PD Downloader...");
4862 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4865 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4867 if (FALSE == bret) {
4868 LOGE("Unable to create PD Downloader...");
4869 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
4878 _mmplayer_realize(MMHandleType hplayer)
4880 mm_player_t* player = (mm_player_t*)hplayer;
4883 MMHandleType attrs = 0;
4884 int ret = MM_ERROR_NONE;
4888 /* check player handle */
4889 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4891 /* check current state */
4892 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4894 attrs = MMPLAYER_GET_ATTRS(player);
4896 LOGE("fail to get attributes.\n");
4897 return MM_ERROR_PLAYER_INTERNAL;
4899 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4900 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4902 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4903 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4905 if (ret != MM_ERROR_NONE) {
4906 LOGE("failed to parse profile\n");
4911 if (uri && (strstr(uri, "es_buff://"))) {
4912 if (strstr(uri, "es_buff://push_mode"))
4913 player->es_player_push_mode = TRUE;
4915 player->es_player_push_mode = FALSE;
4918 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4919 LOGW("mms protocol is not supported format.\n");
4920 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4923 if (MMPLAYER_IS_HTTP_PD(player))
4924 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
4925 else if (MMPLAYER_IS_STREAMING(player))
4926 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4928 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4930 player->smooth_streaming = FALSE;
4931 player->videodec_linked = 0;
4932 player->audiodec_linked = 0;
4933 player->textsink_linked = 0;
4934 player->is_external_subtitle_present = FALSE;
4935 player->is_external_subtitle_added_now = FALSE;
4936 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4937 player->video360_metadata.is_spherical = -1;
4938 player->is_openal_plugin_used = FALSE;
4939 player->demux_pad_index = 0;
4940 player->subtitle_language_list = NULL;
4941 player->is_subtitle_force_drop = FALSE;
4942 player->last_multiwin_status = FALSE;
4944 __mmplayer_track_initialize(player);
4945 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4947 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4948 player->streamer = __mm_player_streaming_create();
4949 __mm_player_streaming_initialize(player->streamer);
4952 /* realize pipeline */
4953 ret = __mmplayer_gst_realize(player);
4954 if (ret != MM_ERROR_NONE)
4955 LOGE("fail to realize the player.\n");
4957 ret = __mmplayer_realize_streaming_ext(player);
4959 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4967 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
4970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4972 /* destroy can called at anytime */
4973 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
4974 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
4977 return MM_ERROR_NONE;
4981 _mmplayer_unrealize(MMHandleType hplayer)
4983 mm_player_t* player = (mm_player_t*)hplayer;
4984 int ret = MM_ERROR_NONE;
4988 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4990 MMPLAYER_CMD_UNLOCK(player);
4991 /* destroy the gst bus msg thread which is created during realize.
4992 this funct have to be called before getting cmd lock. */
4993 __mmplayer_bus_msg_thread_destroy(player);
4994 MMPLAYER_CMD_LOCK(player);
4996 /* check current state */
4997 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4999 /* check async state transition */
5000 __mmplayer_check_async_state_transition(player);
5002 __mmplayer_unrealize_streaming_ext(player);
5004 /* unrealize pipeline */
5005 ret = __mmplayer_gst_unrealize(player);
5007 /* set asm stop if success */
5008 if (MM_ERROR_NONE == ret) {
5009 if (!player->interrupted_by_resource) {
5010 if (player->video_decoder_resource != NULL) {
5011 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5012 player->video_decoder_resource);
5013 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5014 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
5016 player->video_decoder_resource = NULL;
5019 if (player->video_overlay_resource != NULL) {
5020 ret = mm_resource_manager_mark_for_release(player->resource_manager,
5021 player->video_overlay_resource);
5022 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5023 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
5025 player->video_overlay_resource = NULL;
5028 ret = mm_resource_manager_commit(player->resource_manager);
5029 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5030 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
5033 LOGE("failed and don't change asm state to stop");
5041 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5043 mm_player_t* player = (mm_player_t*)hplayer;
5045 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5047 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5051 _mmplayer_get_state(MMHandleType hplayer, int* state)
5053 mm_player_t *player = (mm_player_t*)hplayer;
5055 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5057 *state = MMPLAYER_CURRENT_STATE(player);
5059 return MM_ERROR_NONE;
5064 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5066 mm_player_t* player = (mm_player_t*) hplayer;
5067 GstElement* vol_element = NULL;
5072 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5074 LOGD("volume [L]=%f:[R]=%f\n",
5075 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5077 /* invalid factor range or not */
5078 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5079 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5080 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5081 return MM_ERROR_INVALID_ARGUMENT;
5085 /* not support to set other value into each channel */
5086 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5087 return MM_ERROR_INVALID_ARGUMENT;
5089 /* Save volume to handle. Currently the first array element will be saved. */
5090 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5092 /* check pipeline handle */
5093 if (!player->pipeline || !player->pipeline->audiobin) {
5094 LOGD("audiobin is not created yet\n");
5095 LOGD("but, current stored volume will be set when it's created.\n");
5097 /* NOTE : stored volume will be used in create_audiobin
5098 * returning MM_ERROR_NONE here makes application to able to
5099 * set volume at anytime.
5101 return MM_ERROR_NONE;
5104 /* setting volume to volume element */
5105 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5108 LOGD("volume is set [%f]\n", player->sound.volume);
5109 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5114 return MM_ERROR_NONE;
5119 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5121 mm_player_t* player = (mm_player_t*) hplayer;
5126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5127 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5129 /* returning stored volume */
5130 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5131 volume->level[i] = player->sound.volume;
5135 return MM_ERROR_NONE;
5139 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5141 mm_player_t* player = (mm_player_t*) hplayer;
5142 GstElement* vol_element = NULL;
5146 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5148 /* mute value shoud 0 or 1 */
5149 if (mute != 0 && mute != 1) {
5150 LOGE("bad mute value\n");
5152 /* FIXIT : definitly, we need _BAD_PARAM error code */
5153 return MM_ERROR_INVALID_ARGUMENT;
5156 player->sound.mute = mute;
5158 /* just hold mute value if pipeline is not ready */
5159 if (!player->pipeline || !player->pipeline->audiobin) {
5160 LOGD("pipeline is not ready. holding mute value\n");
5161 return MM_ERROR_NONE;
5164 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5166 /* NOTE : volume will only created when the bt is enabled */
5168 LOGD("mute : %d\n", mute);
5169 g_object_set(vol_element, "mute", mute, NULL);
5171 LOGD("volume elemnet is not created. using volume in audiosink\n");
5175 return MM_ERROR_NONE;
5179 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5181 mm_player_t* player = (mm_player_t*) hplayer;
5185 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5188 /* just hold mute value if pipeline is not ready */
5189 if (!player->pipeline || !player->pipeline->audiobin) {
5190 LOGD("pipeline is not ready. returning stored value\n");
5191 *pmute = player->sound.mute;
5192 return MM_ERROR_NONE;
5195 *pmute = player->sound.mute;
5199 return MM_ERROR_NONE;
5203 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5205 mm_player_t* player = (mm_player_t*) hplayer;
5209 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5211 player->video_stream_changed_cb = callback;
5212 player->video_stream_changed_cb_user_param = user_param;
5213 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5217 return MM_ERROR_NONE;
5221 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5223 mm_player_t* player = (mm_player_t*) hplayer;
5227 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5229 player->audio_stream_changed_cb = callback;
5230 player->audio_stream_changed_cb_user_param = user_param;
5231 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5235 return MM_ERROR_NONE;
5239 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5241 mm_player_t *player = (mm_player_t*) hplayer;
5245 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5247 player->audio_stream_render_cb = callback;
5248 player->audio_stream_cb_user_param = user_param;
5249 player->audio_stream_sink_sync = sync;
5250 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5254 return MM_ERROR_NONE;
5258 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5260 mm_player_t* player = (mm_player_t*) hplayer;
5264 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5266 if (callback && !player->bufmgr)
5267 player->bufmgr = tbm_bufmgr_init(-1);
5269 player->set_mode.media_packet_video_stream = (callback) ? TRUE : FALSE;
5270 player->video_stream_cb = callback;
5271 player->video_stream_cb_user_param = user_param;
5273 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5277 return MM_ERROR_NONE;
5281 __mmplayer_start_streaming_ext(mm_player_t *player)
5283 gint ret = MM_ERROR_NONE;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 if (MMPLAYER_IS_HTTP_PD(player)) {
5289 if (!player->pd_downloader) {
5290 ret = __mmplayer_realize_streaming_ext(player);
5292 if (ret != MM_ERROR_NONE) {
5293 LOGE("failed to realize streaming ext\n");
5298 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5299 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5301 LOGE("ERROR while starting PD...\n");
5302 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5304 ret = MM_ERROR_NONE;
5313 _mmplayer_start(MMHandleType hplayer)
5315 mm_player_t* player = (mm_player_t*) hplayer;
5316 gint ret = MM_ERROR_NONE;
5320 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5322 /* check current state */
5323 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5325 /* PD - start streaming */
5326 ret = __mmplayer_start_streaming_ext(player);
5327 if (ret != MM_ERROR_NONE) {
5328 LOGE("failed to start streaming ext 0x%X", ret);
5332 /* start pipeline */
5333 ret = __mmplayer_gst_start(player);
5334 if (ret != MM_ERROR_NONE)
5335 LOGE("failed to start player.\n");
5337 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5338 LOGD("force playing start even during buffering");
5339 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5347 /* NOTE: post "not supported codec message" to application
5348 * when one codec is not found during AUTOPLUGGING in MSL.
5349 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5350 * And, if any codec is not found, don't send message here.
5351 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5354 __mmplayer_handle_missed_plugin(mm_player_t* player)
5356 MMMessageParamType msg_param;
5357 memset(&msg_param, 0, sizeof(MMMessageParamType));
5358 gboolean post_msg_direct = FALSE;
5362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5364 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5365 player->not_supported_codec, player->can_support_codec);
5367 if (player->not_found_demuxer) {
5368 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5369 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5371 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5372 MMPLAYER_FREEIF(msg_param.data);
5374 return MM_ERROR_NONE;
5377 if (player->not_supported_codec) {
5378 if (player->can_support_codec) {
5379 // There is one codec to play
5380 post_msg_direct = TRUE;
5382 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5383 post_msg_direct = TRUE;
5386 if (post_msg_direct) {
5387 MMMessageParamType msg_param;
5388 memset(&msg_param, 0, sizeof(MMMessageParamType));
5390 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5391 LOGW("not found AUDIO codec, posting error code to application.\n");
5393 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5394 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5395 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5396 LOGW("not found VIDEO codec, posting error code to application.\n");
5398 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5399 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5402 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5404 MMPLAYER_FREEIF(msg_param.data);
5406 return MM_ERROR_NONE;
5408 // no any supported codec case
5409 LOGW("not found any codec, posting error code to application.\n");
5411 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5412 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5413 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5415 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5416 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5419 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5421 MMPLAYER_FREEIF(msg_param.data);
5427 return MM_ERROR_NONE;
5430 static void __mmplayer_check_pipeline(mm_player_t* player)
5432 GstState element_state = GST_STATE_VOID_PENDING;
5433 GstState element_pending_state = GST_STATE_VOID_PENDING;
5435 int ret = MM_ERROR_NONE;
5437 if (player->gapless.reconfigure) {
5438 LOGW("pipeline is under construction.\n");
5440 MMPLAYER_PLAYBACK_LOCK(player);
5441 MMPLAYER_PLAYBACK_UNLOCK(player);
5443 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5445 /* wait for state transition */
5446 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5448 if (ret == GST_STATE_CHANGE_FAILURE)
5449 LOGE("failed to change pipeline state within %d sec\n", timeout);
5453 /* NOTE : it should be able to call 'stop' anytime*/
5455 _mmplayer_stop(MMHandleType hplayer)
5457 mm_player_t* player = (mm_player_t*)hplayer;
5458 int ret = MM_ERROR_NONE;
5462 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5464 /* check current state */
5465 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5467 /* check pipline building state */
5468 __mmplayer_check_pipeline(player);
5469 __mmplayer_reset_gapless_state(player);
5471 /* NOTE : application should not wait for EOS after calling STOP */
5472 __mmplayer_cancel_eos_timer(player);
5474 __mmplayer_unrealize_streaming_ext(player);
5477 player->seek_state = MMPLAYER_SEEK_NONE;
5480 ret = __mmplayer_gst_stop(player);
5482 if (ret != MM_ERROR_NONE)
5483 LOGE("failed to stop player.\n");
5491 _mmplayer_pause(MMHandleType hplayer)
5493 mm_player_t* player = (mm_player_t*)hplayer;
5494 gint64 pos_nsec = 0;
5495 gboolean async = FALSE;
5496 gint ret = MM_ERROR_NONE;
5500 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5502 /* check current state */
5503 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5505 /* check pipline building state */
5506 __mmplayer_check_pipeline(player);
5508 switch (MMPLAYER_CURRENT_STATE(player)) {
5509 case MM_PLAYER_STATE_READY:
5511 /* check prepare async or not.
5512 * In the case of streaming playback, it's recommned to avoid blocking wait.
5514 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5515 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5517 /* Changing back sync of rtspsrc to async */
5518 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5519 LOGD("async prepare working mode for rtsp");
5525 case MM_PLAYER_STATE_PLAYING:
5527 /* NOTE : store current point to overcome some bad operation
5528 *(returning zero when getting current position in paused state) of some
5531 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5532 LOGW("getting current position failed in paused\n");
5534 player->last_position = pos_nsec;
5536 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5537 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5538 This causes problem is position calculation during normal pause resume scenarios also.
5539 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5540 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5541 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5542 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5548 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5549 LOGD("doing async pause in case of ms buff src");
5553 /* pause pipeline */
5554 ret = __mmplayer_gst_pause(player, async);
5556 if (ret != MM_ERROR_NONE)
5557 LOGE("failed to pause player. ret : 0x%x\n", ret);
5559 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5560 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5561 LOGE("failed to update display_rotation");
5569 /* in case of streaming, pause could take long time.*/
5571 _mmplayer_abort_pause(MMHandleType hplayer)
5573 mm_player_t* player = (mm_player_t*)hplayer;
5574 int ret = MM_ERROR_NONE;
5578 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5580 player->pipeline->mainbin,
5581 MM_ERROR_PLAYER_NOT_INITIALIZED);
5583 LOGD("set the pipeline state to READY");
5585 /* set state to READY */
5586 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5587 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5588 if (ret != MM_ERROR_NONE) {
5589 LOGE("fail to change state to READY");
5590 return MM_ERROR_PLAYER_INTERNAL;
5593 LOGD("succeeded in changing state to READY");
5599 _mmplayer_resume(MMHandleType hplayer)
5601 mm_player_t* player = (mm_player_t*)hplayer;
5602 int ret = MM_ERROR_NONE;
5603 gboolean async = FALSE;
5607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5609 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5610 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5611 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5615 /* Changing back sync mode rtspsrc to async */
5616 LOGD("async resume for rtsp case");
5620 /* check current state */
5621 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5623 ret = __mmplayer_gst_resume(player, async);
5624 if (ret != MM_ERROR_NONE)
5625 LOGE("failed to resume player.\n");
5627 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5628 LOGD("force resume even during buffering");
5629 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5638 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5640 mm_player_t* player = (mm_player_t*)hplayer;
5641 gint64 pos_nsec = 0;
5642 int ret = MM_ERROR_NONE;
5644 signed long long start = 0, stop = 0;
5645 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5648 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5649 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5651 /* The sound of video is not supported under 0.0 and over 2.0. */
5652 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5653 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5656 _mmplayer_set_mute(hplayer, mute);
5658 if (player->playback_rate == rate)
5659 return MM_ERROR_NONE;
5661 /* If the position is reached at start potion during fast backward, EOS is posted.
5662 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5664 player->playback_rate = rate;
5666 current_state = MMPLAYER_CURRENT_STATE(player);
5668 if (current_state != MM_PLAYER_STATE_PAUSED)
5669 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5671 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5673 if ((current_state == MM_PLAYER_STATE_PAUSED)
5674 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5675 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5676 pos_nsec = player->last_position;
5681 stop = GST_CLOCK_TIME_NONE;
5683 start = GST_CLOCK_TIME_NONE;
5687 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5688 player->playback_rate,
5690 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5691 GST_SEEK_TYPE_SET, start,
5692 GST_SEEK_TYPE_SET, stop)) {
5693 LOGE("failed to set speed playback\n");
5694 return MM_ERROR_PLAYER_SEEK;
5697 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5701 return MM_ERROR_NONE;;
5705 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5707 mm_player_t* player = (mm_player_t*)hplayer;
5708 int ret = MM_ERROR_NONE;
5712 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5714 /* check pipline building state */
5715 __mmplayer_check_pipeline(player);
5717 ret = __mmplayer_gst_set_position(player, position, FALSE);
5725 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5727 mm_player_t* player = (mm_player_t*)hplayer;
5728 int ret = MM_ERROR_NONE;
5730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5732 ret = __mmplayer_gst_get_position(player, position);
5738 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5740 mm_player_t* player = (mm_player_t*)hplayer;
5741 int ret = MM_ERROR_NONE;
5743 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5744 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5746 *duration = player->duration;
5751 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5753 mm_player_t* player = (mm_player_t*)hplayer;
5754 int ret = MM_ERROR_NONE;
5756 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5758 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5764 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5766 mm_player_t* player = (mm_player_t*)hplayer;
5767 int ret = MM_ERROR_NONE;
5771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5773 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5781 __mmplayer_is_midi_type(gchar* str_caps)
5783 if ((g_strrstr(str_caps, "audio/midi")) ||
5784 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5785 (g_strrstr(str_caps, "application/x-smaf")) ||
5786 (g_strrstr(str_caps, "audio/x-imelody")) ||
5787 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5788 (g_strrstr(str_caps, "audio/xmf")) ||
5789 (g_strrstr(str_caps, "audio/mxmf"))) {
5798 __mmplayer_is_only_mp3_type(gchar *str_caps)
5800 if (g_strrstr(str_caps, "application/x-id3") ||
5801 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5807 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5809 GstStructure* caps_structure = NULL;
5810 gint samplerate = 0;
5814 MMPLAYER_RETURN_IF_FAIL(player && caps);
5816 caps_structure = gst_caps_get_structure(caps, 0);
5818 /* set stream information */
5819 gst_structure_get_int(caps_structure, "rate", &samplerate);
5820 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5822 gst_structure_get_int(caps_structure, "channels", &channels);
5823 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5825 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5829 __mmplayer_update_content_type_info(mm_player_t* player)
5832 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5834 if (__mmplayer_is_midi_type(player->type)) {
5835 player->bypass_audio_effect = TRUE;
5836 } else if (g_strrstr(player->type, "application/x-hls")) {
5837 /* If it can't know exact type when it parses uri because of redirection case,
5838 * it will be fixed by typefinder or when doing autoplugging.
5840 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5841 if (player->streamer) {
5842 player->streamer->is_adaptive_streaming = TRUE;
5843 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5844 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5846 } else if (g_strrstr(player->type, "application/dash+xml")) {
5847 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5848 if (player->streamer) {
5849 player->streamer->is_adaptive_streaming = TRUE;
5850 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5854 LOGD("uri type : %d", player->profile.uri_type);
5859 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5860 GstCaps *caps, gpointer data)
5862 mm_player_t* player = (mm_player_t*)data;
5867 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5869 /* store type string */
5870 MMPLAYER_FREEIF(player->type);
5871 player->type = gst_caps_to_string(caps);
5873 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5874 player, player->type, probability, gst_caps_get_size(caps));
5877 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5878 (g_strrstr(player->type, "audio/x-raw-int"))) {
5879 LOGE("not support media format\n");
5881 if (player->msg_posted == FALSE) {
5882 MMMessageParamType msg_param;
5883 memset(&msg_param, 0, sizeof(MMMessageParamType));
5885 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5886 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5888 /* don't post more if one was sent already */
5889 player->msg_posted = TRUE;
5894 __mmplayer_update_content_type_info(player);
5896 pad = gst_element_get_static_pad(tf, "src");
5898 LOGE("fail to get typefind src pad.\n");
5902 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5903 gboolean async = FALSE;
5904 LOGE("failed to autoplug %s\n", player->type);
5906 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5908 if (async && player->msg_posted == FALSE)
5909 __mmplayer_handle_missed_plugin(player);
5915 gst_object_unref(GST_OBJECT(pad));
5923 __mmplayer_gst_make_decodebin(mm_player_t* player)
5925 GstElement *decodebin = NULL;
5929 /* create decodebin */
5930 decodebin = gst_element_factory_make("decodebin", NULL);
5933 LOGE("fail to create decodebin\n");
5937 /* raw pad handling signal */
5938 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5939 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5941 /* no-more-pad pad handling signal */
5942 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5943 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5945 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5946 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5948 /* This signal is emitted when a pad for which there is no further possible
5949 decoding is added to the decodebin.*/
5950 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5951 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5953 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5954 before looking for any elements that can handle that stream.*/
5955 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5956 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5958 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5959 before looking for any elements that can handle that stream.*/
5960 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5961 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5963 /* This signal is emitted once decodebin has finished decoding all the data.*/
5964 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5965 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5967 /* This signal is emitted when a element is added to the bin.*/
5968 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5969 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5976 __mmplayer_gst_make_queue2(mm_player_t *player)
5978 GstElement* queue2 = NULL;
5979 gint64 dur_bytes = 0L;
5980 guint max_buffer_size_bytes = 0;
5981 MMPlayerGstElement *mainbin = NULL;
5982 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5985 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5987 mainbin = player->pipeline->mainbin;
5989 queue2 = gst_element_factory_make("queue2", "queue2");
5991 LOGE("failed to create buffering queue element");
5995 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5996 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5998 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6000 if (dur_bytes > 0) {
6001 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
6002 type = MUXED_BUFFER_TYPE_FILE;
6004 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6005 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6011 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
6012 * skip the pull mode(file or ring buffering) setting. */
6013 if (!g_strrstr(player->type, "video/mpegts")) {
6014 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
6015 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
6017 __mm_player_streaming_set_queue2(player->streamer,
6020 max_buffer_size_bytes,
6021 player->ini.http_buffering_time,
6022 1.0, /* no meaning */
6023 player->ini.http_buffering_limit, /* no meaning */
6025 player->http_file_buffering_path,
6026 (guint64)dur_bytes);
6033 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
6035 MMPlayerGstElement* mainbin = NULL;
6036 GstElement* decodebin = NULL;
6037 GstElement* queue2 = NULL;
6038 GstPad* sinkpad = NULL;
6039 GstPad* qsrcpad = NULL;
6040 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6043 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6045 mainbin = player->pipeline->mainbin;
6047 if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
6049 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6050 LOGW("need to check: muxed buffer is not null");
6053 queue2 = __mmplayer_gst_make_queue2(player);
6055 LOGE("failed to make queue2");
6059 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6060 LOGE("failed to add buffering queue");
6064 sinkpad = gst_element_get_static_pad(queue2, "sink");
6065 qsrcpad = gst_element_get_static_pad(queue2, "src");
6067 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6068 LOGE("failed to link [%s:%s]-[%s:%s]",
6069 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6073 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6074 LOGE("failed to sync queue2 state with parent");
6078 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6079 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6083 gst_object_unref(GST_OBJECT(sinkpad));
6087 /* create decodebin */
6088 decodebin = __mmplayer_gst_make_decodebin(player);
6090 LOGE("failed to make decodebin");
6094 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6095 LOGE("failed to add decodebin\n");
6099 /* to force caps on the decodebin element and avoid reparsing stuff by
6100 * typefind. It also avoids a deadlock in the way typefind activates pads in
6101 * the state change */
6102 g_object_set(decodebin, "sink-caps", caps, NULL);
6104 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6106 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6107 LOGE("failed to link [%s:%s]-[%s:%s]",
6108 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6112 gst_object_unref(GST_OBJECT(sinkpad));
6115 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6116 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6118 /* set decodebin property about buffer in streaming playback. *
6119 * in case of HLS/DASH, it does not need to have big buffer *
6120 * because it is kind of adaptive streaming. */
6121 if (!MMPLAYER_IS_HTTP_PD(player) &&
6122 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6123 gdouble high_percent = 0.0;
6125 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6126 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6128 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6129 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6131 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6132 "high-percent", (gint)high_percent,
6133 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6134 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6135 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6136 "max-size-buffers", 0, NULL); // disable or automatic
6139 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6140 LOGE("failed to sync decodebin state with parent\n");
6151 gst_object_unref(GST_OBJECT(sinkpad));
6154 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6155 * You need to explicitly set elements to the NULL state before
6156 * dropping the final reference, to allow them to clean up.
6158 gst_element_set_state(queue2, GST_STATE_NULL);
6160 /* And, it still has a parent "player".
6161 * You need to let the parent manage the object instead of unreffing the object directly.
6163 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6164 gst_object_unref(queue2);
6169 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6170 * You need to explicitly set elements to the NULL state before
6171 * dropping the final reference, to allow them to clean up.
6173 gst_element_set_state(decodebin, GST_STATE_NULL);
6175 /* And, it still has a parent "player".
6176 * You need to let the parent manage the object instead of unreffing the object directly.
6179 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6180 gst_object_unref(decodebin);
6188 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6192 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6193 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6195 LOGD("class : %s, mime : %s \n", factory_class, mime);
6197 /* add missing plugin */
6198 /* NOTE : msl should check missing plugin for image mime type.
6199 * Some motion jpeg clips can have playable audio track.
6200 * So, msl have to play audio after displaying popup written video format not supported.
6202 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6203 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6204 LOGD("not found demuxer\n");
6205 player->not_found_demuxer = TRUE;
6206 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6212 if (!g_strrstr(factory_class, "Demuxer")) {
6213 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6214 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6215 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6217 /* check that clip have multi tracks or not */
6218 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6219 LOGD("video plugin is already linked\n");
6221 LOGW("add VIDEO to missing plugin\n");
6222 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6223 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6225 } else if (g_str_has_prefix(mime, "audio")) {
6226 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6227 LOGD("audio plugin is already linked\n");
6229 LOGW("add AUDIO to missing plugin\n");
6230 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6231 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6239 return MM_ERROR_NONE;
6244 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6246 mm_player_t* player = (mm_player_t*)data;
6250 MMPLAYER_RETURN_IF_FAIL(player);
6252 /* remove fakesink. */
6253 if (!__mmplayer_gst_remove_fakesink(player,
6254 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6255 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6256 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6257 * source element are not same. To overcome this situation, this function will called
6258 * several places and several times. Therefore, this is not an error case.
6263 LOGD("[handle: %p] pipeline has completely constructed", player);
6265 if ((player->ini.async_start) &&
6266 (player->msg_posted == FALSE) &&
6267 (player->cmd >= MMPLAYER_COMMAND_START))
6268 __mmplayer_handle_missed_plugin(player);
6270 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6274 __mmplayer_check_profile(void)
6277 static int profile_tv = -1;
6279 if (__builtin_expect(profile_tv != -1, 1))
6282 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6283 switch (*profileName) {
6298 __mmplayer_get_next_uri(mm_player_t *player)
6300 MMPlayerParseProfile profile;
6302 guint num_of_list = 0;
6305 num_of_list = g_list_length(player->uri_info.uri_list);
6306 uri_idx = player->uri_info.uri_idx;
6308 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6309 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6310 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6312 LOGW("next uri does not exist");
6316 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6317 LOGE("failed to parse profile");
6321 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6322 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6323 LOGW("uri type is not supported(%d)", profile.uri_type);
6327 LOGD("success to find next uri %d", uri_idx);
6331 if (uri_idx == num_of_list) {
6332 LOGE("failed to find next uri");
6336 player->uri_info.uri_idx = uri_idx;
6337 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6339 if (mm_attrs_commit_all(player->attrs)) {
6340 LOGE("failed to commit");
6344 SECURE_LOGD("next playback uri: %s", uri);
6349 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6351 #define REPEAT_COUNT_INFINITELY -1
6352 #define REPEAT_COUNT_MIN 2
6354 MMHandleType attrs = 0;
6355 gint mode = MM_PLAYER_PD_MODE_NONE;
6359 guint num_of_list = 0;
6360 int profile_tv = -1;
6364 LOGD("checking for gapless play option");
6366 if (player->pipeline->textbin) {
6367 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6371 attrs = MMPLAYER_GET_ATTRS(player);
6373 LOGE("fail to get attributes.\n");
6377 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6379 /* gapless playback is not supported in case of video at TV profile. */
6380 profile_tv = __mmplayer_check_profile();
6381 if (profile_tv && video) {
6382 LOGW("not support video gapless playback");
6386 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6393 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6394 LOGE("failed to get play count");
6396 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6397 LOGE("failed to get gapless mode");
6399 /* check repeat count in case of audio */
6401 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6402 LOGW("gapless is disabled");
6406 num_of_list = g_list_length(player->uri_info.uri_list);
6408 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6410 if (num_of_list == 0) {
6411 /* audio looping path */
6412 if (count >= REPEAT_COUNT_MIN) {
6413 /* decrease play count */
6414 /* we succeeded to rewind. update play count and then wait for next EOS */
6417 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6419 /* commit attribute */
6420 if (mm_attrs_commit_all(attrs))
6421 LOGE("failed to commit attribute");
6422 } else if (count != REPEAT_COUNT_INFINITELY) {
6423 LOGD("there is no next uri and no repeat");
6427 LOGD("looping cnt %d", count);
6429 /* gapless playback path */
6430 if (!__mmplayer_get_next_uri(player)) {
6431 LOGE("failed to get next uri");
6439 LOGE("unable to play gapless path. EOS will be posted soon");
6444 __mmplayer_initialize_gapless_play(mm_player_t *player)
6450 player->smooth_streaming = FALSE;
6451 player->videodec_linked = 0;
6452 player->audiodec_linked = 0;
6453 player->textsink_linked = 0;
6454 player->is_external_subtitle_present = FALSE;
6455 player->is_external_subtitle_added_now = FALSE;
6456 player->not_supported_codec = MISSING_PLUGIN_NONE;
6457 player->can_support_codec = FOUND_PLUGIN_NONE;
6458 player->pending_seek.is_pending = FALSE;
6459 player->pending_seek.pos = 0;
6460 player->msg_posted = FALSE;
6461 player->has_many_types = FALSE;
6462 player->no_more_pad = FALSE;
6463 player->not_found_demuxer = 0;
6464 player->seek_state = MMPLAYER_SEEK_NONE;
6465 player->is_subtitle_force_drop = FALSE;
6466 player->play_subtitle = FALSE;
6467 player->adjust_subtitle_pos = 0;
6469 player->total_bitrate = 0;
6470 player->total_maximum_bitrate = 0;
6472 __mmplayer_track_initialize(player);
6473 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6475 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6476 player->bitrate[i] = 0;
6477 player->maximum_bitrate[i] = 0;
6480 if (player->v_stream_caps) {
6481 gst_caps_unref(player->v_stream_caps);
6482 player->v_stream_caps = NULL;
6485 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6487 /* clean found parsers */
6488 if (player->parsers) {
6489 GList *parsers = player->parsers;
6490 for (; parsers; parsers = g_list_next(parsers)) {
6491 gchar *name = parsers->data;
6492 MMPLAYER_FREEIF(name);
6494 g_list_free(player->parsers);
6495 player->parsers = NULL;
6498 /* clean found audio decoders */
6499 if (player->audio_decoders) {
6500 GList *a_dec = player->audio_decoders;
6501 for (; a_dec; a_dec = g_list_next(a_dec)) {
6502 gchar *name = a_dec->data;
6503 MMPLAYER_FREEIF(name);
6505 g_list_free(player->audio_decoders);
6506 player->audio_decoders = NULL;
6513 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6515 MMPlayerGstElement *mainbin = NULL;
6516 MMMessageParamType msg_param = {0,};
6517 GstElement *element = NULL;
6518 MMHandleType attrs = 0;
6520 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6524 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6525 LOGE("player is not initialized");
6529 mainbin = player->pipeline->mainbin;
6530 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6532 attrs = MMPLAYER_GET_ATTRS(player);
6534 LOGE("fail to get attributes");
6538 /* Initialize Player values */
6539 __mmplayer_initialize_gapless_play(player);
6541 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6543 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6544 LOGE("failed to parse profile");
6545 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6549 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6550 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6551 LOGE("dash or hls is not supportable");
6552 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6556 element = __mmplayer_gst_create_source(player);
6558 LOGE("no source element was created");
6562 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6563 LOGE("failed to add source element to pipeline");
6564 gst_object_unref(GST_OBJECT(element));
6569 /* take source element */
6570 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6571 mainbin[MMPLAYER_M_SRC].gst = element;
6575 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6576 if (player->streamer == NULL) {
6577 player->streamer = __mm_player_streaming_create();
6578 __mm_player_streaming_initialize(player->streamer);
6581 elem_idx = MMPLAYER_M_TYPEFIND;
6582 element = gst_element_factory_make("typefind", "typefinder");
6583 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6584 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6586 elem_idx = MMPLAYER_M_AUTOPLUG;
6587 element = __mmplayer_gst_make_decodebin(player);
6590 /* check autoplug element is OK */
6592 LOGE("can not create element(%d)", elem_idx);
6596 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6597 LOGE("failed to add sinkbin to pipeline");
6598 gst_object_unref(GST_OBJECT(element));
6603 mainbin[elem_idx].id = elem_idx;
6604 mainbin[elem_idx].gst = element;
6606 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6607 LOGE("Failed to link src - autoplug(or typefind)");
6611 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6612 LOGE("Failed to change state of src element");
6616 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6617 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6618 LOGE("Failed to change state of decodebin");
6622 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6623 LOGE("Failed to change state of src element");
6628 player->gapless.stream_changed = TRUE;
6629 player->gapless.running = TRUE;
6635 MMPLAYER_PLAYBACK_UNLOCK(player);
6637 if (!player->msg_posted) {
6638 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6639 player->msg_posted = TRUE;
6646 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6648 mm_player_selector_t *selector = &player->selector[type];
6649 MMPlayerGstElement *sinkbin = NULL;
6650 enum MainElementID selectorId = MMPLAYER_M_NUM;
6651 enum MainElementID sinkId = MMPLAYER_M_NUM;
6652 GstPad *srcpad = NULL;
6653 GstPad *sinkpad = NULL;
6654 gboolean send_notice = FALSE;
6657 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6659 LOGD("type %d", type);
6662 case MM_PLAYER_TRACK_TYPE_AUDIO:
6663 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6664 sinkId = MMPLAYER_A_BIN;
6665 sinkbin = player->pipeline->audiobin;
6667 case MM_PLAYER_TRACK_TYPE_VIDEO:
6668 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6669 sinkId = MMPLAYER_V_BIN;
6670 sinkbin = player->pipeline->videobin;
6673 case MM_PLAYER_TRACK_TYPE_TEXT:
6674 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6675 sinkId = MMPLAYER_T_BIN;
6676 sinkbin = player->pipeline->textbin;
6679 LOGE("requested type is not supportable");
6684 if (player->pipeline->mainbin[selectorId].gst) {
6687 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6689 if (selector->event_probe_id != 0)
6690 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6691 selector->event_probe_id = 0;
6693 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6694 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6696 if (srcpad && sinkpad) {
6697 /* after getting drained signal there is no data flows, so no need to do pad_block */
6698 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6699 gst_pad_unlink(srcpad, sinkpad);
6701 /* send custom event to sink pad to handle it at video sink */
6703 LOGD("send custom event to sinkpad");
6704 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6705 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6706 gst_pad_send_event(sinkpad, event);
6710 gst_object_unref(sinkpad);
6713 gst_object_unref(srcpad);
6716 LOGD("selector release");
6718 /* release and unref requests pad from the selector */
6719 for (n = 0; n < selector->channels->len; n++) {
6720 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6721 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6723 g_ptr_array_set_size(selector->channels, 0);
6725 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6726 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6728 player->pipeline->mainbin[selectorId].gst = NULL;
6736 __mmplayer_deactivate_old_path(mm_player_t *player)
6739 MMPLAYER_RETURN_IF_FAIL(player);
6741 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6742 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6743 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6744 LOGE("deactivate selector error");
6748 __mmplayer_track_destroy(player);
6749 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6751 if (player->streamer) {
6752 __mm_player_streaming_deinitialize(player->streamer);
6753 __mm_player_streaming_destroy(player->streamer);
6754 player->streamer = NULL;
6757 MMPLAYER_PLAYBACK_LOCK(player);
6758 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6765 if (!player->msg_posted) {
6766 MMMessageParamType msg = {0,};
6769 msg.code = MM_ERROR_PLAYER_INTERNAL;
6770 LOGE("gapless_uri_play> deactivate error");
6772 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6773 player->msg_posted = TRUE;
6778 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6780 int result = MM_ERROR_NONE;
6781 mm_player_t* player = (mm_player_t*) hplayer;
6784 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6787 player->http_file_buffering_path = (gchar*)file_path;
6788 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6794 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6796 int result = MM_ERROR_NONE;
6797 mm_player_t* player = (mm_player_t*) hplayer;
6800 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6802 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6803 if (mm_attrs_commit_all(player->attrs)) {
6804 LOGE("failed to commit the original uri.\n");
6805 result = MM_ERROR_PLAYER_INTERNAL;
6807 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6808 LOGE("failed to add the original uri in the uri list.\n");
6815 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6817 mm_player_t* player = (mm_player_t*) hplayer;
6818 guint num_of_list = 0;
6822 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6823 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6825 if (player->pipeline && player->pipeline->textbin) {
6826 LOGE("subtitle path is enabled.\n");
6827 return MM_ERROR_PLAYER_INVALID_STATE;
6830 num_of_list = g_list_length(player->uri_info.uri_list);
6832 if (is_first_path == TRUE) {
6833 if (num_of_list == 0) {
6834 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6835 LOGD("add original path : %s", uri);
6837 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6838 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6840 LOGD("change original path : %s", uri);
6843 MMHandleType attrs = 0;
6844 attrs = MMPLAYER_GET_ATTRS(player);
6846 if (num_of_list == 0) {
6847 char *original_uri = NULL;
6850 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6852 if (!original_uri) {
6853 LOGE("there is no original uri.");
6854 return MM_ERROR_PLAYER_INVALID_STATE;
6857 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6858 player->uri_info.uri_idx = 0;
6860 LOGD("add original path at first : %s(%d)", original_uri);
6864 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6865 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6869 return MM_ERROR_NONE;
6872 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6874 mm_player_t* player = (mm_player_t*) hplayer;
6875 char *next_uri = NULL;
6876 guint num_of_list = 0;
6879 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6881 num_of_list = g_list_length(player->uri_info.uri_list);
6883 if (num_of_list > 0) {
6884 gint uri_idx = player->uri_info.uri_idx;
6886 if (uri_idx < num_of_list-1)
6891 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6892 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6894 *uri = g_strdup(next_uri);
6898 return MM_ERROR_NONE;
6902 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6903 GstCaps *caps, gpointer data)
6905 mm_player_t* player = (mm_player_t*)data;
6906 const gchar* klass = NULL;
6907 const gchar* mime = NULL;
6908 gchar* caps_str = NULL;
6910 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6911 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6912 caps_str = gst_caps_to_string(caps);
6914 LOGW("unknown type of caps : %s from %s",
6915 caps_str, GST_ELEMENT_NAME(elem));
6917 MMPLAYER_FREEIF(caps_str);
6919 /* There is no available codec. */
6920 __mmplayer_check_not_supported_codec(player, klass, mime);
6924 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6925 GstCaps * caps, gpointer data)
6927 mm_player_t* player = (mm_player_t*)data;
6928 const char* mime = NULL;
6929 gboolean ret = TRUE;
6931 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6932 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6934 if (g_str_has_prefix(mime, "audio")) {
6935 GstStructure* caps_structure = NULL;
6936 gint samplerate = 0;
6938 gchar *caps_str = NULL;
6940 caps_structure = gst_caps_get_structure(caps, 0);
6941 gst_structure_get_int(caps_structure, "rate", &samplerate);
6942 gst_structure_get_int(caps_structure, "channels", &channels);
6944 if ((channels > 0 && samplerate == 0)) {
6945 LOGD("exclude audio...");
6949 caps_str = gst_caps_to_string(caps);
6950 /* set it directly because not sent by TAG */
6951 if (g_strrstr(caps_str, "mobile-xmf"))
6952 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6953 MMPLAYER_FREEIF(caps_str);
6954 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6955 MMMessageParamType msg_param;
6956 memset(&msg_param, 0, sizeof(MMMessageParamType));
6957 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6958 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6959 LOGD("video file is not supported on this device");
6961 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6962 LOGD("already video linked");
6965 LOGD("found new stream");
6972 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6974 int ret = MM_ERROR_NONE;
6976 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6978 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6979 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6981 LOGD("audio codec type: %d", codec_type);
6982 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6983 /* sw codec will be skipped */
6984 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6985 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6986 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6987 ret = MM_ERROR_PLAYER_INTERNAL;
6991 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6992 /* hw codec will be skipped */
6993 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6994 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6995 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6996 ret = MM_ERROR_PLAYER_INTERNAL;
7001 /* set stream information */
7002 if (!player->audiodec_linked)
7003 __mmplayer_set_audio_attrs(player, caps);
7005 /* update codec info */
7006 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7007 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7008 player->audiodec_linked = 1;
7010 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7012 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7014 LOGD("video codec type: %d", codec_type);
7015 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7016 /* sw codec is skipped */
7017 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7018 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7019 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7020 ret = MM_ERROR_PLAYER_INTERNAL;
7024 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7025 /* hw codec is skipped */
7026 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7027 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7028 ret = MM_ERROR_PLAYER_INTERNAL;
7033 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7034 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7036 /* mark video decoder for acquire */
7037 if (player->video_decoder_resource == NULL) {
7038 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7039 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7040 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7041 &player->video_decoder_resource)
7042 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7043 LOGE("could not mark video_decoder resource for acquire");
7044 ret = MM_ERROR_PLAYER_INTERNAL;
7048 LOGW("video decoder resource is already acquired, skip it.");
7049 ret = MM_ERROR_PLAYER_INTERNAL;
7053 player->interrupted_by_resource = FALSE;
7054 /* acquire resources for video playing */
7055 if (mm_resource_manager_commit(player->resource_manager)
7056 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7057 LOGE("could not acquire resources for video decoding\n");
7058 ret = MM_ERROR_PLAYER_INTERNAL;
7063 /* update codec info */
7064 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7065 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7066 player->videodec_linked = 1;
7074 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7075 GstCaps* caps, GstElementFactory* factory, gpointer data)
7077 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7078 We are defining our own and will be removed when it actually exposed */
7080 GST_AUTOPLUG_SELECT_TRY,
7081 GST_AUTOPLUG_SELECT_EXPOSE,
7082 GST_AUTOPLUG_SELECT_SKIP
7083 } GstAutoplugSelectResult;
7085 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7086 mm_player_t* player = (mm_player_t*)data;
7088 gchar* factory_name = NULL;
7089 gchar* caps_str = NULL;
7090 const gchar* klass = NULL;
7093 factory_name = GST_OBJECT_NAME(factory);
7094 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7095 caps_str = gst_caps_to_string(caps);
7097 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7099 /* store type string */
7100 if (player->type == NULL) {
7101 player->type = gst_caps_to_string(caps);
7102 __mmplayer_update_content_type_info(player);
7105 /* filtering exclude keyword */
7106 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7107 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7108 LOGW("skipping [%s] by exculde keyword [%s]",
7109 factory_name, player->ini.exclude_element_keyword[idx]);
7111 result = GST_AUTOPLUG_SELECT_SKIP;
7116 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7117 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7118 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7119 factory_name, player->ini.unsupported_codec_keyword[idx]);
7120 result = GST_AUTOPLUG_SELECT_SKIP;
7125 /* exclude webm format */
7126 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7127 * because webm format is not supportable.
7128 * If webm is disabled in "autoplug-continue", there is no state change
7129 * failure or error because the decodebin will expose the pad directly.
7130 * It make MSL invoke _prepare_async_callback.
7131 * So, we need to disable webm format in "autoplug-select" */
7132 if (caps_str && strstr(caps_str, "webm")) {
7133 LOGW("webm is not supported");
7134 result = GST_AUTOPLUG_SELECT_SKIP;
7138 /* check factory class for filtering */
7139 /* NOTE : msl don't need to use image plugins.
7140 * So, those plugins should be skipped for error handling.
7142 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7143 LOGD("skipping [%s] by not required\n", factory_name);
7144 result = GST_AUTOPLUG_SELECT_SKIP;
7148 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7149 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7150 // TO CHECK : subtitle if needed, add subparse exception.
7151 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7152 result = GST_AUTOPLUG_SELECT_SKIP;
7156 if (g_strrstr(factory_name, "mpegpsdemux")) {
7157 LOGD("skipping PS container - not support\n");
7158 result = GST_AUTOPLUG_SELECT_SKIP;
7162 if (g_strrstr(factory_name, "mssdemux"))
7163 player->smooth_streaming = TRUE;
7165 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7166 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7169 GstStructure *str = NULL;
7170 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7172 /* don't make video because of not required */
7173 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7174 (player->set_mode.media_packet_video_stream == FALSE)) {
7175 LOGD("no video because it's not required. -> return expose");
7176 result = GST_AUTOPLUG_SELECT_EXPOSE;
7180 /* get w/h for omx state-tune */
7181 /* FIXME: deprecated? */
7182 str = gst_caps_get_structure(caps, 0);
7183 gst_structure_get_int(str, "width", &width);
7186 if (player->v_stream_caps) {
7187 gst_caps_unref(player->v_stream_caps);
7188 player->v_stream_caps = NULL;
7191 player->v_stream_caps = gst_caps_copy(caps);
7192 LOGD("take caps for video state tune");
7193 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7197 if (g_strrstr(klass, "Codec/Decoder")) {
7198 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7199 LOGD("skipping %s codec", factory_name);
7200 result = GST_AUTOPLUG_SELECT_SKIP;
7206 MMPLAYER_FREEIF(caps_str);
7212 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7215 //mm_player_t* player = (mm_player_t*)data;
7216 GstCaps* caps = NULL;
7218 LOGD("[Decodebin2] pad-removed signal\n");
7220 caps = gst_pad_query_caps(new_pad, NULL);
7222 gchar* caps_str = NULL;
7223 caps_str = gst_caps_to_string(caps);
7225 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7227 MMPLAYER_FREEIF(caps_str);
7228 gst_caps_unref(caps);
7233 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7235 mm_player_t* player = (mm_player_t*)data;
7236 GstIterator *iter = NULL;
7237 GValue item = { 0, };
7239 gboolean done = FALSE;
7240 gboolean is_all_drained = TRUE;
7243 MMPLAYER_RETURN_IF_FAIL(player);
7245 LOGD("__mmplayer_gst_decode_drained");
7247 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7248 LOGW("Fail to get cmd lock");
7252 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7253 !__mmplayer_verify_gapless_play_path(player)) {
7254 LOGD("decoding is finished.");
7255 __mmplayer_reset_gapless_state(player);
7256 MMPLAYER_CMD_UNLOCK(player);
7260 player->gapless.reconfigure = TRUE;
7262 /* check decodebin src pads whether they received EOS or not */
7263 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7266 switch (gst_iterator_next(iter, &item)) {
7267 case GST_ITERATOR_OK:
7268 pad = g_value_get_object(&item);
7269 if (pad && !GST_PAD_IS_EOS(pad)) {
7270 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7271 is_all_drained = FALSE;
7274 g_value_reset(&item);
7276 case GST_ITERATOR_RESYNC:
7277 gst_iterator_resync(iter);
7279 case GST_ITERATOR_ERROR:
7280 case GST_ITERATOR_DONE:
7285 g_value_unset(&item);
7286 gst_iterator_free(iter);
7288 if (!is_all_drained) {
7289 LOGD("Wait util the all pads get EOS.");
7290 MMPLAYER_CMD_UNLOCK(player);
7295 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7296 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7298 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7299 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7300 __mmplayer_deactivate_old_path(player);
7301 MMPLAYER_CMD_UNLOCK(player);
7307 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7309 mm_player_t* player = (mm_player_t*)data;
7310 const gchar* klass = NULL;
7311 gchar* factory_name = NULL;
7313 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7314 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7316 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7318 if (__mmplayer_add_dump_buffer_probe(player, element))
7319 LOGD("add buffer probe");
7322 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7323 gchar* selected = NULL;
7324 selected = g_strdup(GST_ELEMENT_NAME(element));
7325 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7329 if (g_strrstr(klass, "Parser")) {
7330 gchar* selected = NULL;
7332 selected = g_strdup(factory_name);
7333 player->parsers = g_list_append(player->parsers, selected);
7336 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7337 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7338 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7340 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7341 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7343 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7344 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7345 "max-video-width", player->adaptive_info.limit.width,
7346 "max-video-height", player->adaptive_info.limit.height, NULL);
7348 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
7349 /* FIXIT : first value will be overwritten if there's more
7350 * than 1 demuxer/parser
7353 //LOGD("plugged element is demuxer. take it\n");
7354 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7355 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7357 /*Added for multi audio support */ // Q. del?
7358 if (g_strrstr(klass, "Demux")) {
7359 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
7360 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
7364 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7365 int surface_type = 0;
7367 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7370 // to support trust-zone only
7371 if (g_strrstr(factory_name, "asfdemux")) {
7372 LOGD("set file-location %s\n", player->profile.uri);
7373 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7374 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7375 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7376 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7377 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7378 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7379 (__mmplayer_is_only_mp3_type(player->type))) {
7380 LOGD("[mpegaudioparse] set streaming pull mode.");
7381 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7383 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7384 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7387 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7388 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7389 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7391 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7392 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7394 if (!MMPLAYER_IS_HTTP_PD(player) &&
7395 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7396 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7397 (MMPLAYER_IS_DASH_STREAMING(player)))) {
7398 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7399 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7400 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7409 __mmplayer_release_misc(mm_player_t* player)
7412 bool cur_mode = player->set_mode.rich_audio;
7415 MMPLAYER_RETURN_IF_FAIL(player);
7417 player->video_stream_cb = NULL;
7418 player->video_stream_cb_user_param = NULL;
7419 player->video_stream_prerolled = FALSE;
7421 player->audio_stream_render_cb = NULL;
7422 player->audio_stream_cb_user_param = NULL;
7423 player->audio_stream_sink_sync = false;
7425 player->video_stream_changed_cb = NULL;
7426 player->video_stream_changed_cb_user_param = NULL;
7428 player->audio_stream_changed_cb = NULL;
7429 player->audio_stream_changed_cb_user_param = NULL;
7431 player->sent_bos = FALSE;
7432 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7434 player->seek_state = MMPLAYER_SEEK_NONE;
7436 player->total_bitrate = 0;
7437 player->total_maximum_bitrate = 0;
7439 player->not_found_demuxer = 0;
7441 player->last_position = 0;
7442 player->duration = 0;
7443 player->http_content_size = 0;
7444 player->not_supported_codec = MISSING_PLUGIN_NONE;
7445 player->can_support_codec = FOUND_PLUGIN_NONE;
7446 player->pending_seek.is_pending = FALSE;
7447 player->pending_seek.pos = 0;
7448 player->msg_posted = FALSE;
7449 player->has_many_types = FALSE;
7450 player->is_subtitle_force_drop = FALSE;
7451 player->play_subtitle = FALSE;
7452 player->adjust_subtitle_pos = 0;
7453 player->last_multiwin_status = FALSE;
7454 player->has_closed_caption = FALSE;
7455 player->set_mode.media_packet_video_stream = FALSE;
7456 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7457 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7459 player->set_mode.rich_audio = cur_mode;
7461 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7462 player->bitrate[i] = 0;
7463 player->maximum_bitrate[i] = 0;
7466 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7468 /* remove media stream cb(appsrc cb) */
7469 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7470 player->media_stream_buffer_status_cb[i] = NULL;
7471 player->media_stream_seek_data_cb[i] = NULL;
7472 player->buffer_cb_user_param[i] = NULL;
7473 player->seek_cb_user_param[i] = NULL;
7475 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7477 /* free memory related to audio effect */
7478 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7480 if (player->adaptive_info.var_list) {
7481 g_list_free_full(player->adaptive_info.var_list, g_free);
7482 player->adaptive_info.var_list = NULL;
7485 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7486 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7487 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7489 /* Reset video360 settings to their defaults in case if the pipeline is to be
7492 player->video360_metadata.is_spherical = -1;
7493 player->is_openal_plugin_used = FALSE;
7495 player->is_content_spherical = FALSE;
7496 player->is_video360_enabled = TRUE;
7497 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7498 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7499 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7500 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7501 player->video360_zoom = 1.0f;
7502 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7503 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7505 player->sound.rg_enable = false;
7507 __mmplayer_initialize_video_roi(player);
7512 __mmplayer_release_misc_post(mm_player_t* player)
7514 char *original_uri = NULL;
7517 /* player->pipeline is already released before. */
7519 MMPLAYER_RETURN_IF_FAIL(player);
7521 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7523 /* clean found parsers */
7524 if (player->parsers) {
7525 GList *parsers = player->parsers;
7526 for (; parsers; parsers = g_list_next(parsers)) {
7527 gchar *name = parsers->data;
7528 MMPLAYER_FREEIF(name);
7530 g_list_free(player->parsers);
7531 player->parsers = NULL;
7534 /* clean found audio decoders */
7535 if (player->audio_decoders) {
7536 GList *a_dec = player->audio_decoders;
7537 for (; a_dec; a_dec = g_list_next(a_dec)) {
7538 gchar *name = a_dec->data;
7539 MMPLAYER_FREEIF(name);
7541 g_list_free(player->audio_decoders);
7542 player->audio_decoders = NULL;
7545 /* clean the uri list except original uri */
7546 if (player->uri_info.uri_list) {
7547 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7549 if (player->attrs) {
7550 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7551 LOGD("restore original uri = %s\n", original_uri);
7553 if (mm_attrs_commit_all(player->attrs))
7554 LOGE("failed to commit the original uri.\n");
7557 GList *uri_list = player->uri_info.uri_list;
7558 for (; uri_list; uri_list = g_list_next(uri_list)) {
7559 gchar *uri = uri_list->data;
7560 MMPLAYER_FREEIF(uri);
7562 g_list_free(player->uri_info.uri_list);
7563 player->uri_info.uri_list = NULL;
7566 /* clear the audio stream buffer list */
7567 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7569 /* clear the video stream bo list */
7570 __mmplayer_video_stream_destroy_bo_list(player);
7571 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7573 if (player->profile.input_mem.buf) {
7574 free(player->profile.input_mem.buf);
7575 player->profile.input_mem.buf = NULL;
7577 player->profile.input_mem.len = 0;
7578 player->profile.input_mem.offset = 0;
7580 player->uri_info.uri_idx = 0;
7585 __mmplayer_check_subtitle(mm_player_t* player)
7587 MMHandleType attrs = 0;
7588 char *subtitle_uri = NULL;
7592 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7594 /* get subtitle attribute */
7595 attrs = MMPLAYER_GET_ATTRS(player);
7599 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7600 if (!subtitle_uri || !strlen(subtitle_uri))
7603 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7604 player->is_external_subtitle_present = TRUE;
7612 __mmplayer_cancel_eos_timer(mm_player_t* player)
7614 MMPLAYER_RETURN_IF_FAIL(player);
7616 if (player->eos_timer) {
7617 LOGD("cancel eos timer");
7618 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7619 player->eos_timer = 0;
7626 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7630 MMPLAYER_RETURN_IF_FAIL(player);
7631 MMPLAYER_RETURN_IF_FAIL(sink);
7633 player->sink_elements =
7634 g_list_append(player->sink_elements, sink);
7640 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7644 MMPLAYER_RETURN_IF_FAIL(player);
7645 MMPLAYER_RETURN_IF_FAIL(sink);
7647 player->sink_elements =
7648 g_list_remove(player->sink_elements, sink);
7654 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7655 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7657 MMPlayerSignalItem* item = NULL;
7660 MMPLAYER_RETURN_IF_FAIL(player);
7662 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7663 LOGE("invalid signal type [%d]", type);
7667 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7669 LOGE("cannot connect signal [%s]", signal);
7674 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7675 player->signals[type] = g_list_append(player->signals[type], item);
7681 /* NOTE : be careful with calling this api. please refer to below glib comment
7682 * glib comment : Note that there is a bug in GObject that makes this function much
7683 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7684 * will no longer be called, but, the signal handler is not currently disconnected.
7685 * If the instance is itself being freed at the same time than this doesn't matter,
7686 * since the signal will automatically be removed, but if instance persists,
7687 * then the signal handler will leak. You should not remove the signal yourself
7688 * because in a future versions of GObject, the handler will automatically be
7691 * It's possible to work around this problem in a way that will continue to work
7692 * with future versions of GObject by checking that the signal handler is still
7693 * connected before disconnected it:
7695 * if (g_signal_handler_is_connected(instance, id))
7696 * g_signal_handler_disconnect(instance, id);
7699 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7701 GList* sig_list = NULL;
7702 MMPlayerSignalItem* item = NULL;
7706 MMPLAYER_RETURN_IF_FAIL(player);
7708 LOGD("release signals type : %d", type);
7710 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7711 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7712 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7713 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7714 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7715 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7719 sig_list = player->signals[type];
7721 for (; sig_list; sig_list = sig_list->next) {
7722 item = sig_list->data;
7724 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7725 if (g_signal_handler_is_connected(item->obj, item->sig))
7726 g_signal_handler_disconnect(item->obj, item->sig);
7729 MMPLAYER_FREEIF(item);
7732 g_list_free(player->signals[type]);
7733 player->signals[type] = NULL;
7740 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7742 mm_player_t* player = 0;
7743 int prev_display_surface_type = 0;
7744 void *prev_display_overlay = NULL;
7748 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7749 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7751 player = MM_PLAYER_CAST(handle);
7753 /* check video sinkbin is created */
7754 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7755 LOGE("Videosink is already created");
7756 return MM_ERROR_NONE;
7759 LOGD("videosink element is not yet ready");
7761 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7762 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7764 return MM_ERROR_INVALID_ARGUMENT;
7767 /* load previous attributes */
7768 if (player->attrs) {
7769 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7770 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7771 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7772 if (prev_display_surface_type == surface_type) {
7773 LOGD("incoming display surface type is same as previous one, do nothing..");
7775 return MM_ERROR_NONE;
7778 LOGE("failed to load attributes");
7780 return MM_ERROR_PLAYER_INTERNAL;
7783 /* videobin is not created yet, so we just set attributes related to display surface */
7784 LOGD("store display attribute for given surface type(%d)", surface_type);
7785 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7786 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7787 if (mm_attrs_commit_all(player->attrs)) {
7788 LOGE("failed to commit attribute");
7790 return MM_ERROR_PLAYER_INTERNAL;
7794 return MM_ERROR_NONE;
7797 /* Note : if silent is true, then subtitle would not be displayed. :*/
7798 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7800 mm_player_t* player = (mm_player_t*) hplayer;
7804 /* check player handle */
7805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7807 player->set_mode.subtitle_off = silent;
7809 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7813 return MM_ERROR_NONE;
7816 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7818 MMPlayerGstElement* mainbin = NULL;
7819 MMPlayerGstElement* textbin = NULL;
7820 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7821 GstState current_state = GST_STATE_VOID_PENDING;
7822 GstState element_state = GST_STATE_VOID_PENDING;
7823 GstState element_pending_state = GST_STATE_VOID_PENDING;
7825 GstEvent *event = NULL;
7826 int result = MM_ERROR_NONE;
7828 GstClock *curr_clock = NULL;
7829 GstClockTime base_time, start_time, curr_time;
7834 /* check player handle */
7835 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7837 player->pipeline->mainbin &&
7838 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7840 mainbin = player->pipeline->mainbin;
7841 textbin = player->pipeline->textbin;
7843 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7845 // sync clock with current pipeline
7846 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7847 curr_time = gst_clock_get_time(curr_clock);
7849 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7850 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7852 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7853 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7855 if (current_state > GST_STATE_READY) {
7856 // sync state with current pipeline
7857 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7858 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7859 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7861 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7862 if (GST_STATE_CHANGE_FAILURE == ret) {
7863 LOGE("fail to state change.\n");
7864 result = MM_ERROR_PLAYER_INTERNAL;
7869 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7870 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7873 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7874 gst_object_unref(curr_clock);
7877 // seek to current position
7878 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7879 result = MM_ERROR_PLAYER_INVALID_STATE;
7880 LOGE("gst_element_query_position failed, invalid state\n");
7884 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7885 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);
7887 __mmplayer_gst_send_event_to_sink(player, event);
7889 result = MM_ERROR_PLAYER_INTERNAL;
7890 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7894 /* sync state with current pipeline */
7895 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7896 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7897 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7899 return MM_ERROR_NONE;
7902 /* release text pipeline resource */
7903 player->textsink_linked = 0;
7905 /* release signal */
7906 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7908 /* release textbin with it's childs */
7909 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7910 MMPLAYER_FREEIF(player->pipeline->textbin);
7911 player->pipeline->textbin = NULL;
7913 /* release subtitle elem */
7914 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7915 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7921 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7923 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7924 GstState current_state = GST_STATE_VOID_PENDING;
7926 MMHandleType attrs = 0;
7927 MMPlayerGstElement* mainbin = NULL;
7928 MMPlayerGstElement* textbin = NULL;
7930 gchar* subtitle_uri = NULL;
7931 int result = MM_ERROR_NONE;
7932 const gchar *charset = NULL;
7936 /* check player handle */
7937 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7939 player->pipeline->mainbin &&
7940 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7941 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7943 mainbin = player->pipeline->mainbin;
7944 textbin = player->pipeline->textbin;
7946 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7947 if (current_state < GST_STATE_READY) {
7948 result = MM_ERROR_PLAYER_INVALID_STATE;
7949 LOGE("Pipeline is not in proper state\n");
7953 attrs = MMPLAYER_GET_ATTRS(player);
7955 LOGE("cannot get content attribute\n");
7956 result = MM_ERROR_PLAYER_INTERNAL;
7960 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7961 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7962 LOGE("subtitle uri is not proper filepath\n");
7963 result = MM_ERROR_PLAYER_INVALID_URI;
7967 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7968 LOGE("failed to get storage info of subtitle path");
7969 result = MM_ERROR_PLAYER_INVALID_URI;
7973 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7974 LOGD("new subtitle file path is [%s]\n", filepath);
7976 if (!strcmp(filepath, subtitle_uri)) {
7977 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7980 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7981 if (mm_attrs_commit_all(player->attrs)) {
7982 LOGE("failed to commit.\n");
7987 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7988 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7989 player->subtitle_language_list = NULL;
7990 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7992 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7993 if (ret != GST_STATE_CHANGE_SUCCESS) {
7994 LOGE("failed to change state of textbin to READY");
7995 result = MM_ERROR_PLAYER_INTERNAL;
7999 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8000 if (ret != GST_STATE_CHANGE_SUCCESS) {
8001 LOGE("failed to change state of subparse to READY");
8002 result = MM_ERROR_PLAYER_INTERNAL;
8006 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8007 if (ret != GST_STATE_CHANGE_SUCCESS) {
8008 LOGE("failed to change state of filesrc to READY");
8009 result = MM_ERROR_PLAYER_INTERNAL;
8013 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8015 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8017 charset = util_get_charset(filepath);
8019 LOGD("detected charset is %s\n", charset);
8020 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8023 result = _mmplayer_sync_subtitle_pipeline(player);
8030 /* API to switch between external subtitles */
8031 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
8033 int result = MM_ERROR_NONE;
8034 mm_player_t* player = (mm_player_t*)hplayer;
8039 /* check player handle */
8040 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8042 /* filepath can be null in idle state */
8044 /* check file path */
8045 if ((path = strstr(filepath, "file://")))
8046 result = util_exist_file_path(path + 7);
8048 result = util_exist_file_path(filepath);
8050 if (result != MM_ERROR_NONE) {
8051 LOGE("invalid subtitle path 0x%X", result);
8052 return result; /* file not found or permission denied */
8056 if (!player->pipeline) {
8058 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8059 if (mm_attrs_commit_all(player->attrs)) {
8060 LOGE("failed to commit"); /* subtitle path will not be created */
8061 return MM_ERROR_PLAYER_INTERNAL;
8064 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8065 /* check filepath */
8066 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8068 if (!__mmplayer_check_subtitle(player)) {
8069 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8070 if (mm_attrs_commit_all(player->attrs)) {
8071 LOGE("failed to commit");
8072 return MM_ERROR_PLAYER_INTERNAL;
8075 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8076 LOGE("fail to create text pipeline");
8077 return MM_ERROR_PLAYER_INTERNAL;
8080 result = _mmplayer_sync_subtitle_pipeline(player);
8082 result = __mmplayer_change_external_subtitle_language(player, filepath);
8085 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8086 player->is_external_subtitle_added_now = TRUE;
8088 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8089 if (!player->subtitle_language_list) {
8090 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8091 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8092 LOGW("subtitle language list is not updated yet");
8094 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8102 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8104 int result = MM_ERROR_NONE;
8105 gchar* change_pad_name = NULL;
8106 GstPad* sinkpad = NULL;
8107 MMPlayerGstElement* mainbin = NULL;
8108 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8109 GstCaps* caps = NULL;
8110 gint total_track_num = 0;
8114 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8115 MM_ERROR_PLAYER_NOT_INITIALIZED);
8117 LOGD("Change Track(%d) to %d\n", type, index);
8119 mainbin = player->pipeline->mainbin;
8121 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8122 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8123 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8124 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8126 /* Changing Video Track is not supported. */
8127 LOGE("Track Type Error\n");
8131 if (mainbin[elem_idx].gst == NULL) {
8132 result = MM_ERROR_PLAYER_NO_OP;
8133 LOGD("Req track doesn't exist\n");
8137 total_track_num = player->selector[type].total_track_num;
8138 if (total_track_num <= 0) {
8139 result = MM_ERROR_PLAYER_NO_OP;
8140 LOGD("Language list is not available \n");
8144 if ((index < 0) || (index >= total_track_num)) {
8145 result = MM_ERROR_INVALID_ARGUMENT;
8146 LOGD("Not a proper index : %d \n", index);
8150 /*To get the new pad from the selector*/
8151 change_pad_name = g_strdup_printf("sink_%u", index);
8152 if (change_pad_name == NULL) {
8153 result = MM_ERROR_PLAYER_INTERNAL;
8154 LOGD("Pad does not exists\n");
8158 LOGD("new active pad name: %s\n", change_pad_name);
8160 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8161 if (sinkpad == NULL) {
8162 LOGD("sinkpad is NULL");
8163 result = MM_ERROR_PLAYER_INTERNAL;
8167 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8168 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8170 caps = gst_pad_get_current_caps(sinkpad);
8171 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8174 gst_object_unref(sinkpad);
8176 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8177 __mmplayer_set_audio_attrs(player, caps);
8181 MMPLAYER_FREEIF(change_pad_name);
8185 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8187 int result = MM_ERROR_NONE;
8188 mm_player_t* player = NULL;
8189 MMPlayerGstElement* mainbin = NULL;
8191 gint current_active_index = 0;
8193 GstState current_state = GST_STATE_VOID_PENDING;
8194 GstEvent* event = NULL;
8199 player = (mm_player_t*)hplayer;
8200 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8202 if (!player->pipeline) {
8203 LOGE("Track %d pre setting -> %d\n", type, index);
8205 player->selector[type].active_pad_index = index;
8209 mainbin = player->pipeline->mainbin;
8211 current_active_index = player->selector[type].active_pad_index;
8213 /*If index is same as running index no need to change the pad*/
8214 if (current_active_index == index)
8217 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8218 result = MM_ERROR_PLAYER_INVALID_STATE;
8222 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8223 if (current_state < GST_STATE_PAUSED) {
8224 result = MM_ERROR_PLAYER_INVALID_STATE;
8225 LOGW("Pipeline not in porper state\n");
8229 result = __mmplayer_change_selector_pad(player, type, index);
8230 if (result != MM_ERROR_NONE) {
8231 LOGE("change selector pad error\n");
8235 player->selector[type].active_pad_index = index;
8237 if (current_state == GST_STATE_PLAYING) {
8238 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8240 __mmplayer_gst_send_event_to_sink(player, event);
8242 result = MM_ERROR_PLAYER_INTERNAL;
8251 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8253 mm_player_t* player = (mm_player_t*) hplayer;
8257 /* check player handle */
8258 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8260 *silent = player->set_mode.subtitle_off;
8262 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8266 return MM_ERROR_NONE;
8270 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8272 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8273 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8275 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8276 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8280 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8281 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8282 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8283 mm_player_dump_t *dump_s;
8284 dump_s = g_malloc(sizeof(mm_player_dump_t));
8286 if (dump_s == NULL) {
8287 LOGE("malloc fail");
8291 dump_s->dump_element_file = NULL;
8292 dump_s->dump_pad = NULL;
8293 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8295 if (dump_s->dump_pad) {
8296 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8297 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]);
8298 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8299 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);
8300 /* add list for removed buffer probe and close FILE */
8301 player->dump_list = g_list_append(player->dump_list, dump_s);
8302 LOGD("%s sink pad added buffer probe for dump", factory_name);
8307 LOGE("failed to get %s sink pad added", factory_name);
8314 static GstPadProbeReturn
8315 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8317 FILE *dump_data = (FILE *) u_data;
8319 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8320 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8322 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8324 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8326 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8328 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8330 return GST_PAD_PROBE_OK;
8334 __mmplayer_release_dump_list(GList *dump_list)
8337 GList *d_list = dump_list;
8338 for (; d_list; d_list = g_list_next(d_list)) {
8339 mm_player_dump_t *dump_s = d_list->data;
8340 if (dump_s->dump_pad) {
8341 if (dump_s->probe_handle_id)
8342 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8344 if (dump_s->dump_element_file) {
8345 fclose(dump_s->dump_element_file);
8346 dump_s->dump_element_file = NULL;
8348 MMPLAYER_FREEIF(dump_s);
8350 g_list_free(dump_list);
8356 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8358 mm_player_t* player = (mm_player_t*) hplayer;
8362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8363 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8365 *exist = player->has_closed_caption;
8369 return MM_ERROR_NONE;
8372 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8376 // LOGD("unref internal gst buffer %p", buffer);
8377 gst_buffer_unref((GstBuffer *)buffer);
8383 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8385 mm_player_t* player = (mm_player_t*) hplayer;
8389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8390 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8392 if (MMPLAYER_IS_HTTP_PD(player))
8393 /* consider the timeout both download pipeline and playback pipeline */
8394 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8395 else if (MMPLAYER_IS_STREAMING(player))
8396 *timeout = player->ini.live_state_change_timeout;
8398 *timeout = player->ini.localplayback_state_change_timeout;
8400 LOGD("timeout = %d\n", *timeout);
8403 return MM_ERROR_NONE;
8406 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8408 mm_player_t* player = (mm_player_t*) hplayer;
8412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8413 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8415 *num = player->video_num_buffers;
8416 *extra_num = player->video_extra_num_buffers;
8418 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8421 return MM_ERROR_NONE;
8425 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8429 MMPLAYER_RETURN_IF_FAIL(player);
8431 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8433 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8434 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8435 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8436 player->storage_info[i].id = -1;
8437 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8439 if (path_type != MMPLAYER_PATH_MAX)
8447 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8449 int ret = MM_ERROR_NONE;
8450 mm_player_t* player = (mm_player_t*)hplayer;
8451 MMMessageParamType msg_param = {0, };
8454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8456 LOGW("state changed storage %d:%d", id, state);
8458 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8459 return MM_ERROR_NONE;
8461 /* FIXME: text path should be handled seperately. */
8462 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8463 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8464 LOGW("external storage is removed");
8466 if (player->msg_posted == FALSE) {
8467 memset(&msg_param, 0, sizeof(MMMessageParamType));
8468 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8469 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8470 player->msg_posted = TRUE;
8473 /* unrealize the player */
8474 ret = _mmplayer_unrealize(hplayer);
8475 if (ret != MM_ERROR_NONE)
8476 LOGE("failed to unrealize");
8483 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8485 int ret = MM_ERROR_NONE;
8486 mm_player_t* player = (mm_player_t*) hplayer;
8487 int idx = 0, total = 0;
8488 gchar *result = NULL, *tmp = NULL;
8491 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8492 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8494 total = *num = g_list_length(player->adaptive_info.var_list);
8496 LOGW("There is no stream variant info.");
8500 result = g_strdup("");
8501 for (idx = 0 ; idx < total ; idx++) {
8502 VariantData *v_data = NULL;
8503 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8506 gchar data[64] = {0};
8507 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8509 tmp = g_strconcat(result, data, NULL);
8513 LOGW("There is no variant data in %d", idx);
8518 *var_info = (char *)result;
8520 LOGD("variant info %d:%s", *num, *var_info);
8525 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8527 int ret = MM_ERROR_NONE;
8528 mm_player_t* player = (mm_player_t*) hplayer;
8531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8533 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8535 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8536 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8537 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8539 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8540 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8541 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8542 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8544 /* FIXME: seek to current position for applying new variant limitation */
8552 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8554 int ret = MM_ERROR_NONE;
8555 mm_player_t* player = (mm_player_t*) hplayer;
8558 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8559 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8561 *bandwidth = player->adaptive_info.limit.bandwidth;
8562 *width = player->adaptive_info.limit.width;
8563 *height = player->adaptive_info.limit.height;
8565 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8571 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8573 int ret = MM_ERROR_NONE;
8574 mm_player_t* player = (mm_player_t*) hplayer;
8577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8579 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8580 LOGW("buffer_ms will not be applied.");
8583 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8585 if (player->streamer == NULL) {
8586 player->streamer = __mm_player_streaming_create();
8587 __mm_player_streaming_initialize(player->streamer);
8591 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8593 if (rebuffer_ms >= 0)
8594 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8601 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8603 int ret = MM_ERROR_NONE;
8604 mm_player_t* player = (mm_player_t*) hplayer;
8607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8608 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8610 if (player->streamer == NULL) {
8611 player->streamer = __mm_player_streaming_create();
8612 __mm_player_streaming_initialize(player->streamer);
8615 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8616 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8618 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8624 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8626 #define IDX_FIRST_SW_CODEC 0
8627 mm_player_t* player = (mm_player_t*) hplayer;
8628 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8629 MMHandleType attrs = 0;
8632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8634 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8635 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8636 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8638 switch (stream_type) {
8639 case MM_PLAYER_STREAM_TYPE_AUDIO:
8640 /* to support audio codec selection, codec info have to be added in ini file as below.
8641 audio codec element hw = xxxx
8642 audio codec element sw = avdec */
8643 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8644 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8645 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8646 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8647 LOGE("There is no audio codec info for codec_type %d", codec_type);
8648 return MM_ERROR_PLAYER_NO_OP;
8651 case MM_PLAYER_STREAM_TYPE_VIDEO:
8652 /* to support video codec selection, codec info have to be added in ini file as below.
8653 video codec element hw = omx
8654 video codec element sw = avdec */
8655 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8656 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8657 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8658 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8659 LOGE("There is no video codec info for codec_type %d", codec_type);
8660 return MM_ERROR_PLAYER_NO_OP;
8664 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8665 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8669 LOGD("update %s codec_type to %d", attr_name, codec_type);
8671 attrs = MMPLAYER_GET_ATTRS(player);
8672 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8674 if (mm_attrs_commit_all(player->attrs)) {
8675 LOGE("failed to commit codec_type attributes");
8676 return MM_ERROR_PLAYER_INTERNAL;
8680 return MM_ERROR_NONE;
8684 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8686 mm_player_t* player = (mm_player_t*) hplayer;
8687 GstElement* rg_vol_element = NULL;
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8693 player->sound.rg_enable = enabled;
8695 /* just hold rgvolume enable value if pipeline is not ready */
8696 if (!player->pipeline || !player->pipeline->audiobin) {
8697 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8698 return MM_ERROR_NONE;
8701 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8703 if (!rg_vol_element) {
8704 LOGD("rgvolume element is not created");
8705 return MM_ERROR_PLAYER_INTERNAL;
8709 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8711 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8715 return MM_ERROR_NONE;
8719 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8721 mm_player_t* player = (mm_player_t*) hplayer;
8722 GstElement* rg_vol_element = NULL;
8723 gboolean enable = FALSE;
8727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8728 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8730 /* just hold enable_rg value if pipeline is not ready */
8731 if (!player->pipeline || !player->pipeline->audiobin) {
8732 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8733 *enabled = player->sound.rg_enable;
8734 return MM_ERROR_NONE;
8737 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8739 if (!rg_vol_element) {
8740 LOGD("rgvolume element is not created");
8741 return MM_ERROR_PLAYER_INTERNAL;
8744 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8749 return MM_ERROR_NONE;
8753 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8755 mm_player_t* player = (mm_player_t*) hplayer;
8756 MMHandleType attrs = 0;
8757 void *handle = NULL;
8758 int ret = MM_ERROR_NONE;
8762 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8764 attrs = MMPLAYER_GET_ATTRS(player);
8765 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8767 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8769 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8770 return MM_ERROR_PLAYER_INTERNAL;
8773 player->video_roi.scale_x = scale_x;
8774 player->video_roi.scale_y = scale_y;
8775 player->video_roi.scale_width = scale_width;
8776 player->video_roi.scale_height = scale_height;
8778 /* check video sinkbin is created */
8779 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8780 return MM_ERROR_NONE;
8782 if (!gst_video_overlay_set_video_roi_area(
8783 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8784 scale_x, scale_y, scale_width, scale_height))
8785 ret = MM_ERROR_PLAYER_INTERNAL;
8787 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8788 scale_x, scale_y, scale_width, scale_height);
8796 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8798 mm_player_t* player = (mm_player_t*) hplayer;
8799 int ret = MM_ERROR_NONE;
8803 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8804 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8806 *scale_x = player->video_roi.scale_x;
8807 *scale_y = player->video_roi.scale_y;
8808 *scale_width = player->video_roi.scale_width;
8809 *scale_height = player->video_roi.scale_height;
8811 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8812 *scale_x, *scale_y, *scale_width, *scale_height);
8818 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8820 gboolean ret = FALSE;
8821 gint64 dur_nsec = 0;
8822 LOGD("try to update duration");
8824 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8825 player->duration = dur_nsec;
8826 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8830 if (player->duration < 0) {
8831 LOGW("duration is Non-Initialized !!!");
8832 player->duration = 0;
8835 /* update streaming service type */
8836 player->streaming_type = __mmplayer_get_stream_service_type(player);
8838 /* check duration is OK */
8839 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8840 /* FIXIT : find another way to get duration here. */
8841 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8848 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8850 /* update audio params
8851 NOTE : We need original audio params and it can be only obtained from src pad of audio
8852 decoder. Below code only valid when we are not using 'resampler' just before
8853 'audioconverter'. */
8854 GstCaps *caps_a = NULL;
8856 gint samplerate = 0, channels = 0;
8857 GstStructure* p = NULL;
8859 LOGD("try to update audio attrs");
8861 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8862 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8864 pad = gst_element_get_static_pad(
8865 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8868 LOGW("failed to get pad from audiosink");
8872 caps_a = gst_pad_get_current_caps(pad);
8875 LOGW("not ready to get audio caps");
8876 gst_object_unref(pad);
8880 p = gst_caps_get_structure(caps_a, 0);
8882 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8884 gst_structure_get_int(p, "rate", &samplerate);
8885 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8887 gst_structure_get_int(p, "channels", &channels);
8888 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8890 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8892 gst_caps_unref(caps_a);
8893 gst_object_unref(pad);
8899 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8901 LOGD("try to update video attrs");
8903 GstCaps *caps_v = NULL;
8907 GstStructure* p = NULL;
8909 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8910 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8912 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8914 LOGD("no videosink sink pad");
8918 caps_v = gst_pad_get_current_caps(pad);
8919 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8920 if (!caps_v && player->v_stream_caps) {
8921 caps_v = player->v_stream_caps;
8922 gst_caps_ref(caps_v);
8926 LOGD("no negitiated caps from videosink");
8927 gst_object_unref(pad);
8931 p = gst_caps_get_structure(caps_v, 0);
8932 gst_structure_get_int(p, "width", &width);
8933 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8935 gst_structure_get_int(p, "height", &height);
8936 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8938 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8940 SECURE_LOGD("width : %d height : %d", width, height);
8942 gst_caps_unref(caps_v);
8943 gst_object_unref(pad);
8946 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8947 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8954 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8956 gboolean ret = FALSE;
8957 guint64 data_size = 0;
8961 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8962 if (!player->duration)
8965 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8966 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8967 if (stat(path, &sb) == 0)
8968 data_size = (guint64)sb.st_size;
8970 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8971 data_size = player->http_content_size;
8974 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8977 guint64 bitrate = 0;
8978 guint64 msec_dur = 0;
8980 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8982 bitrate = data_size * 8 * 1000 / msec_dur;
8983 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
8984 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8988 LOGD("player duration is less than 0");
8992 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8993 if (player->total_bitrate) {
8994 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9002 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
9004 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9005 data->uri_type = uri_type;
9008 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
9010 int ret = MM_ERROR_PLAYER_INVALID_URI;
9012 char *buffer = NULL;
9013 char *seperator = strchr(path, ',');
9014 char ext[100] = {0,}, size[100] = {0,};
9017 if ((buffer = strstr(path, "ext="))) {
9018 buffer += strlen("ext=");
9020 if (strlen(buffer)) {
9021 strncpy(ext, buffer, 99);
9023 if ((seperator = strchr(ext, ','))
9024 || (seperator = strchr(ext, ' '))
9025 || (seperator = strchr(ext, '\0'))) {
9026 seperator[0] = '\0';
9031 if ((buffer = strstr(path, "size="))) {
9032 buffer += strlen("size=");
9034 if (strlen(buffer) > 0) {
9035 strncpy(size, buffer, 99);
9037 if ((seperator = strchr(size, ','))
9038 || (seperator = strchr(size, ' '))
9039 || (seperator = strchr(size, '\0'))) {
9040 seperator[0] = '\0';
9043 mem_size = atoi(size);
9048 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
9050 if (mem_size && param) {
9051 if (data->input_mem.buf)
9052 free(data->input_mem.buf);
9053 data->input_mem.buf = malloc(mem_size);
9055 if (data->input_mem.buf) {
9056 memcpy(data->input_mem.buf, param, mem_size);
9057 data->input_mem.len = mem_size;
9058 ret = MM_ERROR_NONE;
9060 LOGE("failed to alloc mem %d", mem_size);
9061 ret = MM_ERROR_PLAYER_INTERNAL;
9064 data->input_mem.offset = 0;
9065 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9072 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9074 gchar *location = NULL;
9077 int ret = MM_ERROR_NONE;
9079 if ((path = strstr(uri, "file://"))) {
9080 location = g_filename_from_uri(uri, NULL, &err);
9081 if (!location || (err != NULL)) {
9082 LOGE("Invalid URI '%s' for filesrc: %s", path,
9083 (err != NULL) ? err->message : "unknown error");
9089 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9090 return MM_ERROR_PLAYER_INVALID_URI;
9092 LOGD("path from uri: %s", location);
9095 path = (location != NULL) ? (location) : ((char *)uri);
9098 ret = util_exist_file_path(path);
9100 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9101 if (ret == MM_ERROR_NONE) {
9102 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9103 if (util_is_sdp_file(path)) {
9104 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9105 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9107 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9109 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9110 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9112 LOGE("invalid uri, could not play..\n");
9113 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9122 static MMPlayerVideoStreamDataType*
9123 __mmplayer_create_stream_from_pad(GstPad *pad)
9125 GstCaps *caps = NULL;
9126 GstStructure *structure = NULL;
9127 unsigned int fourcc = 0;
9128 const gchar *string_format = NULL;
9129 MMPlayerVideoStreamDataType *stream = NULL;
9131 MMPixelFormatType format;
9133 caps = gst_pad_get_current_caps(pad);
9135 LOGE("Caps is NULL.");
9139 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9140 structure = gst_caps_get_structure(caps, 0);
9141 gst_structure_get_int(structure, "width", &width);
9142 gst_structure_get_int(structure, "height", &height);
9143 string_format = gst_structure_get_string(structure, "format");
9145 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9146 format = util_get_pixtype(fourcc);
9147 gst_caps_unref(caps);
9150 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9151 LOGE("Wrong condition!!");
9155 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9157 LOGE("failed to alloc mem for video data");
9161 stream->width = width;
9162 stream->height = height;
9163 stream->format = format;
9169 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9171 unsigned int pitch = 0;
9173 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9175 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9176 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9177 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9178 stream->stride[index] = pitch;
9179 stream->elevation[index] = stream->height;
9184 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9186 if (stream->format == MM_PIXEL_FORMAT_I420) {
9187 int ret = TBM_SURFACE_ERROR_NONE;
9188 tbm_surface_h surface;
9189 tbm_surface_info_s info;
9191 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9193 ret = tbm_surface_get_info(surface, &info);
9194 if (ret != TBM_SURFACE_ERROR_NONE) {
9195 tbm_surface_destroy(surface);
9199 tbm_surface_destroy(surface);
9200 stream->stride[0] = info.planes[0].stride;
9201 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9202 stream->stride[1] = info.planes[1].stride;
9203 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9204 stream->stride[2] = info.planes[2].stride;
9205 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9206 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9207 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9208 stream->stride[0] = stream->width * 4;
9209 stream->elevation[0] = stream->height;
9210 stream->bo_size = stream->stride[0] * stream->height;
9212 LOGE("Not support format %d", stream->format);
9220 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9222 tbm_bo_handle thandle;
9224 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9225 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9226 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9230 unsigned char *src = NULL;
9231 unsigned char *dest = NULL;
9232 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9234 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9236 LOGE("fail to gst_memory_map");
9240 if (!mapinfo.data) {
9241 LOGE("data pointer is wrong");
9245 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9246 if (!stream->bo[0]) {
9247 LOGE("Fail to tbm_bo_alloc!!");
9251 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9253 LOGE("thandle pointer is wrong");
9257 if (stream->format == MM_PIXEL_FORMAT_I420) {
9258 src_stride[0] = GST_ROUND_UP_4(stream->width);
9259 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9260 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9261 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9264 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9265 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9267 for (i = 0; i < 3; i++) {
9268 src = mapinfo.data + src_offset[i];
9269 dest = thandle.ptr + dest_offset[i];
9274 for (j = 0; j < stream->height >> k; j++) {
9275 memcpy(dest, src, stream->width>>k);
9276 src += src_stride[i];
9277 dest += stream->stride[i];
9280 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9281 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9283 LOGE("Not support format %d", stream->format);
9287 tbm_bo_unmap(stream->bo[0]);
9288 gst_memory_unmap(mem, &mapinfo);
9294 tbm_bo_unmap(stream->bo[0]);
9297 gst_memory_unmap(mem, &mapinfo);
9303 __mmplayer_set_pause_state(mm_player_t *player)
9305 if (player->sent_bos)
9308 /* rtsp case, get content attrs by GstMessage */
9309 if (MMPLAYER_IS_RTSP_STREAMING(player))
9312 /* it's first time to update all content attrs. */
9313 __mmplayer_update_content_attrs(player, ATTR_ALL);
9317 __mmplayer_set_playing_state(mm_player_t *player)
9319 gchar *audio_codec = NULL;
9321 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9322 /* initialize because auto resume is done well. */
9323 player->resumed_by_rewind = FALSE;
9324 player->playback_rate = 1.0;
9327 if (player->sent_bos)
9330 /* try to get content metadata */
9332 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9333 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9334 * legacy mmfw-player api
9336 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9338 if ((player->cmd == MMPLAYER_COMMAND_START)
9339 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9340 __mmplayer_handle_missed_plugin(player);
9343 /* check audio codec field is set or not
9344 * we can get it from typefinder or codec's caps.
9346 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9348 /* The codec format can't be sent for audio only case like amr, mid etc.
9349 * Because, parser don't make related TAG.
9350 * So, if it's not set yet, fill it with found data.
9353 if (g_strrstr(player->type, "audio/midi"))
9354 audio_codec = "MIDI";
9355 else if (g_strrstr(player->type, "audio/x-amr"))
9356 audio_codec = "AMR";
9357 else if (g_strrstr(player->type, "audio/mpeg")
9358 && !g_strrstr(player->type, "mpegversion= (int)1"))
9359 audio_codec = "AAC";
9361 audio_codec = "unknown";
9363 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9365 if (mm_attrs_commit_all(player->attrs))
9366 LOGE("failed to update attributes\n");
9368 LOGD("set audio codec type with caps\n");