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 if (player->v_stream_caps) {
1012 gst_caps_unref(player->v_stream_caps);
1013 player->v_stream_caps = NULL;
1015 if (player->ini.set_dump_element_flag)
1016 __mmplayer_add_dump_buffer_probe(player, fakesink);
1019 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1020 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1024 gst_object_unref(GST_OBJECT(sinkpad));
1031 __mmplayer_gst_make_selector(mm_player_t *player, enum MainElementID elem_idx, MMPlayerTrackType stream_type)
1033 GstElement *pipeline = NULL;
1034 GstElement *selector = NULL;
1035 GstPad *srcpad = NULL;
1038 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1040 selector = gst_element_factory_make("input-selector", NULL);
1042 LOGE("failed to create input-selector");
1045 g_object_set(selector, "sync-streams", TRUE, NULL);
1047 player->pipeline->mainbin[elem_idx].id = elem_idx;
1048 player->pipeline->mainbin[elem_idx].gst = selector;
1050 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1052 srcpad = gst_element_get_static_pad(selector, "src");
1054 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1055 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1056 __mmplayer_gst_selector_blocked, NULL, NULL);
1057 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1058 __mmplayer_gst_selector_event_probe, player, NULL);
1060 gst_element_set_state(selector, GST_STATE_PAUSED);
1062 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1063 gst_bin_add(GST_BIN(pipeline), selector);
1070 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1072 mm_player_t *player = NULL;
1073 GstElement *selector = NULL;
1074 GstCaps *caps = NULL;
1075 GstStructure *str = NULL;
1076 const gchar *name = NULL;
1077 GstPad *sinkpad = NULL;
1078 GstPad *srcpad = NULL;
1079 gboolean first_track = FALSE;
1080 gboolean caps_ret = TRUE;
1082 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1083 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1086 player = (mm_player_t*)data;
1089 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1090 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1092 LOGD("pad-added signal handling");
1094 /* get mimetype from caps */
1095 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1099 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1100 /* LOGD("detected mimetype : %s", name); */
1102 if (strstr(name, "video")) {
1104 gchar *caps_str = NULL;
1106 caps_str = gst_caps_to_string(caps);
1107 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1108 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1109 player->set_mode.video_zc = TRUE;
1111 MMPLAYER_FREEIF(caps_str);
1113 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1114 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1116 LOGD("surface type : %d", stype);
1118 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1119 __mmplayer_gst_create_sinkbin(elem, pad, player);
1123 /* in case of exporting video frame, it requires the 360 video filter.
1124 * it will be handled in _no_more_pads(). */
1125 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
1126 __mmplayer_gst_make_fakesink(player, pad, name);
1130 LOGD("video selector is required");
1131 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1132 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1133 } else if (strstr(name, "audio")) {
1134 gint samplerate = 0;
1137 gst_structure_get_int(str, "rate", &samplerate);
1138 gst_structure_get_int(str, "channels", &channels);
1140 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1141 __mmplayer_gst_create_sinkbin(elem, pad, player);
1145 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1146 __mmplayer_gst_make_fakesink(player, pad, name);
1150 LOGD("audio selector is required");
1151 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1152 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1154 } else if (strstr(name, "text")) {
1155 LOGD("text selector is required");
1156 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1157 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1159 LOGE("invalid caps info");
1163 /* check selector and create it */
1164 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1165 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1170 LOGD("input-selector is already created.");
1174 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1176 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1178 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1179 LOGE("failed to link selector");
1180 gst_object_unref(GST_OBJECT(selector));
1185 LOGD("this track will be activated");
1186 g_object_set(selector, "active-pad", sinkpad, NULL);
1189 __mmplayer_track_update_info(player, stream_type, sinkpad);
1195 gst_caps_unref(caps);
1198 gst_object_unref(GST_OBJECT(sinkpad));
1203 gst_object_unref(GST_OBJECT(srcpad));
1210 static gboolean __mmplayer_create_sink_path(mm_player_t* player, GstElement* selector, MMPlayerTrackType type)
1212 GstPad* srcpad = NULL;
1215 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1217 LOGD("type %d", type);
1220 LOGD("there is no %d track", type);
1224 srcpad = gst_element_get_static_pad(selector, "src");
1226 LOGE("failed to get srcpad from selector");
1230 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1232 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1234 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1235 if (player->selector[type].block_id) {
1236 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1237 player->selector[type].block_id = 0;
1241 gst_object_unref(GST_OBJECT(srcpad));
1249 static void __mmplayer_set_decode_track_info(mm_player_t* player, MMPlayerTrackType type)
1251 MMHandleType attrs = 0;
1252 gint active_index = 0;
1253 gchar *attr_name = NULL;
1256 MMPLAYER_RETURN_IF_FAIL(player);
1258 LOGD("type %d", type);
1260 /* change track to active pad */
1261 active_index = player->selector[type].active_pad_index;
1262 if ((active_index != DEFAULT_TRACK) &&
1263 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1264 LOGW("failed to change %d type track to %d", type, active_index);
1265 player->selector[type].active_pad_index = DEFAULT_TRACK;
1268 LOGD("Total num of tracks = %d", player->selector[type].total_track_num);
1270 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
1271 attr_name = "content_audio_track_num";
1272 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1273 attr_name = "content_text_track_num";
1275 LOGE("invalid type info %d", type);
1279 attrs = MMPLAYER_GET_ATTRS(player);
1281 mm_attrs_set_int_by_name(attrs, attr_name, (gint)player->selector[type].total_track_num);
1282 if (mm_attrs_commit_all(attrs))
1283 LOGW("failed to commit attrs.");
1285 LOGW("cannot get content attribute");
1292 static gboolean __mmplayer_create_audio_sink_path(mm_player_t* player, GstElement* audio_selector)
1295 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1297 if (!audio_selector) {
1298 LOGD("there is no audio track");
1300 /* in case the source is changed, output can be changed. */
1301 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1302 LOGD("remove previous audiobin if it exist");
1304 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1305 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1307 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1308 MMPLAYER_FREEIF(player->pipeline->audiobin);
1311 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1312 __mmplayer_pipeline_complete(NULL, player);
1317 /* apply the audio track information */
1318 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1320 /* create audio sink path */
1321 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1322 LOGE("failed to create audio sink path");
1330 static gboolean __mmplayer_create_text_sink_path(mm_player_t* player, GstElement* text_selector)
1333 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1335 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1336 LOGD("text path is not supproted");
1340 /* apply the text track information */
1341 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1343 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1344 player->has_closed_caption = TRUE;
1346 /* create text decode path */
1347 player->no_more_pad = TRUE;
1349 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1350 LOGE("failed to create text sink path");
1359 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1361 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1363 gint init_buffering_time = 0;
1364 guint buffer_bytes = 0;
1365 gint64 dur_bytes = 0L;
1368 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1369 player->pipeline->mainbin && player->streamer, FALSE);
1371 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1372 buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1374 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1375 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1377 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1379 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1380 LOGE("fail to get duration.");
1382 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1383 * use file information was already set on Q2 when it was created. */
1384 __mm_player_streaming_set_queue2(player->streamer,
1385 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1386 TRUE, /* use_buffering */
1388 init_buffering_time,
1389 1.0, /* low percent */
1390 player->ini.http_buffering_limit, /* high percent */
1391 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1393 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1400 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1402 mm_player_t *player = NULL;
1403 GstElement *video_selector = NULL;
1404 GstElement *audio_selector = NULL;
1405 GstElement *text_selector = NULL;
1408 player = (mm_player_t*) data;
1410 LOGD("no-more-pad signal handling");
1412 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1413 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1414 LOGW("player is shutting down");
1418 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
1419 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
1420 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1421 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1422 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1423 LOGE("failed to set queue2 buffering");
1428 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1429 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1430 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1432 /* create video path followed by video-select */
1433 if (video_selector && !audio_selector && !text_selector)
1434 player->no_more_pad = TRUE;
1436 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1439 /* create audio path followed by audio-select */
1440 if (audio_selector && !text_selector)
1441 player->no_more_pad = TRUE;
1443 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1447 /* create text path followed by text-select */
1448 __mmplayer_create_text_sink_path(player, text_selector);
1451 if (player->gapless.reconfigure) {
1452 player->gapless.reconfigure = FALSE;
1453 MMPLAYER_PLAYBACK_UNLOCK(player);
1460 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1462 gboolean ret = FALSE;
1463 GstElement *pipeline = NULL;
1464 GstPad *sinkpad = NULL;
1467 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1468 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1470 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1472 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1474 LOGE("failed to get pad from sinkbin");
1480 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1481 LOGE("failed to link sinkbin for reusing");
1482 goto EXIT; /* exit either pass or fail */
1486 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1487 LOGE("failed to set state(READY) to sinkbin");
1492 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1493 LOGE("failed to add sinkbin to pipeline");
1498 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1499 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1504 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1505 LOGE("failed to set state(PAUSED) to sinkbin");
1514 gst_object_unref(GST_OBJECT(sinkpad));
1521 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1523 mm_player_t *player = NULL;
1524 MMHandleType attrs = 0;
1525 GstCaps *caps = NULL;
1526 gchar *caps_str = NULL;
1527 GstStructure *str = NULL;
1528 const gchar *name = NULL;
1529 GstElement *sinkbin = NULL;
1530 gboolean reusing = FALSE;
1531 gboolean caps_ret = TRUE;
1532 gchar *sink_pad_name = "sink";
1535 player = (mm_player_t*) data;
1538 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1539 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1541 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1545 caps_str = gst_caps_to_string(caps);
1547 /* LOGD("detected mimetype : %s", name); */
1548 if (strstr(name, "audio")) {
1549 if (player->pipeline->audiobin == NULL) {
1550 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1551 LOGE("failed to create audiobin. continuing without audio");
1555 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1556 LOGD("creating audiobin success");
1559 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1560 LOGD("reusing audiobin");
1561 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1563 } else if (strstr(name, "video")) {
1564 /* 1. zero copy is updated at _decode_pad_added()
1565 * 2. NULL surface type is handled in _decode_pad_added() */
1566 LOGD("zero copy %d", player->set_mode.video_zc);
1567 if (player->pipeline->videobin == NULL) {
1568 int surface_type = 0;
1569 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1570 LOGD("display_surface_type (%d)", surface_type);
1572 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1573 LOGD("mark video overlay for acquire");
1574 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1575 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1576 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1577 &player->video_overlay_resource)
1578 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1579 LOGE("could not mark video_overlay resource for acquire");
1584 player->interrupted_by_resource = FALSE;
1586 if (mm_resource_manager_commit(player->resource_manager) !=
1587 MM_RESOURCE_MANAGER_ERROR_NONE) {
1588 LOGE("could not acquire resources for video playing");
1592 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1593 LOGE("failed to create videobin. continuing without video");
1597 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1598 LOGD("creating videosink bin success");
1601 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1602 LOGD("re-using videobin");
1603 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1605 } else if (strstr(name, "text")) {
1606 if (player->pipeline->textbin == NULL) {
1607 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1608 LOGE("failed to create text sink bin. continuing without text");
1612 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1613 LOGD("creating textsink bin success");
1615 mm_attrs_set_int_by_name(attrs, "content_text_track_num", 1);
1616 player->textsink_linked = 1;
1619 if (!player->textsink_linked) {
1620 LOGD("re-using textbin");
1622 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1623 player->textsink_linked = 1;
1625 /* linked textbin exist which means that the external subtitle path exist already */
1626 LOGW("ignoring internal subtutle since external subtitle is available");
1629 sink_pad_name = "text_sink";
1631 LOGW("unknown mime type %s, ignoring it", name);
1635 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1638 LOGD("[handle: %p] success to create and link sink bin", player);
1640 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1641 * streaming task. if the task blocked, then buffer will not flow to the next element
1642 *(autoplugging element). so this is special hack for streaming. please try to remove it
1644 /* dec stream count. we can remove fakesink if it's zero */
1645 if (player->num_dynamic_pad)
1646 player->num_dynamic_pad--;
1648 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1650 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1651 __mmplayer_pipeline_complete(NULL, player);
1655 MMPLAYER_FREEIF(caps_str);
1658 gst_caps_unref(caps);
1660 /* flusing out new attributes */
1661 if (mm_attrs_commit_all(attrs))
1662 LOGE("failed to comit attributes");
1668 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1670 int required_angle = 0; /* Angle required for straight view */
1671 int rotation_angle = 0;
1673 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1674 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1676 /* Counter clockwise */
1677 switch (orientation) {
1682 required_angle = 270;
1685 required_angle = 180;
1688 required_angle = 90;
1692 rotation_angle = display_angle + required_angle;
1693 if (rotation_angle >= 360)
1694 rotation_angle -= 360;
1696 /* chech if supported or not */
1697 if (rotation_angle % 90) {
1698 LOGD("not supported rotation angle = %d", rotation_angle);
1702 switch (rotation_angle) {
1704 *value = MM_DISPLAY_ROTATION_NONE;
1707 *value = MM_DISPLAY_ROTATION_90;
1710 *value = MM_DISPLAY_ROTATION_180;
1713 *value = MM_DISPLAY_ROTATION_270;
1717 LOGD("setting rotation property value : %d", value);
1723 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1725 /* check video sinkbin is created */
1726 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1728 player->pipeline->videobin &&
1729 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1730 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1731 MM_ERROR_PLAYER_NOT_INITIALIZED);
1733 return MM_ERROR_NONE;
1737 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1739 int display_rotation = 0;
1740 gchar *org_orient = NULL;
1741 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1744 LOGE("cannot get content attribute");
1745 return MM_ERROR_PLAYER_INTERNAL;
1748 if (display_angle) {
1749 /* update user roation */
1750 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1752 /* Counter clockwise */
1753 switch (display_rotation) {
1754 case MM_DISPLAY_ROTATION_NONE:
1757 case MM_DISPLAY_ROTATION_90:
1758 *display_angle = 90;
1760 case MM_DISPLAY_ROTATION_180:
1761 *display_angle = 180;
1763 case MM_DISPLAY_ROTATION_270:
1764 *display_angle = 270;
1767 LOGW("wrong angle type : %d", display_rotation);
1770 LOGD("check user angle: %d", *display_angle);
1774 /* Counter clockwise */
1775 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1778 if (!strcmp(org_orient, "rotate-90"))
1780 else if (!strcmp(org_orient, "rotate-180"))
1782 else if (!strcmp(org_orient, "rotate-270"))
1785 LOGD("original rotation is %s", org_orient);
1787 LOGD("content_video_orientation get fail");
1790 LOGD("check orientation: %d", *orientation);
1793 return MM_ERROR_NONE;
1797 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1799 int rotation_value = 0;
1800 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1801 int display_angle = 0;
1804 /* check video sinkbin is created */
1805 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1808 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1810 /* get rotation value to set */
1811 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1812 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1813 LOGD("set video param : rotate %d", rotation_value);
1817 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1819 MMHandleType attrs = 0;
1823 /* check video sinkbin is created */
1824 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1827 attrs = MMPLAYER_GET_ATTRS(player);
1828 MMPLAYER_RETURN_IF_FAIL(attrs);
1830 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1831 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1832 LOGD("set video param : visible %d", visible);
1836 __mmplayer_video_param_set_display_method(mm_player_t* player)
1838 MMHandleType attrs = 0;
1839 int display_method = 0;
1842 /* check video sinkbin is created */
1843 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1846 attrs = MMPLAYER_GET_ATTRS(player);
1847 MMPLAYER_RETURN_IF_FAIL(attrs);
1849 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1850 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1851 LOGD("set video param : method %d", display_method);
1854 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1856 MMHandleType attrs = 0;
1857 void *handle = NULL;
1860 /* check video sinkbin is created */
1861 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1862 LOGW("There is no video sink");
1866 attrs = MMPLAYER_GET_ATTRS(player);
1867 MMPLAYER_RETURN_IF_FAIL(attrs);
1868 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1870 gst_video_overlay_set_video_roi_area(
1871 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1872 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1873 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1874 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1879 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1881 MMHandleType attrs = 0;
1882 void *handle = NULL;
1886 int win_roi_width = 0;
1887 int win_roi_height = 0;
1890 /* check video sinkbin is created */
1891 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1892 LOGW("There is no video sink");
1896 attrs = MMPLAYER_GET_ATTRS(player);
1897 MMPLAYER_RETURN_IF_FAIL(attrs);
1899 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1902 /* It should be set after setting window */
1903 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1904 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1905 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1906 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1908 /* After setting window handle, set display roi area */
1909 gst_video_overlay_set_display_roi_area(
1910 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1911 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1912 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1913 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1917 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1919 MMHandleType attrs = 0;
1920 void *handle = NULL;
1922 /* check video sinkbin is created */
1923 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1926 attrs = MMPLAYER_GET_ATTRS(player);
1927 MMPLAYER_RETURN_IF_FAIL(attrs);
1929 /* common case if using overlay surface */
1930 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1933 /* default is using wl_surface_id */
1934 unsigned int wl_surface_id = 0;
1935 wl_surface_id = *(int*)handle;
1936 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
1937 gst_video_overlay_set_wl_window_wl_surface_id(
1938 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1941 /* FIXIT : is it error case? */
1942 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1947 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
1949 bool update_all_param = FALSE;
1952 /* check video sinkbin is created */
1953 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1954 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1956 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1957 LOGE("can not find tizenwlsink");
1958 return MM_ERROR_PLAYER_INTERNAL;
1961 LOGD("param_name : %s", param_name);
1962 if (!g_strcmp0(param_name, "update_all_param"))
1963 update_all_param = TRUE;
1965 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1966 __mmplayer_video_param_set_display_overlay(player);
1967 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1968 __mmplayer_video_param_set_display_method(player);
1969 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1970 __mmplayer_video_param_set_display_visible(player);
1971 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1972 __mmplayer_video_param_set_display_rotation(player);
1973 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1974 __mmplayer_video_param_set_roi_area(player);
1975 if (update_all_param)
1976 __mmplayer_video_param_set_video_roi_area(player);
1978 return MM_ERROR_NONE;
1982 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
1984 MMHandleType attrs = 0;
1985 int surface_type = 0;
1986 int ret = MM_ERROR_NONE;
1990 /* check video sinkbin is created */
1991 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1992 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1994 attrs = MMPLAYER_GET_ATTRS(player);
1996 LOGE("cannot get content attribute");
1997 return MM_ERROR_PLAYER_INTERNAL;
1999 LOGD("param_name : %s", param_name);
2001 /* update display surface */
2002 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2003 LOGD("check display surface type attribute: %d", surface_type);
2005 /* configuring display */
2006 switch (surface_type) {
2007 case MM_DISPLAY_SURFACE_OVERLAY:
2009 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2010 if (ret != MM_ERROR_NONE)
2018 return MM_ERROR_NONE;
2022 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2024 gboolean disable_overlay = FALSE;
2025 mm_player_t* player = (mm_player_t*) hplayer;
2026 int ret = MM_ERROR_NONE;
2029 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2030 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2031 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2032 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2034 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2035 LOGW("Display control is not supported");
2036 return MM_ERROR_PLAYER_INTERNAL;
2039 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2041 if (audio_only == (bool)disable_overlay) {
2042 LOGE("It's the same with current setting: (%d)", audio_only);
2043 return MM_ERROR_NONE;
2047 LOGE("disable overlay");
2048 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2050 /* release overlay resource */
2051 if (player->video_overlay_resource != NULL) {
2052 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2053 player->video_overlay_resource);
2054 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2055 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2058 player->video_overlay_resource = NULL;
2061 ret = mm_resource_manager_commit(player->resource_manager);
2062 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2063 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2067 /* mark video overlay for acquire */
2068 if (player->video_overlay_resource == NULL) {
2069 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2070 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2071 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2072 &player->video_overlay_resource);
2073 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2074 LOGE("could not prepare for video_overlay resource\n");
2079 player->interrupted_by_resource = FALSE;
2080 /* acquire resources for video overlay */
2081 ret = mm_resource_manager_commit(player->resource_manager);
2082 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2083 LOGE("could not acquire resources for video playing\n");
2087 LOGD("enable overlay");
2088 __mmplayer_video_param_set_display_overlay(player);
2089 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2094 return MM_ERROR_NONE;
2098 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2100 mm_player_t* player = (mm_player_t*) hplayer;
2101 gboolean disable_overlay = FALSE;
2105 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2106 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2107 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2108 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2109 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2111 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2112 LOGW("Display control is not supported");
2113 return MM_ERROR_PLAYER_INTERNAL;
2116 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2118 *paudio_only = (bool)(disable_overlay);
2120 LOGD("audio_only : %d", *paudio_only);
2124 return MM_ERROR_NONE;
2128 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2130 GList* bucket = element_bucket;
2131 MMPlayerGstElement* element = NULL;
2132 MMPlayerGstElement* prv_element = NULL;
2133 gint successful_link_count = 0;
2137 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2139 prv_element = (MMPlayerGstElement*)bucket->data;
2140 bucket = bucket->next;
2142 for (; bucket; bucket = bucket->next) {
2143 element = (MMPlayerGstElement*)bucket->data;
2145 if (element && element->gst) {
2146 if (prv_element && prv_element->gst) {
2147 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2148 LOGD("linking [%s] to [%s] success\n",
2149 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2150 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2151 successful_link_count++;
2153 LOGD("linking [%s] to [%s] failed\n",
2154 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2155 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2161 prv_element = element;
2166 return successful_link_count;
2170 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2172 GList* bucket = element_bucket;
2173 MMPlayerGstElement* element = NULL;
2174 int successful_add_count = 0;
2178 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2179 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2181 for (; bucket; bucket = bucket->next) {
2182 element = (MMPlayerGstElement*)bucket->data;
2184 if (element && element->gst) {
2185 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2186 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2187 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2188 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2191 successful_add_count++;
2197 return successful_add_count;
2200 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2202 mm_player_t *player = (mm_player_t*) data;
2203 GstCaps *caps = NULL;
2204 GstStructure *str = NULL;
2206 gboolean caps_ret = TRUE;
2210 MMPLAYER_RETURN_IF_FAIL(pad);
2211 MMPLAYER_RETURN_IF_FAIL(unused);
2212 MMPLAYER_RETURN_IF_FAIL(data);
2214 caps = gst_pad_get_current_caps(pad);
2218 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2222 LOGD("name = %s", name);
2224 if (strstr(name, "audio")) {
2225 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2227 if (player->audio_stream_changed_cb) {
2228 LOGE("call the audio stream changed cb");
2229 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2231 } else if (strstr(name, "video")) {
2232 if ((name = gst_structure_get_string(str, "format")))
2233 player->set_mode.video_zc = name[0] == 'S';
2235 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2237 if (player->video_stream_changed_cb) {
2238 LOGE("call the video stream changed cb");
2239 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2242 LOGW("invalid caps info");
2247 gst_caps_unref(caps);
2257 * This function is to create audio pipeline for playing.
2259 * @param player [in] handle of player
2261 * @return This function returns zero on success.
2263 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2265 /* macro for code readability. just for sinkbin-creation functions */
2266 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2268 x_bin[x_id].id = x_id;\
2269 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2270 if (!x_bin[x_id].gst) {\
2271 LOGE("failed to create %s \n", x_factory);\
2274 if (x_player->ini.set_dump_element_flag)\
2275 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2278 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2282 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2287 MMPLAYER_RETURN_IF_FAIL(player);
2289 if (player->audio_stream_buff_list) {
2290 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2291 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2294 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2295 __mmplayer_audio_stream_send_data(player, tmp);
2298 g_free(tmp->pcm_data);
2302 g_list_free(player->audio_stream_buff_list);
2303 player->audio_stream_buff_list = NULL;
2310 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2312 MMPlayerAudioStreamDataType audio_stream = { 0, };
2315 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2317 audio_stream.bitrate = a_buffer->bitrate;
2318 audio_stream.channel = a_buffer->channel;
2319 audio_stream.depth = a_buffer->depth;
2320 audio_stream.is_little_endian = a_buffer->is_little_endian;
2321 audio_stream.channel_mask = a_buffer->channel_mask;
2322 audio_stream.data_size = a_buffer->data_size;
2323 audio_stream.data = a_buffer->pcm_data;
2325 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2326 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2332 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2334 mm_player_t* player = (mm_player_t*) data;
2339 gint endianness = 0;
2340 guint64 channel_mask = 0;
2341 void *a_data = NULL;
2343 mm_player_audio_stream_buff_t *a_buffer = NULL;
2344 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2348 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2350 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2351 a_data = mapinfo.data;
2352 a_size = mapinfo.size;
2354 GstCaps *caps = gst_pad_get_current_caps(pad);
2355 GstStructure *structure = gst_caps_get_structure(caps, 0);
2357 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2358 gst_structure_get_int(structure, "rate", &rate);
2359 gst_structure_get_int(structure, "channels", &channel);
2360 gst_structure_get_int(structure, "depth", &depth);
2361 gst_structure_get_int(structure, "endianness", &endianness);
2362 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2363 gst_caps_unref(GST_CAPS(caps));
2365 /* In case of the sync is false, use buffer list. *
2366 * The num of buffer list depends on the num of audio channels */
2367 if (player->audio_stream_buff_list) {
2368 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2369 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2371 if (channel_mask == tmp->channel_mask) {
2372 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2373 if (tmp->data_size + a_size < tmp->buff_size) {
2374 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2375 tmp->data_size += a_size;
2377 /* send data to client */
2378 __mmplayer_audio_stream_send_data(player, tmp);
2380 if (a_size > tmp->buff_size) {
2381 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2382 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2383 if (tmp->pcm_data == NULL) {
2384 LOGE("failed to realloc data.");
2387 tmp->buff_size = a_size;
2389 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2390 memcpy(tmp->pcm_data, a_data, a_size);
2391 tmp->data_size = a_size;
2396 LOGE("data is empty in list.");
2402 /* create new audio stream data */
2403 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2404 if (a_buffer == NULL) {
2405 LOGE("failed to alloc data.");
2408 a_buffer->bitrate = rate;
2409 a_buffer->channel = channel;
2410 a_buffer->depth = depth;
2411 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2412 a_buffer->channel_mask = channel_mask;
2413 a_buffer->data_size = a_size;
2415 if (!player->audio_stream_sink_sync) {
2416 /* If sync is FALSE, use buffer list to reduce the IPC. */
2417 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2418 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2419 if (a_buffer->pcm_data == NULL) {
2420 LOGE("failed to alloc data.");
2424 memcpy(a_buffer->pcm_data, a_data, a_size);
2425 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2426 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2428 /* If sync is TRUE, send data directly. */
2429 a_buffer->pcm_data = a_data;
2430 __mmplayer_audio_stream_send_data(player, a_buffer);
2435 gst_buffer_unmap(buffer, &mapinfo);
2440 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2442 mm_player_t* player = (mm_player_t*)data;
2443 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2444 GstPad* sinkpad = NULL;
2445 GstElement *queue = NULL, *sink = NULL;
2448 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2450 queue = gst_element_factory_make("queue", NULL);
2451 if (queue == NULL) {
2452 LOGD("fail make queue\n");
2456 sink = gst_element_factory_make("fakesink", NULL);
2458 LOGD("fail make fakesink\n");
2462 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2464 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2465 LOGW("failed to link queue & sink\n");
2469 sinkpad = gst_element_get_static_pad(queue, "sink");
2471 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2472 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2476 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2478 gst_object_unref(sinkpad);
2479 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2480 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2482 gst_element_set_state(sink, GST_STATE_PAUSED);
2483 gst_element_set_state(queue, GST_STATE_PAUSED);
2485 __mmplayer_add_signal_connection(player,
2487 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2489 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2496 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2498 gst_object_unref(GST_OBJECT(queue));
2502 gst_object_unref(GST_OBJECT(sink));
2506 gst_object_unref(GST_OBJECT(sinkpad));
2513 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2515 #define MAX_PROPS_LEN 128
2516 gint latency_mode = 0;
2517 gchar *stream_type = NULL;
2518 gchar *latency = NULL;
2520 gchar stream_props[MAX_PROPS_LEN] = {0,};
2521 GstStructure *props = NULL;
2524 * It should be set after player creation through attribute.
2525 * But, it can not be changed during playing.
2528 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2530 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2531 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2534 LOGE("stream_type is null.");
2536 if (player->sound.focus_id)
2537 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2538 stream_type, stream_id, player->sound.focus_id);
2540 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2541 stream_type, stream_id);
2542 props = gst_structure_from_string(stream_props, NULL);
2543 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2544 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2545 stream_type, stream_id, player->sound.focus_id, stream_props);
2546 gst_structure_free(props);
2549 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2551 switch (latency_mode) {
2552 case AUDIO_LATENCY_MODE_LOW:
2553 latency = g_strndup("low", 3);
2555 case AUDIO_LATENCY_MODE_MID:
2556 latency = g_strndup("mid", 3);
2558 case AUDIO_LATENCY_MODE_HIGH:
2559 latency = g_strndup("high", 4);
2563 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2567 LOGD("audiosink property - latency=%s", latency);
2574 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2576 MMPlayerGstElement *audiobin = NULL;
2579 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2581 audiobin = player->pipeline->audiobin;
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2584 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2585 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2587 if (player->video360_yaw_radians <= M_PI &&
2588 player->video360_yaw_radians >= -M_PI &&
2589 player->video360_pitch_radians <= M_PI_2 &&
2590 player->video360_pitch_radians >= -M_PI_2) {
2591 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2592 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2593 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2594 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2595 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2596 "source-orientation-y", player->video360_metadata.init_view_heading,
2597 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2604 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2606 MMPlayerGstElement *audiobin = NULL;
2607 MMHandleType attrs = 0;
2608 GList *element_bucket = NULL;
2609 GstCaps *acaps = NULL;
2610 GstPad *sink_pad = NULL;
2613 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2614 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2616 audiobin = player->pipeline->audiobin;
2617 attrs = MMPLAYER_GET_ATTRS(player);
2620 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2622 /* replaygain volume */
2623 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2624 if (player->sound.rg_enable)
2625 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2627 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2632 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2633 gchar *dst_format = NULL;
2635 int dst_samplerate = 0;
2636 int dst_channels = 0;
2637 GstCaps *caps = NULL;
2638 char *caps_str = NULL;
2640 /* get conf. values */
2641 mm_attrs_multiple_get(player->attrs, NULL,
2642 "pcm_audioformat", &dst_format, &dst_len,
2643 "pcm_extraction_samplerate", &dst_samplerate,
2644 "pcm_extraction_channels", &dst_channels,
2647 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2651 caps = gst_caps_new_simple("audio/x-raw",
2652 "format", G_TYPE_STRING, dst_format,
2653 "rate", G_TYPE_INT, dst_samplerate,
2654 "channels", G_TYPE_INT, dst_channels,
2657 caps_str = gst_caps_to_string(caps);
2658 LOGD("new caps : %s", caps_str);
2660 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2663 gst_caps_unref(caps);
2664 MMPLAYER_FREEIF(caps_str);
2666 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2668 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2670 /* raw pad handling signal, audiosink will be added after getting signal */
2671 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2672 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2676 /* normal playback */
2679 /* for logical volume control */
2680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2683 if (player->sound.mute) {
2684 LOGD("mute enabled");
2685 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2688 /* check if multi-channels */
2689 if (player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) {
2690 GstPad *srcpad = NULL;
2691 GstCaps *caps = NULL;
2693 if ((srcpad = gst_element_get_static_pad(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst, "src"))) {
2694 if ((caps = gst_pad_query_caps(srcpad, NULL))) {
2695 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2696 GstStructure *str = gst_caps_get_structure(caps, 0);
2698 gst_structure_get_int(str, "channels", &channels);
2699 gst_caps_unref(caps);
2701 gst_object_unref(srcpad);
2705 /* audio effect element. if audio effect is enabled */
2706 if ((strcmp(player->ini.audioeffect_element, ""))
2708 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2711 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2713 if ((!player->bypass_audio_effect)
2714 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2715 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2716 if (!_mmplayer_audio_effect_custom_apply(player))
2717 LOGI("apply audio effect(custom) setting success");
2721 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2722 && (player->set_mode.rich_audio))
2723 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2726 /* create audio sink */
2727 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2728 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2729 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2731 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2732 if (player->is_360_feature_enabled &&
2733 player->is_content_spherical &&
2735 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2736 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2737 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2739 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2741 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2743 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2744 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2746 gst_caps_unref(acaps);
2748 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2750 player->is_openal_plugin_used = TRUE;
2752 if (player->is_360_feature_enabled && player->is_content_spherical)
2753 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2754 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2757 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2758 (player->videodec_linked && player->ini.use_system_clock)) {
2759 LOGD("system clock will be used.");
2760 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2763 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2764 __mmplayer_gst_set_pulsesink_property(player, attrs);
2765 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2766 __mmplayer_gst_set_openalsink_property(player);
2769 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2770 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2772 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2773 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2774 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2775 gst_object_unref(GST_OBJECT(sink_pad));
2777 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2780 *bucket = element_bucket;
2783 return MM_ERROR_NONE;
2786 g_list_free(element_bucket);
2790 return MM_ERROR_PLAYER_INTERNAL;
2794 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2796 MMPlayerGstElement *first_element = NULL;
2797 MMPlayerGstElement *audiobin = NULL;
2799 GstPad *ghostpad = NULL;
2800 GList *element_bucket = NULL;
2804 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2807 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2809 LOGE("failed to allocate memory for audiobin");
2810 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2814 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2815 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2816 if (!audiobin[MMPLAYER_A_BIN].gst) {
2817 LOGE("failed to create audiobin");
2822 player->pipeline->audiobin = audiobin;
2824 /* create audio filters and audiosink */
2825 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2828 /* adding created elements to bin */
2829 LOGD("adding created elements to bin");
2830 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2833 /* linking elements in the bucket by added order. */
2834 LOGD("Linking elements in the bucket by added order.");
2835 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2838 /* get first element's sinkpad for creating ghostpad */
2839 first_element = (MMPlayerGstElement *)element_bucket->data;
2840 if (!first_element) {
2841 LOGE("failed to get first elem");
2845 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2847 LOGE("failed to get pad from first element of audiobin");
2851 ghostpad = gst_ghost_pad_new("sink", pad);
2853 LOGE("failed to create ghostpad");
2857 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2858 LOGE("failed to add ghostpad to audiobin");
2862 gst_object_unref(pad);
2864 g_list_free(element_bucket);
2867 return MM_ERROR_NONE;
2870 LOGD("ERROR : releasing audiobin");
2873 gst_object_unref(GST_OBJECT(pad));
2876 gst_object_unref(GST_OBJECT(ghostpad));
2879 g_list_free(element_bucket);
2881 /* release element which are not added to bin */
2882 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2883 /* NOTE : skip bin */
2884 if (audiobin[i].gst) {
2885 GstObject* parent = NULL;
2886 parent = gst_element_get_parent(audiobin[i].gst);
2889 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2890 audiobin[i].gst = NULL;
2892 gst_object_unref(GST_OBJECT(parent));
2896 /* release audiobin with it's childs */
2897 if (audiobin[MMPLAYER_A_BIN].gst)
2898 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2900 MMPLAYER_FREEIF(audiobin);
2902 player->pipeline->audiobin = NULL;
2904 return MM_ERROR_PLAYER_INTERNAL;
2907 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2909 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2912 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2914 int ret = MM_ERROR_NONE;
2916 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2917 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2919 MMPLAYER_VIDEO_BO_LOCK(player);
2921 if (player->video_bo_list) {
2922 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2923 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2924 if (tmp && tmp->bo == bo) {
2926 LOGD("release bo %p", bo);
2927 tbm_bo_unref(tmp->bo);
2928 MMPLAYER_VIDEO_BO_UNLOCK(player);
2929 MMPLAYER_VIDEO_BO_SIGNAL(player);
2934 /* hw codec is running or the list was reset for DRC. */
2935 LOGW("there is no bo list.");
2937 MMPLAYER_VIDEO_BO_UNLOCK(player);
2939 LOGW("failed to find bo %p", bo);
2944 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2949 MMPLAYER_RETURN_IF_FAIL(player);
2951 MMPLAYER_VIDEO_BO_LOCK(player);
2952 if (player->video_bo_list) {
2953 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2954 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2955 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2958 tbm_bo_unref(tmp->bo);
2962 g_list_free(player->video_bo_list);
2963 player->video_bo_list = NULL;
2965 player->video_bo_size = 0;
2966 MMPLAYER_VIDEO_BO_UNLOCK(player);
2973 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2976 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2977 gboolean ret = TRUE;
2979 /* check DRC, if it is, destroy the prev bo list to create again */
2980 if (player->video_bo_size != size) {
2981 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2982 __mmplayer_video_stream_destroy_bo_list(player);
2983 player->video_bo_size = size;
2986 MMPLAYER_VIDEO_BO_LOCK(player);
2988 if ((!player->video_bo_list) ||
2989 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2991 /* create bo list */
2993 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2995 if (player->video_bo_list) {
2996 /* if bo list did not created all, try it again. */
2997 idx = g_list_length(player->video_bo_list);
2998 LOGD("bo list exist(len: %d)", idx);
3001 for (; idx < player->ini.num_of_video_bo; idx++) {
3002 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
3004 LOGE("Fail to alloc bo_info.");
3007 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3009 LOGE("Fail to tbm_bo_alloc.");
3013 bo_info->used = FALSE;
3014 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3017 /* update video num buffers */
3018 player->video_num_buffers = idx;
3019 if (idx == player->ini.num_of_video_bo)
3020 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3023 MMPLAYER_VIDEO_BO_UNLOCK(player);
3027 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3031 /* get bo from list*/
3032 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3033 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3034 if (tmp && (tmp->used == FALSE)) {
3035 LOGD("found bo %p to use", tmp->bo);
3037 MMPLAYER_VIDEO_BO_UNLOCK(player);
3038 return tbm_bo_ref(tmp->bo);
3042 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3043 MMPLAYER_VIDEO_BO_UNLOCK(player);
3047 if (player->ini.video_bo_timeout <= 0) {
3048 MMPLAYER_VIDEO_BO_WAIT(player);
3050 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3051 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3058 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3060 mm_player_t* player = (mm_player_t*)data;
3062 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3064 /* send prerolled pkt */
3065 player->video_stream_prerolled = FALSE;
3067 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3069 /* not to send prerolled pkt again */
3070 player->video_stream_prerolled = TRUE;
3074 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3076 mm_player_t* player = (mm_player_t*)data;
3077 MMPlayerVideoStreamDataType *stream = NULL;
3078 GstMemory *mem = NULL;
3081 MMPLAYER_RETURN_IF_FAIL(player);
3082 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3084 if (player->video_stream_prerolled) {
3085 player->video_stream_prerolled = FALSE;
3086 LOGD("skip the prerolled pkt not to send it again");
3090 /* clear stream data structure */
3091 stream = __mmplayer_create_stream_from_pad(pad);
3093 LOGE("failed to alloc stream");
3097 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3099 /* set size and timestamp */
3100 mem = gst_buffer_peek_memory(buffer, 0);
3101 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3102 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3104 /* check zero-copy */
3105 if (player->set_mode.video_zc &&
3106 player->set_mode.media_packet_video_stream &&
3107 gst_is_tizen_memory(mem)) {
3108 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3109 stream->internal_buffer = gst_buffer_ref(buffer);
3110 } else { /* sw codec */
3111 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3114 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3118 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3119 LOGE("failed to send video stream data.");
3126 LOGE("release video stream resource.");
3127 if (gst_is_tizen_memory(mem)) {
3129 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3131 tbm_bo_unref(stream->bo[i]);
3134 /* unref gst buffer */
3135 if (stream->internal_buffer)
3136 gst_buffer_unref(stream->internal_buffer);
3139 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3146 __mmplayer_gst_set_video360_property(mm_player_t *player)
3148 MMPlayerGstElement *videobin = NULL;
3151 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3153 videobin = player->pipeline->videobin;
3155 /* Set spatial media metadata and/or user settings to the element.
3157 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3158 "projection-type", player->video360_metadata.projection_type, NULL);
3160 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3161 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3163 if (player->video360_metadata.full_pano_width_pixels &&
3164 player->video360_metadata.full_pano_height_pixels &&
3165 player->video360_metadata.cropped_area_image_width &&
3166 player->video360_metadata.cropped_area_image_height) {
3167 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3168 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3169 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3170 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3171 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3172 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3173 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3177 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3178 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3179 "horizontal-fov", player->video360_horizontal_fov,
3180 "vertical-fov", player->video360_vertical_fov, NULL);
3183 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3184 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3185 "zoom", 1.0f / player->video360_zoom, NULL);
3188 if (player->video360_yaw_radians <= M_PI &&
3189 player->video360_yaw_radians >= -M_PI &&
3190 player->video360_pitch_radians <= M_PI_2 &&
3191 player->video360_pitch_radians >= -M_PI_2) {
3192 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3193 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3194 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3195 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3196 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3197 "pose-yaw", player->video360_metadata.init_view_heading,
3198 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3201 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3202 "passthrough", !player->is_video360_enabled, NULL);
3209 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3211 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3212 GList *element_bucket = NULL;
3215 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3217 /* create video360 filter */
3218 if (player->is_360_feature_enabled && player->is_content_spherical) {
3219 LOGD("create video360 element");
3220 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3221 __mmplayer_gst_set_video360_property(player);
3225 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3226 LOGD("skip creating the videoconv and rotator");
3227 return MM_ERROR_NONE;
3230 /* in case of sw codec & overlay surface type, except 360 playback.
3231 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3232 LOGD("create video converter: %s", video_csc);
3233 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3235 /* set video rotator */
3236 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3239 *bucket = element_bucket;
3241 return MM_ERROR_NONE;
3243 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3244 g_list_free(element_bucket);
3248 return MM_ERROR_PLAYER_INTERNAL;
3252 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3254 gchar *factory_name = NULL;
3256 switch (surface_type) {
3257 case MM_DISPLAY_SURFACE_OVERLAY:
3258 if (strlen(player->ini.videosink_element_overlay) > 0)
3259 factory_name = player->ini.videosink_element_overlay;
3261 case MM_DISPLAY_SURFACE_REMOTE:
3262 case MM_DISPLAY_SURFACE_NULL:
3263 if (strlen(player->ini.videosink_element_fake) > 0)
3264 factory_name = player->ini.videosink_element_fake;
3267 LOGE("unidentified surface type");
3271 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3272 return factory_name;
3276 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3278 gchar *factory_name = NULL;
3279 MMPlayerGstElement *videobin = NULL;
3284 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3286 videobin = player->pipeline->videobin;
3287 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3289 attrs = MMPLAYER_GET_ATTRS(player);
3291 LOGE("cannot get content attribute");
3292 return MM_ERROR_PLAYER_INTERNAL;
3295 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3296 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3297 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3299 /* support shard memory with S/W codec on HawkP */
3300 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3301 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3302 "use-tbm", use_tbm, NULL);
3306 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3307 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3310 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3312 LOGD("disable last-sample");
3313 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3316 if (player->set_mode.media_packet_video_stream) {
3318 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3319 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3320 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3322 __mmplayer_add_signal_connection(player,
3323 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3324 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3326 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3329 __mmplayer_add_signal_connection(player,
3330 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3331 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3333 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3337 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3338 return MM_ERROR_PLAYER_INTERNAL;
3340 if (videobin[MMPLAYER_V_SINK].gst) {
3341 GstPad *sink_pad = NULL;
3342 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3344 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3345 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3346 gst_object_unref(GST_OBJECT(sink_pad));
3348 LOGE("failed to get sink pad from videosink");
3352 return MM_ERROR_NONE;
3357 * - video overlay surface(arm/x86) : tizenwlsink
3360 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3363 GList *element_bucket = NULL;
3364 MMPlayerGstElement *first_element = NULL;
3365 MMPlayerGstElement *videobin = NULL;
3366 gchar *videosink_factory_name = NULL;
3369 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3372 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3374 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3376 player->pipeline->videobin = videobin;
3379 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3380 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3381 if (!videobin[MMPLAYER_V_BIN].gst) {
3382 LOGE("failed to create videobin");
3386 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3389 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3390 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3392 /* additional setting for sink plug-in */
3393 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3394 LOGE("failed to set video property");
3398 /* store it as it's sink element */
3399 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3401 /* adding created elements to bin */
3402 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3403 LOGE("failed to add elements");
3407 /* Linking elements in the bucket by added order */
3408 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3409 LOGE("failed to link elements");
3413 /* get first element's sinkpad for creating ghostpad */
3414 first_element = (MMPlayerGstElement *)element_bucket->data;
3415 if (!first_element) {
3416 LOGE("failed to get first element from bucket");
3420 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3422 LOGE("failed to get pad from first element");
3426 /* create ghostpad */
3427 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3428 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3429 LOGE("failed to add ghostpad to videobin");
3432 gst_object_unref(pad);
3434 /* done. free allocated variables */
3435 g_list_free(element_bucket);
3439 return MM_ERROR_NONE;
3442 LOGE("ERROR : releasing videobin");
3443 g_list_free(element_bucket);
3446 gst_object_unref(GST_OBJECT(pad));
3448 /* release videobin with it's childs */
3449 if (videobin[MMPLAYER_V_BIN].gst)
3450 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3452 MMPLAYER_FREEIF(videobin);
3453 player->pipeline->videobin = NULL;
3455 return MM_ERROR_PLAYER_INTERNAL;
3458 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3460 GList *element_bucket = NULL;
3461 MMPlayerGstElement *textbin = player->pipeline->textbin;
3463 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3464 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3465 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3466 "signal-handoffs", FALSE,
3469 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3470 __mmplayer_add_signal_connection(player,
3471 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3472 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3474 G_CALLBACK(__mmplayer_update_subtitle),
3477 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3478 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3480 if (!player->play_subtitle) {
3481 LOGD("add textbin sink as sink element of whole pipeline.\n");
3482 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3485 /* adding created elements to bin */
3486 LOGD("adding created elements to bin\n");
3487 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3488 LOGE("failed to add elements\n");
3492 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3493 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3494 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3496 /* linking elements in the bucket by added order. */
3497 LOGD("Linking elements in the bucket by added order.\n");
3498 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3499 LOGE("failed to link elements\n");
3503 /* done. free allocated variables */
3504 g_list_free(element_bucket);
3506 if (textbin[MMPLAYER_T_QUEUE].gst) {
3508 GstPad *ghostpad = NULL;
3510 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3512 LOGE("failed to get sink pad of text queue");
3516 ghostpad = gst_ghost_pad_new("text_sink", pad);
3517 gst_object_unref(pad);
3520 LOGE("failed to create ghostpad of textbin\n");
3524 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3525 LOGE("failed to add ghostpad to textbin\n");
3526 gst_object_unref(ghostpad);
3531 return MM_ERROR_NONE;
3534 g_list_free(element_bucket);
3536 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3537 LOGE("remove textbin sink from sink list");
3538 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3541 /* release element at __mmplayer_gst_create_text_sink_bin */
3542 return MM_ERROR_PLAYER_INTERNAL;
3545 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3547 MMPlayerGstElement *textbin = NULL;
3548 GList *element_bucket = NULL;
3549 int surface_type = 0;
3554 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3557 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3559 LOGE("failed to allocate memory for textbin\n");
3560 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3564 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3565 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3566 if (!textbin[MMPLAYER_T_BIN].gst) {
3567 LOGE("failed to create textbin\n");
3572 player->pipeline->textbin = textbin;
3575 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3576 LOGD("surface type for subtitle : %d", surface_type);
3577 switch (surface_type) {
3578 case MM_DISPLAY_SURFACE_OVERLAY:
3579 case MM_DISPLAY_SURFACE_NULL:
3580 case MM_DISPLAY_SURFACE_REMOTE:
3581 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3582 LOGE("failed to make plain text elements\n");
3593 return MM_ERROR_NONE;
3597 LOGD("ERROR : releasing textbin\n");
3599 g_list_free(element_bucket);
3601 /* release signal */
3602 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3604 /* release element which are not added to bin */
3605 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3606 /* NOTE : skip bin */
3607 if (textbin[i].gst) {
3608 GstObject* parent = NULL;
3609 parent = gst_element_get_parent(textbin[i].gst);
3612 gst_object_unref(GST_OBJECT(textbin[i].gst));
3613 textbin[i].gst = NULL;
3615 gst_object_unref(GST_OBJECT(parent));
3620 /* release textbin with it's childs */
3621 if (textbin[MMPLAYER_T_BIN].gst)
3622 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3624 MMPLAYER_FREEIF(player->pipeline->textbin);
3625 player->pipeline->textbin = NULL;
3628 return MM_ERROR_PLAYER_INTERNAL;
3633 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3635 MMPlayerGstElement* mainbin = NULL;
3636 MMPlayerGstElement* textbin = NULL;
3637 MMHandleType attrs = 0;
3638 GstElement *subsrc = NULL;
3639 GstElement *subparse = NULL;
3640 gchar *subtitle_uri = NULL;
3641 const gchar *charset = NULL;
3647 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3649 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3651 mainbin = player->pipeline->mainbin;
3653 attrs = MMPLAYER_GET_ATTRS(player);
3655 LOGE("cannot get content attribute\n");
3656 return MM_ERROR_PLAYER_INTERNAL;
3659 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3660 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3661 LOGE("subtitle uri is not proper filepath.\n");
3662 return MM_ERROR_PLAYER_INVALID_URI;
3665 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3666 LOGE("failed to get storage info of subtitle path");
3667 return MM_ERROR_PLAYER_INVALID_URI;
3670 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3672 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3673 player->subtitle_language_list = NULL;
3674 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3676 /* create the subtitle source */
3677 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3679 LOGE("failed to create filesrc element\n");
3682 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3684 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3685 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3687 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3688 LOGW("failed to add queue\n");
3689 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3690 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3691 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3696 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3698 LOGE("failed to create subparse element\n");
3702 charset = util_get_charset(subtitle_uri);
3704 LOGD("detected charset is %s\n", charset);
3705 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3708 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3709 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3711 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3712 LOGW("failed to add subparse\n");
3713 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3714 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3715 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3719 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3720 LOGW("failed to link subsrc and subparse\n");
3724 player->play_subtitle = TRUE;
3725 player->adjust_subtitle_pos = 0;
3727 LOGD("play subtitle using subtitle file\n");
3729 if (player->pipeline->textbin == NULL) {
3730 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3731 LOGE("failed to create text sink bin. continuing without text\n");
3735 textbin = player->pipeline->textbin;
3737 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3738 LOGW("failed to add textbin\n");
3740 /* release signal */
3741 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3743 /* release textbin with it's childs */
3744 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3745 MMPLAYER_FREEIF(player->pipeline->textbin);
3746 player->pipeline->textbin = textbin = NULL;
3750 LOGD("link text input selector and textbin ghost pad");
3752 player->textsink_linked = 1;
3753 player->external_text_idx = 0;
3754 LOGI("player->textsink_linked set to 1\n");
3756 textbin = player->pipeline->textbin;
3757 LOGD("text bin has been created. reuse it.");
3758 player->external_text_idx = 1;
3761 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3762 LOGW("failed to link subparse and textbin\n");
3766 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3768 LOGE("failed to get sink pad from textsink to probe data");
3772 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3773 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3775 gst_object_unref(pad);
3778 /* create dot. for debugging */
3779 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3782 return MM_ERROR_NONE;
3785 /* release text pipeline resource */
3786 player->textsink_linked = 0;
3788 /* release signal */
3789 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3791 if (player->pipeline->textbin) {
3792 LOGE("remove textbin");
3794 /* release textbin with it's childs */
3795 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3796 MMPLAYER_FREEIF(player->pipeline->textbin);
3797 player->pipeline->textbin = NULL;
3801 /* release subtitle elem */
3802 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3803 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3805 return MM_ERROR_PLAYER_INTERNAL;
3809 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3811 mm_player_t* player = (mm_player_t*) data;
3812 MMMessageParamType msg = {0, };
3813 GstClockTime duration = 0;
3814 gpointer text = NULL;
3815 guint text_size = 0;
3816 gboolean ret = TRUE;
3817 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3821 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3822 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3824 if (player->is_subtitle_force_drop) {
3825 LOGW("subtitle is dropped forcedly.");
3829 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3830 text = mapinfo.data;
3831 text_size = mapinfo.size;
3832 duration = GST_BUFFER_DURATION(buffer);
3834 if (player->set_mode.subtitle_off) {
3835 LOGD("subtitle is OFF.\n");
3839 if (!text || (text_size == 0)) {
3840 LOGD("There is no subtitle to be displayed.\n");
3844 msg.data = (void *) text;
3845 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3847 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3849 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3850 gst_buffer_unmap(buffer, &mapinfo);
3857 static GstPadProbeReturn
3858 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3860 mm_player_t *player = (mm_player_t *) u_data;
3861 GstClockTime cur_timestamp = 0;
3862 gint64 adjusted_timestamp = 0;
3863 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3865 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3867 if (player->set_mode.subtitle_off) {
3868 LOGD("subtitle is OFF.\n");
3872 if (player->adjust_subtitle_pos == 0) {
3873 LOGD("nothing to do");
3877 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3878 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3880 if (adjusted_timestamp < 0) {
3881 LOGD("adjusted_timestamp under zero");
3886 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3887 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3888 GST_TIME_ARGS(cur_timestamp),
3889 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3891 return GST_PAD_PROBE_OK;
3893 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3897 /* check player and subtitlebin are created */
3898 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3899 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3901 if (position == 0) {
3902 LOGD("nothing to do\n");
3904 return MM_ERROR_NONE;
3908 case MM_PLAYER_POS_FORMAT_TIME:
3910 /* check current postion */
3911 player->adjust_subtitle_pos = position;
3913 LOGD("save adjust_subtitle_pos in player") ;
3919 LOGW("invalid format.\n");
3921 return MM_ERROR_INVALID_ARGUMENT;
3927 return MM_ERROR_NONE;
3931 * This function is to create audio or video pipeline for playing.
3933 * @param player [in] handle of player
3935 * @return This function returns zero on success.
3940 __mmplayer_gst_create_pipeline(mm_player_t* player)
3942 int ret = MM_ERROR_NONE;
3943 MMPlayerGstElement *mainbin = NULL;
3944 MMHandleType attrs = 0;
3945 gint mode = MM_PLAYER_PD_MODE_NONE;
3948 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3950 /* get profile attribute */
3951 attrs = MMPLAYER_GET_ATTRS(player);
3953 LOGE("failed to get content attribute");
3957 /* create pipeline handles */
3958 if (player->pipeline) {
3959 LOGE("pipeline should be released before create new one");
3963 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3964 if (player->pipeline == NULL)
3967 /* create mainbin */
3968 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3969 if (mainbin == NULL)
3972 /* create pipeline */
3973 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3974 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3975 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3976 LOGE("failed to create pipeline");
3981 player->pipeline->mainbin = mainbin;
3984 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
3985 player->pd_mode = mode;
3987 /* create the source and decoder elements */
3988 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3989 ret = __mmplayer_gst_build_es_pipeline(player);
3990 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
3991 ret = __mmplayer_gst_build_pd_pipeline(player);
3993 ret = __mmplayer_gst_build_pipeline(player);
3996 if (ret != MM_ERROR_NONE) {
3997 LOGE("failed to create some elements");
4001 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4002 if (__mmplayer_check_subtitle(player)) {
4003 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
4004 LOGE("failed to create text pipeline");
4008 ret = __mmplayer_gst_add_bus_watch(player);
4009 if (ret != MM_ERROR_NONE) {
4010 LOGE("failed to add bus watch");
4015 return MM_ERROR_NONE;
4018 __mmplayer_gst_destroy_pipeline(player);
4019 return MM_ERROR_PLAYER_INTERNAL;
4023 __mmplayer_reset_gapless_state(mm_player_t* player)
4026 MMPLAYER_RETURN_IF_FAIL(player
4028 && player->pipeline->audiobin
4029 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4031 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4038 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4041 int ret = MM_ERROR_NONE;
4045 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4047 /* cleanup stuffs */
4048 MMPLAYER_FREEIF(player->type);
4049 player->no_more_pad = FALSE;
4050 player->num_dynamic_pad = 0;
4051 player->demux_pad_index = 0;
4053 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4054 player->subtitle_language_list = NULL;
4055 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4057 __mmplayer_reset_gapless_state(player);
4059 if (player->streamer) {
4060 __mm_player_streaming_deinitialize(player->streamer);
4061 __mm_player_streaming_destroy(player->streamer);
4062 player->streamer = NULL;
4065 /* cleanup unlinked mime type */
4066 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4067 MMPLAYER_FREEIF(player->unlinked_video_mime);
4068 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4070 /* cleanup running stuffs */
4071 __mmplayer_cancel_eos_timer(player);
4073 /* cleanup gst stuffs */
4074 if (player->pipeline) {
4075 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4076 GstTagList* tag_list = player->pipeline->tag_list;
4078 /* first we need to disconnect all signal hander */
4079 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4082 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4083 MMPlayerGstElement* videobin = player->pipeline->videobin;
4084 MMPlayerGstElement* textbin = player->pipeline->textbin;
4085 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4086 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4087 gst_object_unref(bus);
4089 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4090 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4091 if (ret != MM_ERROR_NONE) {
4092 LOGE("fail to change state to NULL\n");
4093 return MM_ERROR_PLAYER_INTERNAL;
4096 LOGW("succeeded in changing state to NULL\n");
4098 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4101 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4102 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4104 /* free avsysaudiosink
4105 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4106 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4108 MMPLAYER_FREEIF(audiobin);
4109 MMPLAYER_FREEIF(videobin);
4110 MMPLAYER_FREEIF(textbin);
4111 MMPLAYER_FREEIF(mainbin);
4115 gst_tag_list_free(tag_list);
4117 MMPLAYER_FREEIF(player->pipeline);
4119 MMPLAYER_FREEIF(player->album_art);
4121 if (player->v_stream_caps) {
4122 gst_caps_unref(player->v_stream_caps);
4123 player->v_stream_caps = NULL;
4125 if (player->a_stream_caps) {
4126 gst_caps_unref(player->a_stream_caps);
4127 player->a_stream_caps = NULL;
4130 if (player->s_stream_caps) {
4131 gst_caps_unref(player->s_stream_caps);
4132 player->s_stream_caps = NULL;
4134 __mmplayer_track_destroy(player);
4136 if (player->sink_elements)
4137 g_list_free(player->sink_elements);
4138 player->sink_elements = NULL;
4140 if (player->bufmgr) {
4141 tbm_bufmgr_deinit(player->bufmgr);
4142 player->bufmgr = NULL;
4145 LOGW("finished destroy pipeline\n");
4152 static int __mmplayer_gst_realize(mm_player_t* player)
4155 int ret = MM_ERROR_NONE;
4159 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4161 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4163 ret = __mmplayer_gst_create_pipeline(player);
4165 LOGE("failed to create pipeline\n");
4169 /* set pipeline state to READY */
4170 /* NOTE : state change to READY must be performed sync. */
4171 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4172 ret = __mmplayer_gst_set_state(player,
4173 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4175 if (ret != MM_ERROR_NONE) {
4176 /* return error if failed to set state */
4177 LOGE("failed to set READY state");
4181 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4183 /* create dot before error-return. for debugging */
4184 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4191 static int __mmplayer_gst_unrealize(mm_player_t* player)
4193 int ret = MM_ERROR_NONE;
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4199 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4200 MMPLAYER_PRINT_STATE(player);
4202 /* release miscellaneous information */
4203 __mmplayer_release_misc(player);
4205 /* destroy pipeline */
4206 ret = __mmplayer_gst_destroy_pipeline(player);
4207 if (ret != MM_ERROR_NONE) {
4208 LOGE("failed to destory pipeline\n");
4212 /* release miscellaneous information.
4213 these info needs to be released after pipeline is destroyed. */
4214 __mmplayer_release_misc_post(player);
4216 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4224 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4229 LOGW("set_message_callback is called with invalid player handle\n");
4230 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4233 player->msg_cb = callback;
4234 player->msg_cb_param = user_param;
4236 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4240 return MM_ERROR_NONE;
4243 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4245 int ret = MM_ERROR_NONE;
4250 MMPLAYER_RETURN_VAL_IF_FAIL(uri , FALSE);
4251 MMPLAYER_RETURN_VAL_IF_FAIL(data , FALSE);
4252 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), FALSE);
4254 memset(data, 0, sizeof(MMPlayerParseProfile));
4256 if (strstr(uri, "es_buff://")) {
4257 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4258 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4259 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4260 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4262 tmp = g_ascii_strdown(uri, strlen(uri));
4263 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4264 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4266 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4268 } else if (strstr(uri, "mms://")) {
4269 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4270 } else if ((path = strstr(uri, "mem://"))) {
4271 ret = __mmplayer_set_mem_uri(data, path, param);
4273 ret = __mmplayer_set_file_uri(data, uri);
4276 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4277 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4278 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4279 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4281 /* dump parse result */
4282 SECURE_LOGW("incoming uri : %s\n", uri);
4283 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4284 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4292 __mmplayer_can_do_interrupt(mm_player_t *player)
4294 if (!player || !player->pipeline || !player->attrs) {
4295 LOGW("not initialized");
4299 if (player->audio_stream_render_cb) {
4300 LOGW("not support in pcm extraction mode");
4304 /* check if seeking */
4305 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4306 MMMessageParamType msg_param;
4307 memset(&msg_param, 0, sizeof(MMMessageParamType));
4308 msg_param.code = MM_ERROR_PLAYER_SEEK;
4309 player->seek_state = MMPLAYER_SEEK_NONE;
4310 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4314 /* check other thread */
4315 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4316 LOGW("locked already, cmd state : %d", player->cmd);
4318 /* check application command */
4319 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4320 LOGW("playing.. should wait cmd lock then, will be interrupted");
4322 /* lock will be released at mrp_resource_release_cb() */
4323 MMPLAYER_CMD_LOCK(player);
4326 LOGW("nothing to do");
4329 LOGW("can interrupt immediately");
4333 FAILED: /* with CMD UNLOCKED */
4336 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4341 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4344 mm_player_t *player = NULL;
4348 if (user_data == NULL) {
4349 LOGE("- user_data is null\n");
4352 player = (mm_player_t *)user_data;
4354 /* do something to release resource here.
4355 * player stop and interrupt forwarding */
4356 if (!__mmplayer_can_do_interrupt(player)) {
4357 LOGW("no need to interrupt, so leave");
4359 MMMessageParamType msg = {0, };
4362 player->interrupted_by_resource = TRUE;
4364 /* get last play position */
4365 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4366 LOGW("failed to get play position.");
4368 msg.union_type = MM_MSG_UNION_TIME;
4369 msg.time.elapsed = pos;
4370 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4372 LOGD("video resource conflict so, resource will be freed by unrealizing");
4373 if (_mmplayer_unrealize((MMHandleType)player))
4374 LOGW("failed to unrealize");
4376 /* lock is called in __mmplayer_can_do_interrupt() */
4377 MMPLAYER_CMD_UNLOCK(player);
4380 if (res == player->video_overlay_resource)
4381 player->video_overlay_resource = FALSE;
4383 player->video_decoder_resource = FALSE;
4391 __mmplayer_initialize_video_roi(mm_player_t *player)
4393 player->video_roi.scale_x = 0.0;
4394 player->video_roi.scale_y = 0.0;
4395 player->video_roi.scale_width = 1.0;
4396 player->video_roi.scale_height = 1.0;
4400 _mmplayer_create_player(MMHandleType handle)
4402 int ret = MM_ERROR_PLAYER_INTERNAL;
4403 bool enabled = false;
4405 mm_player_t* player = MM_PLAYER_CAST(handle);
4409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4411 /* initialize player state */
4412 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4413 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4414 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4415 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4417 /* check current state */
4418 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4420 /* construct attributes */
4421 player->attrs = _mmplayer_construct_attribute(handle);
4423 if (!player->attrs) {
4424 LOGE("Failed to construct attributes\n");
4428 /* initialize gstreamer with configured parameter */
4429 if (!__mmplayer_init_gstreamer(player)) {
4430 LOGE("Initializing gstreamer failed\n");
4431 _mmplayer_deconstruct_attribute(handle);
4435 /* create lock. note that g_tread_init() has already called in gst_init() */
4436 g_mutex_init(&player->fsink_lock);
4438 /* create update tag lock */
4439 g_mutex_init(&player->update_tag_lock);
4441 /* create gapless play mutex */
4442 g_mutex_init(&player->gapless_play_thread_mutex);
4444 /* create gapless play cond */
4445 g_cond_init(&player->gapless_play_thread_cond);
4447 /* create gapless play thread */
4448 player->gapless_play_thread =
4449 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4450 if (!player->gapless_play_thread) {
4451 LOGE("failed to create gapless play thread");
4452 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4453 g_mutex_clear(&player->gapless_play_thread_mutex);
4454 g_cond_clear(&player->gapless_play_thread_cond);
4458 player->bus_msg_q = g_queue_new();
4459 if (!player->bus_msg_q) {
4460 LOGE("failed to create queue for bus_msg");
4461 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4465 ret = _mmplayer_initialize_video_capture(player);
4466 if (ret != MM_ERROR_NONE) {
4467 LOGE("failed to initialize video capture\n");
4471 /* initialize resource manager */
4472 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4473 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4474 &player->resource_manager)) {
4475 LOGE("failed to initialize resource manager\n");
4476 ret = MM_ERROR_PLAYER_INTERNAL;
4480 if (MMPLAYER_IS_HTTP_PD(player)) {
4481 player->pd_downloader = NULL;
4482 player->pd_file_save_path = NULL;
4485 /* create video bo lock and cond */
4486 g_mutex_init(&player->video_bo_mutex);
4487 g_cond_init(&player->video_bo_cond);
4489 /* create media stream callback mutex */
4490 g_mutex_init(&player->media_stream_cb_lock);
4492 /* create subtitle info lock and cond */
4493 g_mutex_init(&player->subtitle_info_mutex);
4494 g_cond_init(&player->subtitle_info_cond);
4496 player->streaming_type = STREAMING_SERVICE_NONE;
4498 /* give default value of audio effect setting */
4499 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4500 player->sound.rg_enable = false;
4501 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4503 player->play_subtitle = FALSE;
4504 player->has_closed_caption = FALSE;
4505 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4506 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4507 player->pending_resume = FALSE;
4508 if (player->ini.dump_element_keyword[0][0] == '\0')
4509 player->ini.set_dump_element_flag = FALSE;
4511 player->ini.set_dump_element_flag = TRUE;
4513 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4514 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4515 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4517 /* Set video360 settings to their defaults for just-created player.
4520 player->is_360_feature_enabled = FALSE;
4521 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4522 LOGI("spherical feature info: %d", enabled);
4524 player->is_360_feature_enabled = TRUE;
4526 LOGE("failed to get spherical feature info");
4529 player->is_content_spherical = FALSE;
4530 player->is_video360_enabled = TRUE;
4531 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4532 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4533 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4534 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4535 player->video360_zoom = 1.0f;
4536 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4537 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4539 __mmplayer_initialize_video_roi(player);
4541 /* set player state to null */
4542 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4543 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4545 return MM_ERROR_NONE;
4549 g_mutex_clear(&player->fsink_lock);
4551 /* free update tag lock */
4552 g_mutex_clear(&player->update_tag_lock);
4554 g_queue_free(player->bus_msg_q);
4556 /* free gapless play thread */
4557 if (player->gapless_play_thread) {
4558 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4559 player->gapless_play_thread_exit = TRUE;
4560 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4561 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4563 g_thread_join(player->gapless_play_thread);
4564 player->gapless_play_thread = NULL;
4566 g_mutex_clear(&player->gapless_play_thread_mutex);
4567 g_cond_clear(&player->gapless_play_thread_cond);
4570 /* release attributes */
4571 _mmplayer_deconstruct_attribute(handle);
4579 __mmplayer_init_gstreamer(mm_player_t* player)
4581 static gboolean initialized = FALSE;
4582 static const int max_argc = 50;
4584 gchar** argv = NULL;
4585 gchar** argv2 = NULL;
4591 LOGD("gstreamer already initialized.\n");
4596 argc = malloc(sizeof(int));
4597 argv = malloc(sizeof(gchar*) * max_argc);
4598 argv2 = malloc(sizeof(gchar*) * max_argc);
4600 if (!argc || !argv || !argv2)
4603 memset(argv, 0, sizeof(gchar*) * max_argc);
4604 memset(argv2, 0, sizeof(gchar*) * max_argc);
4608 argv[0] = g_strdup("mmplayer");
4611 for (i = 0; i < 5; i++) {
4612 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4613 if (strlen(player->ini.gst_param[i]) > 0) {
4614 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4619 /* we would not do fork for scanning plugins */
4620 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4623 /* check disable registry scan */
4624 if (player->ini.skip_rescan) {
4625 argv[*argc] = g_strdup("--gst-disable-registry-update");
4629 /* check disable segtrap */
4630 if (player->ini.disable_segtrap) {
4631 argv[*argc] = g_strdup("--gst-disable-segtrap");
4635 LOGD("initializing gstreamer with following parameter\n");
4636 LOGD("argc : %d\n", *argc);
4639 for (i = 0; i < arg_count; i++) {
4641 LOGD("argv[%d] : %s\n", i, argv2[i]);
4644 /* initializing gstreamer */
4645 if (!gst_init_check(argc, &argv, &err)) {
4646 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4653 for (i = 0; i < arg_count; i++) {
4654 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4655 MMPLAYER_FREEIF(argv2[i]);
4658 MMPLAYER_FREEIF(argv);
4659 MMPLAYER_FREEIF(argv2);
4660 MMPLAYER_FREEIF(argc);
4670 for (i = 0; i < arg_count; i++) {
4671 LOGD("free[%d] : %s\n", i, argv2[i]);
4672 MMPLAYER_FREEIF(argv2[i]);
4675 MMPLAYER_FREEIF(argv);
4676 MMPLAYER_FREEIF(argv2);
4677 MMPLAYER_FREEIF(argc);
4683 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4687 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4688 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4689 MMPLAYER_FREEIF(player->pd_file_save_path);
4692 return MM_ERROR_NONE;
4696 __mmplayer_check_async_state_transition(mm_player_t* player)
4698 GstState element_state = GST_STATE_VOID_PENDING;
4699 GstState element_pending_state = GST_STATE_VOID_PENDING;
4700 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4701 GstElement * element = NULL;
4702 gboolean async = FALSE;
4704 /* check player handle */
4705 MMPLAYER_RETURN_IF_FAIL(player &&
4707 player->pipeline->mainbin &&
4708 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4711 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4713 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4714 LOGD("don't need to check the pipeline state");
4718 MMPLAYER_PRINT_STATE(player);
4720 /* wait for state transition */
4721 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4722 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4724 if (ret == GST_STATE_CHANGE_FAILURE) {
4725 LOGE(" [%s] state : %s pending : %s \n",
4726 GST_ELEMENT_NAME(element),
4727 gst_element_state_get_name(element_state),
4728 gst_element_state_get_name(element_pending_state));
4730 /* dump state of all element */
4731 __mmplayer_dump_pipeline_state(player);
4736 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4741 _mmplayer_destroy(MMHandleType handle)
4743 mm_player_t* player = MM_PLAYER_CAST(handle);
4747 /* check player handle */
4748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4750 /* destroy can called at anytime */
4751 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4753 /* check async state transition */
4754 __mmplayer_check_async_state_transition(player);
4756 __mmplayer_destroy_streaming_ext(player);
4758 /* release gapless play thread */
4759 if (player->gapless_play_thread) {
4760 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4761 player->gapless_play_thread_exit = TRUE;
4762 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4763 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4765 LOGD("waitting for gapless play thread exit\n");
4766 g_thread_join(player->gapless_play_thread);
4767 g_mutex_clear(&player->gapless_play_thread_mutex);
4768 g_cond_clear(&player->gapless_play_thread_cond);
4769 LOGD("gapless play thread released\n");
4772 _mmplayer_release_video_capture(player);
4774 /* de-initialize resource manager */
4775 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4776 player->resource_manager))
4777 LOGE("failed to deinitialize resource manager\n");
4779 /* release pipeline */
4780 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4781 LOGE("failed to destory pipeline\n");
4782 return MM_ERROR_PLAYER_INTERNAL;
4785 g_queue_free(player->bus_msg_q);
4787 /* release subtitle info lock and cond */
4788 g_mutex_clear(&player->subtitle_info_mutex);
4789 g_cond_clear(&player->subtitle_info_cond);
4791 __mmplayer_release_dump_list(player->dump_list);
4793 /* release miscellaneous information */
4794 __mmplayer_release_misc(player);
4796 /* release miscellaneous information.
4797 these info needs to be released after pipeline is destroyed. */
4798 __mmplayer_release_misc_post(player);
4800 /* release attributes */
4801 _mmplayer_deconstruct_attribute(handle);
4804 g_mutex_clear(&player->fsink_lock);
4807 g_mutex_clear(&player->update_tag_lock);
4809 /* release video bo lock and cond */
4810 g_mutex_clear(&player->video_bo_mutex);
4811 g_cond_clear(&player->video_bo_cond);
4813 /* release media stream callback lock */
4814 g_mutex_clear(&player->media_stream_cb_lock);
4818 return MM_ERROR_NONE;
4822 __mmplayer_realize_streaming_ext(mm_player_t* player)
4824 int ret = MM_ERROR_NONE;
4827 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4829 if (MMPLAYER_IS_HTTP_PD(player)) {
4830 gboolean bret = FALSE;
4832 player->pd_downloader = _mmplayer_create_pd_downloader();
4833 if (!player->pd_downloader) {
4834 LOGE("Unable to create PD Downloader...");
4835 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4838 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4840 if (FALSE == bret) {
4841 LOGE("Unable to create PD Downloader...");
4842 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
4851 _mmplayer_realize(MMHandleType hplayer)
4853 mm_player_t* player = (mm_player_t*)hplayer;
4856 MMHandleType attrs = 0;
4857 int ret = MM_ERROR_NONE;
4861 /* check player handle */
4862 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4864 /* check current state */
4865 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4867 attrs = MMPLAYER_GET_ATTRS(player);
4869 LOGE("fail to get attributes.\n");
4870 return MM_ERROR_PLAYER_INTERNAL;
4872 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4873 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4875 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4876 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4878 if (ret != MM_ERROR_NONE) {
4879 LOGE("failed to parse profile\n");
4884 if (uri && (strstr(uri, "es_buff://"))) {
4885 if (strstr(uri, "es_buff://push_mode"))
4886 player->es_player_push_mode = TRUE;
4888 player->es_player_push_mode = FALSE;
4891 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4892 LOGW("mms protocol is not supported format.\n");
4893 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4896 if (MMPLAYER_IS_HTTP_PD(player))
4897 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
4898 else if (MMPLAYER_IS_STREAMING(player))
4899 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4901 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4903 player->smooth_streaming = FALSE;
4904 player->videodec_linked = 0;
4905 player->audiodec_linked = 0;
4906 player->textsink_linked = 0;
4907 player->is_external_subtitle_present = FALSE;
4908 player->is_external_subtitle_added_now = FALSE;
4909 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4910 player->video360_metadata.is_spherical = -1;
4911 player->is_openal_plugin_used = FALSE;
4912 player->demux_pad_index = 0;
4913 player->subtitle_language_list = NULL;
4914 player->is_subtitle_force_drop = FALSE;
4915 player->last_multiwin_status = FALSE;
4917 __mmplayer_track_initialize(player);
4918 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4920 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4921 player->streamer = __mm_player_streaming_create();
4922 __mm_player_streaming_initialize(player->streamer);
4925 /* realize pipeline */
4926 ret = __mmplayer_gst_realize(player);
4927 if (ret != MM_ERROR_NONE)
4928 LOGE("fail to realize the player.\n");
4930 ret = __mmplayer_realize_streaming_ext(player);
4932 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4940 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
4943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4945 /* destroy can called at anytime */
4946 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
4947 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
4950 return MM_ERROR_NONE;
4954 _mmplayer_unrealize(MMHandleType hplayer)
4956 mm_player_t* player = (mm_player_t*)hplayer;
4957 int ret = MM_ERROR_NONE;
4961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4963 MMPLAYER_CMD_UNLOCK(player);
4964 /* destroy the gst bus msg thread which is created during realize.
4965 this funct have to be called before getting cmd lock. */
4966 __mmplayer_bus_msg_thread_destroy(player);
4967 MMPLAYER_CMD_LOCK(player);
4969 /* check current state */
4970 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4972 /* check async state transition */
4973 __mmplayer_check_async_state_transition(player);
4975 __mmplayer_unrealize_streaming_ext(player);
4977 /* unrealize pipeline */
4978 ret = __mmplayer_gst_unrealize(player);
4980 /* set asm stop if success */
4981 if (MM_ERROR_NONE == ret) {
4982 if (!player->interrupted_by_resource) {
4983 if (player->video_decoder_resource != NULL) {
4984 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4985 player->video_decoder_resource);
4986 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4987 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4989 player->video_decoder_resource = NULL;
4992 if (player->video_overlay_resource != NULL) {
4993 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4994 player->video_overlay_resource);
4995 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4996 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4998 player->video_overlay_resource = NULL;
5001 ret = mm_resource_manager_commit(player->resource_manager);
5002 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
5003 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
5006 LOGE("failed and don't change asm state to stop");
5014 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5016 mm_player_t* player = (mm_player_t*)hplayer;
5018 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5020 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5024 _mmplayer_get_state(MMHandleType hplayer, int* state)
5026 mm_player_t *player = (mm_player_t*)hplayer;
5028 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5030 *state = MMPLAYER_CURRENT_STATE(player);
5032 return MM_ERROR_NONE;
5037 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5039 mm_player_t* player = (mm_player_t*) hplayer;
5040 GstElement* vol_element = NULL;
5045 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5047 LOGD("volume [L]=%f:[R]=%f\n",
5048 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5050 /* invalid factor range or not */
5051 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5052 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5053 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5054 return MM_ERROR_INVALID_ARGUMENT;
5058 /* not support to set other value into each channel */
5059 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5060 return MM_ERROR_INVALID_ARGUMENT;
5062 /* Save volume to handle. Currently the first array element will be saved. */
5063 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5065 /* check pipeline handle */
5066 if (!player->pipeline || !player->pipeline->audiobin) {
5067 LOGD("audiobin is not created yet\n");
5068 LOGD("but, current stored volume will be set when it's created.\n");
5070 /* NOTE : stored volume will be used in create_audiobin
5071 * returning MM_ERROR_NONE here makes application to able to
5072 * set volume at anytime.
5074 return MM_ERROR_NONE;
5077 /* setting volume to volume element */
5078 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5081 LOGD("volume is set [%f]\n", player->sound.volume);
5082 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5087 return MM_ERROR_NONE;
5092 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5094 mm_player_t* player = (mm_player_t*) hplayer;
5099 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5100 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5102 /* returning stored volume */
5103 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5104 volume->level[i] = player->sound.volume;
5108 return MM_ERROR_NONE;
5112 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5114 mm_player_t* player = (mm_player_t*) hplayer;
5115 GstElement* vol_element = NULL;
5119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5121 /* mute value shoud 0 or 1 */
5122 if (mute != 0 && mute != 1) {
5123 LOGE("bad mute value\n");
5125 /* FIXIT : definitly, we need _BAD_PARAM error code */
5126 return MM_ERROR_INVALID_ARGUMENT;
5129 player->sound.mute = mute;
5131 /* just hold mute value if pipeline is not ready */
5132 if (!player->pipeline || !player->pipeline->audiobin) {
5133 LOGD("pipeline is not ready. holding mute value\n");
5134 return MM_ERROR_NONE;
5137 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5139 /* NOTE : volume will only created when the bt is enabled */
5141 LOGD("mute : %d\n", mute);
5142 g_object_set(vol_element, "mute", mute, NULL);
5144 LOGD("volume elemnet is not created. using volume in audiosink\n");
5148 return MM_ERROR_NONE;
5152 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5154 mm_player_t* player = (mm_player_t*) hplayer;
5158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5159 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5161 /* just hold mute value if pipeline is not ready */
5162 if (!player->pipeline || !player->pipeline->audiobin) {
5163 LOGD("pipeline is not ready. returning stored value\n");
5164 *pmute = player->sound.mute;
5165 return MM_ERROR_NONE;
5168 *pmute = player->sound.mute;
5172 return MM_ERROR_NONE;
5176 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5178 mm_player_t* player = (mm_player_t*) hplayer;
5182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5184 player->video_stream_changed_cb = callback;
5185 player->video_stream_changed_cb_user_param = user_param;
5186 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5190 return MM_ERROR_NONE;
5194 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5196 mm_player_t* player = (mm_player_t*) hplayer;
5200 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5202 player->audio_stream_changed_cb = callback;
5203 player->audio_stream_changed_cb_user_param = user_param;
5204 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5208 return MM_ERROR_NONE;
5212 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5214 mm_player_t *player = (mm_player_t*) hplayer;
5218 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5220 player->audio_stream_render_cb = callback;
5221 player->audio_stream_cb_user_param = user_param;
5222 player->audio_stream_sink_sync = sync;
5223 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5227 return MM_ERROR_NONE;
5231 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5233 mm_player_t* player = (mm_player_t*) hplayer;
5237 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5239 if (callback && !player->bufmgr)
5240 player->bufmgr = tbm_bufmgr_init(-1);
5242 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5243 player->video_stream_cb = callback;
5244 player->video_stream_cb_user_param = user_param;
5246 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5250 return MM_ERROR_NONE;
5254 __mmplayer_start_streaming_ext(mm_player_t *player)
5256 gint ret = MM_ERROR_NONE;
5259 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5261 if (MMPLAYER_IS_HTTP_PD(player)) {
5262 if (!player->pd_downloader) {
5263 ret = __mmplayer_realize_streaming_ext(player);
5265 if (ret != MM_ERROR_NONE) {
5266 LOGE("failed to realize streaming ext\n");
5271 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5272 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5274 LOGE("ERROR while starting PD...\n");
5275 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5277 ret = MM_ERROR_NONE;
5286 _mmplayer_start(MMHandleType hplayer)
5288 mm_player_t* player = (mm_player_t*) hplayer;
5289 gint ret = MM_ERROR_NONE;
5293 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5295 /* check current state */
5296 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5298 /* PD - start streaming */
5299 ret = __mmplayer_start_streaming_ext(player);
5300 if (ret != MM_ERROR_NONE) {
5301 LOGE("failed to start streaming ext 0x%X", ret);
5305 /* start pipeline */
5306 ret = __mmplayer_gst_start(player);
5307 if (ret != MM_ERROR_NONE)
5308 LOGE("failed to start player.\n");
5310 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5311 LOGD("force playing start even during buffering");
5312 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5320 /* NOTE: post "not supported codec message" to application
5321 * when one codec is not found during AUTOPLUGGING in MSL.
5322 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5323 * And, if any codec is not found, don't send message here.
5324 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5327 __mmplayer_handle_missed_plugin(mm_player_t* player)
5329 MMMessageParamType msg_param;
5330 memset(&msg_param, 0, sizeof(MMMessageParamType));
5331 gboolean post_msg_direct = FALSE;
5335 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5337 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5338 player->not_supported_codec, player->can_support_codec);
5340 if (player->not_found_demuxer) {
5341 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5342 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5344 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5345 MMPLAYER_FREEIF(msg_param.data);
5347 return MM_ERROR_NONE;
5350 if (player->not_supported_codec) {
5351 if (player->can_support_codec) {
5352 // There is one codec to play
5353 post_msg_direct = TRUE;
5355 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5356 post_msg_direct = TRUE;
5359 if (post_msg_direct) {
5360 MMMessageParamType msg_param;
5361 memset(&msg_param, 0, sizeof(MMMessageParamType));
5363 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5364 LOGW("not found AUDIO codec, posting error code to application.\n");
5366 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5367 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5368 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5369 LOGW("not found VIDEO codec, posting error code to application.\n");
5371 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5372 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5375 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5377 MMPLAYER_FREEIF(msg_param.data);
5379 return MM_ERROR_NONE;
5381 // no any supported codec case
5382 LOGW("not found any codec, posting error code to application.\n");
5384 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5385 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5386 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5388 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5389 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5392 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5394 MMPLAYER_FREEIF(msg_param.data);
5400 return MM_ERROR_NONE;
5403 static void __mmplayer_check_pipeline(mm_player_t* player)
5405 GstState element_state = GST_STATE_VOID_PENDING;
5406 GstState element_pending_state = GST_STATE_VOID_PENDING;
5408 int ret = MM_ERROR_NONE;
5410 if (player->gapless.reconfigure) {
5411 LOGW("pipeline is under construction.\n");
5413 MMPLAYER_PLAYBACK_LOCK(player);
5414 MMPLAYER_PLAYBACK_UNLOCK(player);
5416 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5418 /* wait for state transition */
5419 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5421 if (ret == GST_STATE_CHANGE_FAILURE)
5422 LOGE("failed to change pipeline state within %d sec\n", timeout);
5426 /* NOTE : it should be able to call 'stop' anytime*/
5428 _mmplayer_stop(MMHandleType hplayer)
5430 mm_player_t* player = (mm_player_t*)hplayer;
5431 int ret = MM_ERROR_NONE;
5435 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5437 /* check current state */
5438 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5440 /* check pipline building state */
5441 __mmplayer_check_pipeline(player);
5442 __mmplayer_reset_gapless_state(player);
5444 /* NOTE : application should not wait for EOS after calling STOP */
5445 __mmplayer_cancel_eos_timer(player);
5447 __mmplayer_unrealize_streaming_ext(player);
5450 player->seek_state = MMPLAYER_SEEK_NONE;
5453 ret = __mmplayer_gst_stop(player);
5455 if (ret != MM_ERROR_NONE)
5456 LOGE("failed to stop player.\n");
5464 _mmplayer_pause(MMHandleType hplayer)
5466 mm_player_t* player = (mm_player_t*)hplayer;
5467 gint64 pos_nsec = 0;
5468 gboolean async = FALSE;
5469 gint ret = MM_ERROR_NONE;
5473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5475 /* check current state */
5476 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5478 /* check pipline building state */
5479 __mmplayer_check_pipeline(player);
5481 switch (MMPLAYER_CURRENT_STATE(player)) {
5482 case MM_PLAYER_STATE_READY:
5484 /* check prepare async or not.
5485 * In the case of streaming playback, it's recommned to avoid blocking wait.
5487 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5488 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5490 /* Changing back sync of rtspsrc to async */
5491 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5492 LOGD("async prepare working mode for rtsp");
5498 case MM_PLAYER_STATE_PLAYING:
5500 /* NOTE : store current point to overcome some bad operation
5501 *(returning zero when getting current position in paused state) of some
5504 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5505 LOGW("getting current position failed in paused\n");
5507 player->last_position = pos_nsec;
5509 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5510 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5511 This causes problem is position calculation during normal pause resume scenarios also.
5512 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5513 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5514 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5515 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5521 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5522 LOGD("doing async pause in case of ms buff src");
5526 /* pause pipeline */
5527 ret = __mmplayer_gst_pause(player, async);
5529 if (ret != MM_ERROR_NONE)
5530 LOGE("failed to pause player. ret : 0x%x\n", ret);
5532 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5533 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5534 LOGE("failed to update display_rotation");
5542 /* in case of streaming, pause could take long time.*/
5544 _mmplayer_abort_pause(MMHandleType hplayer)
5546 mm_player_t* player = (mm_player_t*)hplayer;
5547 int ret = MM_ERROR_NONE;
5551 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5553 player->pipeline->mainbin,
5554 MM_ERROR_PLAYER_NOT_INITIALIZED);
5556 LOGD("set the pipeline state to READY");
5558 /* set state to READY */
5559 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5560 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5561 if (ret != MM_ERROR_NONE) {
5562 LOGE("fail to change state to READY");
5563 return MM_ERROR_PLAYER_INTERNAL;
5566 LOGD("succeeded in changing state to READY");
5572 _mmplayer_resume(MMHandleType hplayer)
5574 mm_player_t* player = (mm_player_t*)hplayer;
5575 int ret = MM_ERROR_NONE;
5576 gboolean async = FALSE;
5580 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5582 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5583 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5584 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5588 /* Changing back sync mode rtspsrc to async */
5589 LOGD("async resume for rtsp case");
5593 /* check current state */
5594 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5596 ret = __mmplayer_gst_resume(player, async);
5597 if (ret != MM_ERROR_NONE)
5598 LOGE("failed to resume player.\n");
5600 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5601 LOGD("force resume even during buffering");
5602 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5611 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5613 mm_player_t* player = (mm_player_t*)hplayer;
5614 gint64 pos_nsec = 0;
5615 int ret = MM_ERROR_NONE;
5617 signed long long start = 0, stop = 0;
5618 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5621 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5622 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5624 /* The sound of video is not supported under 0.0 and over 2.0. */
5625 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5626 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5629 _mmplayer_set_mute(hplayer, mute);
5631 if (player->playback_rate == rate)
5632 return MM_ERROR_NONE;
5634 /* If the position is reached at start potion during fast backward, EOS is posted.
5635 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5637 player->playback_rate = rate;
5639 current_state = MMPLAYER_CURRENT_STATE(player);
5641 if (current_state != MM_PLAYER_STATE_PAUSED)
5642 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5644 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5646 if ((current_state == MM_PLAYER_STATE_PAUSED)
5647 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5648 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5649 pos_nsec = player->last_position;
5654 stop = GST_CLOCK_TIME_NONE;
5656 start = GST_CLOCK_TIME_NONE;
5660 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5661 player->playback_rate,
5663 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5664 GST_SEEK_TYPE_SET, start,
5665 GST_SEEK_TYPE_SET, stop)) {
5666 LOGE("failed to set speed playback\n");
5667 return MM_ERROR_PLAYER_SEEK;
5670 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5674 return MM_ERROR_NONE;;
5678 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5680 mm_player_t* player = (mm_player_t*)hplayer;
5681 int ret = MM_ERROR_NONE;
5685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5687 /* check pipline building state */
5688 __mmplayer_check_pipeline(player);
5690 ret = __mmplayer_gst_set_position(player, position, FALSE);
5698 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5700 mm_player_t* player = (mm_player_t*)hplayer;
5701 int ret = MM_ERROR_NONE;
5703 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5705 ret = __mmplayer_gst_get_position(player, position);
5711 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5713 mm_player_t* player = (mm_player_t*)hplayer;
5714 int ret = MM_ERROR_NONE;
5716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5717 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5719 *duration = player->duration;
5724 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5726 mm_player_t* player = (mm_player_t*)hplayer;
5727 int ret = MM_ERROR_NONE;
5729 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5731 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5737 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5739 mm_player_t* player = (mm_player_t*)hplayer;
5740 int ret = MM_ERROR_NONE;
5744 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5746 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5754 __mmplayer_is_midi_type(gchar* str_caps)
5756 if ((g_strrstr(str_caps, "audio/midi")) ||
5757 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5758 (g_strrstr(str_caps, "application/x-smaf")) ||
5759 (g_strrstr(str_caps, "audio/x-imelody")) ||
5760 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5761 (g_strrstr(str_caps, "audio/xmf")) ||
5762 (g_strrstr(str_caps, "audio/mxmf"))) {
5771 __mmplayer_is_only_mp3_type(gchar *str_caps)
5773 if (g_strrstr(str_caps, "application/x-id3") ||
5774 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5780 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5782 GstStructure* caps_structure = NULL;
5783 gint samplerate = 0;
5787 MMPLAYER_RETURN_IF_FAIL(player && caps);
5789 caps_structure = gst_caps_get_structure(caps, 0);
5791 /* set stream information */
5792 gst_structure_get_int(caps_structure, "rate", &samplerate);
5793 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5795 gst_structure_get_int(caps_structure, "channels", &channels);
5796 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5798 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5802 __mmplayer_update_content_type_info(mm_player_t* player)
5805 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5807 if (__mmplayer_is_midi_type(player->type)) {
5808 player->bypass_audio_effect = TRUE;
5809 } else if (g_strrstr(player->type, "application/x-hls")) {
5810 /* If it can't know exact type when it parses uri because of redirection case,
5811 * it will be fixed by typefinder or when doing autoplugging.
5813 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5814 if (player->streamer) {
5815 player->streamer->is_adaptive_streaming = TRUE;
5816 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5817 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5819 } else if (g_strrstr(player->type, "application/dash+xml")) {
5820 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5821 if (player->streamer) {
5822 player->streamer->is_adaptive_streaming = TRUE;
5823 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5827 LOGD("uri type : %d", player->profile.uri_type);
5832 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5833 GstCaps *caps, gpointer data)
5835 mm_player_t* player = (mm_player_t*)data;
5840 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5842 /* store type string */
5843 MMPLAYER_FREEIF(player->type);
5844 player->type = gst_caps_to_string(caps);
5846 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5847 player, player->type, probability, gst_caps_get_size(caps));
5850 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5851 (g_strrstr(player->type, "audio/x-raw-int"))) {
5852 LOGE("not support media format\n");
5854 if (player->msg_posted == FALSE) {
5855 MMMessageParamType msg_param;
5856 memset(&msg_param, 0, sizeof(MMMessageParamType));
5858 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5859 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5861 /* don't post more if one was sent already */
5862 player->msg_posted = TRUE;
5867 __mmplayer_update_content_type_info(player);
5869 pad = gst_element_get_static_pad(tf, "src");
5871 LOGE("fail to get typefind src pad.\n");
5875 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5876 gboolean async = FALSE;
5877 LOGE("failed to autoplug %s\n", player->type);
5879 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5881 if (async && player->msg_posted == FALSE)
5882 __mmplayer_handle_missed_plugin(player);
5888 gst_object_unref(GST_OBJECT(pad));
5896 __mmplayer_gst_make_decodebin(mm_player_t* player)
5898 GstElement *decodebin = NULL;
5902 /* create decodebin */
5903 decodebin = gst_element_factory_make("decodebin", NULL);
5906 LOGE("fail to create decodebin\n");
5910 /* raw pad handling signal */
5911 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5912 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5914 /* no-more-pad pad handling signal */
5915 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5916 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5918 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5919 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5921 /* This signal is emitted when a pad for which there is no further possible
5922 decoding is added to the decodebin.*/
5923 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5924 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5926 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5927 before looking for any elements that can handle that stream.*/
5928 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5929 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5931 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5932 before looking for any elements that can handle that stream.*/
5933 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5934 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5936 /* This signal is emitted once decodebin has finished decoding all the data.*/
5937 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5938 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5940 /* This signal is emitted when a element is added to the bin.*/
5941 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5942 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5949 __mmplayer_gst_make_queue2(mm_player_t *player)
5951 GstElement* queue2 = NULL;
5952 gint64 dur_bytes = 0L;
5953 guint max_buffer_size_bytes = 0;
5954 MMPlayerGstElement *mainbin = NULL;
5955 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5958 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5960 mainbin = player->pipeline->mainbin;
5962 queue2 = gst_element_factory_make("queue2", "queue2");
5964 LOGE("failed to create buffering queue element");
5968 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5969 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5971 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5973 if (dur_bytes > 0) {
5974 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5975 type = MUXED_BUFFER_TYPE_FILE;
5977 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5978 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5984 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5985 * skip the pull mode(file or ring buffering) setting. */
5986 if (!g_strrstr(player->type, "video/mpegts")) {
5987 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5988 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5990 __mm_player_streaming_set_queue2(player->streamer,
5993 max_buffer_size_bytes,
5994 player->ini.http_buffering_time,
5995 1.0, /* no meaning */
5996 player->ini.http_buffering_limit, /* no meaning */
5998 player->http_file_buffering_path,
5999 (guint64)dur_bytes);
6006 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
6008 MMPlayerGstElement* mainbin = NULL;
6009 GstElement* decodebin = NULL;
6010 GstElement* queue2 = NULL;
6011 GstPad* sinkpad = NULL;
6012 GstPad* qsrcpad = NULL;
6013 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6016 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6018 mainbin = player->pipeline->mainbin;
6020 if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
6022 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6023 LOGW("need to check: muxed buffer is not null");
6026 queue2 = __mmplayer_gst_make_queue2(player);
6028 LOGE("failed to make queue2");
6032 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6033 LOGE("failed to add buffering queue");
6037 sinkpad = gst_element_get_static_pad(queue2, "sink");
6038 qsrcpad = gst_element_get_static_pad(queue2, "src");
6040 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6041 LOGE("failed to link [%s:%s]-[%s:%s]",
6042 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6046 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6047 LOGE("failed to sync queue2 state with parent");
6051 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6052 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6056 gst_object_unref(GST_OBJECT(sinkpad));
6060 /* create decodebin */
6061 decodebin = __mmplayer_gst_make_decodebin(player);
6063 LOGE("failed to make decodebin");
6067 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6068 LOGE("failed to add decodebin\n");
6072 /* to force caps on the decodebin element and avoid reparsing stuff by
6073 * typefind. It also avoids a deadlock in the way typefind activates pads in
6074 * the state change */
6075 g_object_set(decodebin, "sink-caps", caps, NULL);
6077 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6079 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6080 LOGE("failed to link [%s:%s]-[%s:%s]",
6081 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6085 gst_object_unref(GST_OBJECT(sinkpad));
6088 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6089 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6091 /* set decodebin property about buffer in streaming playback. *
6092 * in case of HLS/DASH, it does not need to have big buffer *
6093 * because it is kind of adaptive streaming. */
6094 if (!MMPLAYER_IS_HTTP_PD(player) &&
6095 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6096 gdouble high_percent = 0.0;
6098 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6099 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6101 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6102 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6104 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6105 "high-percent", (gint)high_percent,
6106 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6107 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6108 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6109 "max-size-buffers", 0, NULL); // disable or automatic
6112 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6113 LOGE("failed to sync decodebin state with parent\n");
6124 gst_object_unref(GST_OBJECT(sinkpad));
6127 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6128 * You need to explicitly set elements to the NULL state before
6129 * dropping the final reference, to allow them to clean up.
6131 gst_element_set_state(queue2, GST_STATE_NULL);
6133 /* And, it still has a parent "player".
6134 * You need to let the parent manage the object instead of unreffing the object directly.
6136 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6137 gst_object_unref(queue2);
6142 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6143 * You need to explicitly set elements to the NULL state before
6144 * dropping the final reference, to allow them to clean up.
6146 gst_element_set_state(decodebin, GST_STATE_NULL);
6148 /* And, it still has a parent "player".
6149 * You need to let the parent manage the object instead of unreffing the object directly.
6152 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6153 gst_object_unref(decodebin);
6161 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6165 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6166 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6168 LOGD("class : %s, mime : %s \n", factory_class, mime);
6170 /* add missing plugin */
6171 /* NOTE : msl should check missing plugin for image mime type.
6172 * Some motion jpeg clips can have playable audio track.
6173 * So, msl have to play audio after displaying popup written video format not supported.
6175 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6176 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6177 LOGD("not found demuxer\n");
6178 player->not_found_demuxer = TRUE;
6179 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6185 if (!g_strrstr(factory_class, "Demuxer")) {
6186 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6187 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6188 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6190 /* check that clip have multi tracks or not */
6191 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6192 LOGD("video plugin is already linked\n");
6194 LOGW("add VIDEO to missing plugin\n");
6195 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6196 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6198 } else if (g_str_has_prefix(mime, "audio")) {
6199 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6200 LOGD("audio plugin is already linked\n");
6202 LOGW("add AUDIO to missing plugin\n");
6203 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6204 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6212 return MM_ERROR_NONE;
6217 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6219 mm_player_t* player = (mm_player_t*)data;
6223 MMPLAYER_RETURN_IF_FAIL(player);
6225 /* remove fakesink. */
6226 if (!__mmplayer_gst_remove_fakesink(player,
6227 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6228 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6229 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6230 * source element are not same. To overcome this situation, this function will called
6231 * several places and several times. Therefore, this is not an error case.
6236 LOGD("[handle: %p] pipeline has completely constructed", player);
6238 if ((player->ini.async_start) &&
6239 (player->msg_posted == FALSE) &&
6240 (player->cmd >= MMPLAYER_COMMAND_START))
6241 __mmplayer_handle_missed_plugin(player);
6243 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6247 __mmplayer_check_profile(void)
6250 static int profile_tv = -1;
6252 if (__builtin_expect(profile_tv != -1, 1))
6255 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6256 switch (*profileName) {
6271 __mmplayer_get_next_uri(mm_player_t *player)
6273 MMPlayerParseProfile profile;
6275 guint num_of_list = 0;
6278 num_of_list = g_list_length(player->uri_info.uri_list);
6279 uri_idx = player->uri_info.uri_idx;
6281 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6282 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6283 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6285 LOGW("next uri does not exist");
6289 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6290 LOGE("failed to parse profile");
6294 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6295 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6296 LOGW("uri type is not supported(%d)", profile.uri_type);
6300 LOGD("success to find next uri %d", uri_idx);
6304 if (uri_idx == num_of_list) {
6305 LOGE("failed to find next uri");
6309 player->uri_info.uri_idx = uri_idx;
6310 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6312 if (mm_attrs_commit_all(player->attrs)) {
6313 LOGE("failed to commit");
6317 SECURE_LOGD("next playback uri: %s", uri);
6322 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6324 #define REPEAT_COUNT_INFINITELY -1
6325 #define REPEAT_COUNT_MIN 2
6327 MMHandleType attrs = 0;
6328 gint mode = MM_PLAYER_PD_MODE_NONE;
6332 guint num_of_list = 0;
6333 int profile_tv = -1;
6337 LOGD("checking for gapless play option");
6339 if (player->pipeline->textbin) {
6340 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6344 attrs = MMPLAYER_GET_ATTRS(player);
6346 LOGE("fail to get attributes.\n");
6350 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6352 /* gapless playback is not supported in case of video at TV profile. */
6353 profile_tv = __mmplayer_check_profile();
6354 if (profile_tv && video) {
6355 LOGW("not support video gapless playback");
6359 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6366 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6367 LOGE("failed to get play count");
6369 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6370 LOGE("failed to get gapless mode");
6372 /* check repeat count in case of audio */
6374 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6375 LOGW("gapless is disabled");
6379 num_of_list = g_list_length(player->uri_info.uri_list);
6381 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6383 if (num_of_list == 0) {
6384 /* audio looping path */
6385 if (count >= REPEAT_COUNT_MIN) {
6386 /* decrease play count */
6387 /* we succeeded to rewind. update play count and then wait for next EOS */
6390 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6392 /* commit attribute */
6393 if (mm_attrs_commit_all(attrs))
6394 LOGE("failed to commit attribute");
6395 } else if (count != REPEAT_COUNT_INFINITELY) {
6396 LOGD("there is no next uri and no repeat");
6400 LOGD("looping cnt %d", count);
6402 /* gapless playback path */
6403 if (!__mmplayer_get_next_uri(player)) {
6404 LOGE("failed to get next uri");
6412 LOGE("unable to play gapless path. EOS will be posted soon");
6417 __mmplayer_initialize_gapless_play(mm_player_t *player)
6423 player->smooth_streaming = FALSE;
6424 player->videodec_linked = 0;
6425 player->audiodec_linked = 0;
6426 player->textsink_linked = 0;
6427 player->is_external_subtitle_present = FALSE;
6428 player->is_external_subtitle_added_now = FALSE;
6429 player->not_supported_codec = MISSING_PLUGIN_NONE;
6430 player->can_support_codec = FOUND_PLUGIN_NONE;
6431 player->pending_seek.is_pending = FALSE;
6432 player->pending_seek.pos = 0;
6433 player->msg_posted = FALSE;
6434 player->has_many_types = FALSE;
6435 player->no_more_pad = FALSE;
6436 player->not_found_demuxer = 0;
6437 player->seek_state = MMPLAYER_SEEK_NONE;
6438 player->is_subtitle_force_drop = FALSE;
6439 player->play_subtitle = FALSE;
6440 player->adjust_subtitle_pos = 0;
6442 player->total_bitrate = 0;
6443 player->total_maximum_bitrate = 0;
6445 __mmplayer_track_initialize(player);
6446 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6448 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6449 player->bitrate[i] = 0;
6450 player->maximum_bitrate[i] = 0;
6453 if (player->v_stream_caps) {
6454 gst_caps_unref(player->v_stream_caps);
6455 player->v_stream_caps = NULL;
6458 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6460 /* clean found parsers */
6461 if (player->parsers) {
6462 GList *parsers = player->parsers;
6463 for (; parsers; parsers = g_list_next(parsers)) {
6464 gchar *name = parsers->data;
6465 MMPLAYER_FREEIF(name);
6467 g_list_free(player->parsers);
6468 player->parsers = NULL;
6471 /* clean found audio decoders */
6472 if (player->audio_decoders) {
6473 GList *a_dec = player->audio_decoders;
6474 for (; a_dec; a_dec = g_list_next(a_dec)) {
6475 gchar *name = a_dec->data;
6476 MMPLAYER_FREEIF(name);
6478 g_list_free(player->audio_decoders);
6479 player->audio_decoders = NULL;
6486 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6488 MMPlayerGstElement *mainbin = NULL;
6489 MMMessageParamType msg_param = {0,};
6490 GstElement *element = NULL;
6491 MMHandleType attrs = 0;
6493 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6497 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6498 LOGE("player is not initialized");
6502 mainbin = player->pipeline->mainbin;
6503 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6505 attrs = MMPLAYER_GET_ATTRS(player);
6507 LOGE("fail to get attributes");
6511 /* Initialize Player values */
6512 __mmplayer_initialize_gapless_play(player);
6514 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6516 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6517 LOGE("failed to parse profile");
6518 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6522 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6523 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6524 LOGE("dash or hls is not supportable");
6525 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6529 element = __mmplayer_gst_create_source(player);
6531 LOGE("no source element was created");
6535 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6536 LOGE("failed to add source element to pipeline");
6537 gst_object_unref(GST_OBJECT(element));
6542 /* take source element */
6543 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6544 mainbin[MMPLAYER_M_SRC].gst = element;
6548 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6549 if (player->streamer == NULL) {
6550 player->streamer = __mm_player_streaming_create();
6551 __mm_player_streaming_initialize(player->streamer);
6554 elem_idx = MMPLAYER_M_TYPEFIND;
6555 element = gst_element_factory_make("typefind", "typefinder");
6556 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6557 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6559 elem_idx = MMPLAYER_M_AUTOPLUG;
6560 element = __mmplayer_gst_make_decodebin(player);
6563 /* check autoplug element is OK */
6565 LOGE("can not create element(%d)", elem_idx);
6569 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6570 LOGE("failed to add sinkbin to pipeline");
6571 gst_object_unref(GST_OBJECT(element));
6576 mainbin[elem_idx].id = elem_idx;
6577 mainbin[elem_idx].gst = element;
6579 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6580 LOGE("Failed to link src - autoplug(or typefind)");
6584 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6585 LOGE("Failed to change state of src element");
6589 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6590 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6591 LOGE("Failed to change state of decodebin");
6595 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6596 LOGE("Failed to change state of src element");
6601 player->gapless.stream_changed = TRUE;
6602 player->gapless.running = TRUE;
6608 MMPLAYER_PLAYBACK_UNLOCK(player);
6610 if (!player->msg_posted) {
6611 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6612 player->msg_posted = TRUE;
6619 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6621 mm_player_selector_t *selector = &player->selector[type];
6622 MMPlayerGstElement *sinkbin = NULL;
6623 enum MainElementID selectorId = MMPLAYER_M_NUM;
6624 enum MainElementID sinkId = MMPLAYER_M_NUM;
6625 GstPad *srcpad = NULL;
6626 GstPad *sinkpad = NULL;
6627 gboolean send_notice = FALSE;
6630 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6632 LOGD("type %d", type);
6635 case MM_PLAYER_TRACK_TYPE_AUDIO:
6636 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6637 sinkId = MMPLAYER_A_BIN;
6638 sinkbin = player->pipeline->audiobin;
6640 case MM_PLAYER_TRACK_TYPE_VIDEO:
6641 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6642 sinkId = MMPLAYER_V_BIN;
6643 sinkbin = player->pipeline->videobin;
6646 case MM_PLAYER_TRACK_TYPE_TEXT:
6647 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6648 sinkId = MMPLAYER_T_BIN;
6649 sinkbin = player->pipeline->textbin;
6652 LOGE("requested type is not supportable");
6657 if (player->pipeline->mainbin[selectorId].gst) {
6660 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6662 if (selector->event_probe_id != 0)
6663 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6664 selector->event_probe_id = 0;
6666 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6667 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6669 if (srcpad && sinkpad) {
6670 /* after getting drained signal there is no data flows, so no need to do pad_block */
6671 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6672 gst_pad_unlink(srcpad, sinkpad);
6674 /* send custom event to sink pad to handle it at video sink */
6676 LOGD("send custom event to sinkpad");
6677 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6678 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6679 gst_pad_send_event(sinkpad, event);
6683 gst_object_unref(sinkpad);
6686 gst_object_unref(srcpad);
6689 LOGD("selector release");
6691 /* release and unref requests pad from the selector */
6692 for (n = 0; n < selector->channels->len; n++) {
6693 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6694 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6696 g_ptr_array_set_size(selector->channels, 0);
6698 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6699 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6701 player->pipeline->mainbin[selectorId].gst = NULL;
6709 __mmplayer_deactivate_old_path(mm_player_t *player)
6712 MMPLAYER_RETURN_IF_FAIL(player);
6714 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6715 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6716 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6717 LOGE("deactivate selector error");
6721 __mmplayer_track_destroy(player);
6722 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6724 if (player->streamer) {
6725 __mm_player_streaming_deinitialize(player->streamer);
6726 __mm_player_streaming_destroy(player->streamer);
6727 player->streamer = NULL;
6730 MMPLAYER_PLAYBACK_LOCK(player);
6731 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6738 if (!player->msg_posted) {
6739 MMMessageParamType msg = {0,};
6742 msg.code = MM_ERROR_PLAYER_INTERNAL;
6743 LOGE("gapless_uri_play> deactivate error");
6745 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6746 player->msg_posted = TRUE;
6751 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6753 int result = MM_ERROR_NONE;
6754 mm_player_t* player = (mm_player_t*) hplayer;
6757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6760 player->http_file_buffering_path = (gchar*)file_path;
6761 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6767 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6769 int result = MM_ERROR_NONE;
6770 mm_player_t* player = (mm_player_t*) hplayer;
6773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6775 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6776 if (mm_attrs_commit_all(player->attrs)) {
6777 LOGE("failed to commit the original uri.\n");
6778 result = MM_ERROR_PLAYER_INTERNAL;
6780 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6781 LOGE("failed to add the original uri in the uri list.\n");
6788 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6790 mm_player_t* player = (mm_player_t*) hplayer;
6791 guint num_of_list = 0;
6795 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6796 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6798 if (player->pipeline && player->pipeline->textbin) {
6799 LOGE("subtitle path is enabled.\n");
6800 return MM_ERROR_PLAYER_INVALID_STATE;
6803 num_of_list = g_list_length(player->uri_info.uri_list);
6805 if (is_first_path == TRUE) {
6806 if (num_of_list == 0) {
6807 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6808 LOGD("add original path : %s", uri);
6810 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6811 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6813 LOGD("change original path : %s", uri);
6816 MMHandleType attrs = 0;
6817 attrs = MMPLAYER_GET_ATTRS(player);
6819 if (num_of_list == 0) {
6820 char *original_uri = NULL;
6823 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6825 if (!original_uri) {
6826 LOGE("there is no original uri.");
6827 return MM_ERROR_PLAYER_INVALID_STATE;
6830 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6831 player->uri_info.uri_idx = 0;
6833 LOGD("add original path at first : %s(%d)", original_uri);
6837 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6838 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6842 return MM_ERROR_NONE;
6845 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6847 mm_player_t* player = (mm_player_t*) hplayer;
6848 char *next_uri = NULL;
6849 guint num_of_list = 0;
6852 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6854 num_of_list = g_list_length(player->uri_info.uri_list);
6856 if (num_of_list > 0) {
6857 gint uri_idx = player->uri_info.uri_idx;
6859 if (uri_idx < num_of_list-1)
6864 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6865 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6867 *uri = g_strdup(next_uri);
6871 return MM_ERROR_NONE;
6875 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6876 GstCaps *caps, gpointer data)
6878 mm_player_t* player = (mm_player_t*)data;
6879 const gchar* klass = NULL;
6880 const gchar* mime = NULL;
6881 gchar* caps_str = NULL;
6883 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6884 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6885 caps_str = gst_caps_to_string(caps);
6887 LOGW("unknown type of caps : %s from %s",
6888 caps_str, GST_ELEMENT_NAME(elem));
6890 MMPLAYER_FREEIF(caps_str);
6892 /* There is no available codec. */
6893 __mmplayer_check_not_supported_codec(player, klass, mime);
6897 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6898 GstCaps * caps, gpointer data)
6900 mm_player_t* player = (mm_player_t*)data;
6901 const char* mime = NULL;
6902 gboolean ret = TRUE;
6904 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6905 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6907 if (g_str_has_prefix(mime, "audio")) {
6908 GstStructure* caps_structure = NULL;
6909 gint samplerate = 0;
6911 gchar *caps_str = NULL;
6913 caps_structure = gst_caps_get_structure(caps, 0);
6914 gst_structure_get_int(caps_structure, "rate", &samplerate);
6915 gst_structure_get_int(caps_structure, "channels", &channels);
6917 if ((channels > 0 && samplerate == 0)) {
6918 LOGD("exclude audio...");
6922 caps_str = gst_caps_to_string(caps);
6923 /* set it directly because not sent by TAG */
6924 if (g_strrstr(caps_str, "mobile-xmf"))
6925 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6926 MMPLAYER_FREEIF(caps_str);
6927 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6928 MMMessageParamType msg_param;
6929 memset(&msg_param, 0, sizeof(MMMessageParamType));
6930 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6931 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6932 LOGD("video file is not supported on this device");
6934 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6935 LOGD("already video linked");
6938 LOGD("found new stream");
6945 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6947 int ret = MM_ERROR_NONE;
6949 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6951 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6952 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6954 LOGD("audio codec type: %d", codec_type);
6955 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6956 /* sw codec will be skipped */
6957 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6958 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6959 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6960 ret = MM_ERROR_PLAYER_INTERNAL;
6964 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6965 /* hw codec will be skipped */
6966 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6967 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6968 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6969 ret = MM_ERROR_PLAYER_INTERNAL;
6974 /* set stream information */
6975 if (!player->audiodec_linked)
6976 __mmplayer_set_audio_attrs(player, caps);
6978 /* update codec info */
6979 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6980 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6981 player->audiodec_linked = 1;
6983 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6985 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6987 LOGD("video codec type: %d", codec_type);
6988 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6989 /* sw codec is skipped */
6990 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6991 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6992 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6993 ret = MM_ERROR_PLAYER_INTERNAL;
6997 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6998 /* hw codec is skipped */
6999 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7000 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7001 ret = MM_ERROR_PLAYER_INTERNAL;
7006 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7007 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7009 /* mark video decoder for acquire */
7010 if (player->video_decoder_resource == NULL) {
7011 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7012 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7013 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7014 &player->video_decoder_resource)
7015 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7016 LOGE("could not mark video_decoder resource for acquire");
7017 ret = MM_ERROR_PLAYER_INTERNAL;
7021 LOGW("video decoder resource is already acquired, skip it.");
7022 ret = MM_ERROR_PLAYER_INTERNAL;
7026 player->interrupted_by_resource = FALSE;
7027 /* acquire resources for video playing */
7028 if (mm_resource_manager_commit(player->resource_manager)
7029 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7030 LOGE("could not acquire resources for video decoding\n");
7031 ret = MM_ERROR_PLAYER_INTERNAL;
7036 /* update codec info */
7037 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7038 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7039 player->videodec_linked = 1;
7047 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7048 GstCaps* caps, GstElementFactory* factory, gpointer data)
7050 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7051 We are defining our own and will be removed when it actually exposed */
7053 GST_AUTOPLUG_SELECT_TRY,
7054 GST_AUTOPLUG_SELECT_EXPOSE,
7055 GST_AUTOPLUG_SELECT_SKIP
7056 } GstAutoplugSelectResult;
7058 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7059 mm_player_t* player = (mm_player_t*)data;
7061 gchar* factory_name = NULL;
7062 gchar* caps_str = NULL;
7063 const gchar* klass = NULL;
7066 factory_name = GST_OBJECT_NAME(factory);
7067 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7068 caps_str = gst_caps_to_string(caps);
7070 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7072 /* store type string */
7073 if (player->type == NULL) {
7074 player->type = gst_caps_to_string(caps);
7075 __mmplayer_update_content_type_info(player);
7078 /* filtering exclude keyword */
7079 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7080 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7081 LOGW("skipping [%s] by exculde keyword [%s]",
7082 factory_name, player->ini.exclude_element_keyword[idx]);
7084 result = GST_AUTOPLUG_SELECT_SKIP;
7089 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7090 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7091 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7092 factory_name, player->ini.unsupported_codec_keyword[idx]);
7093 result = GST_AUTOPLUG_SELECT_SKIP;
7098 /* exclude webm format */
7099 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7100 * because webm format is not supportable.
7101 * If webm is disabled in "autoplug-continue", there is no state change
7102 * failure or error because the decodebin will expose the pad directly.
7103 * It make MSL invoke _prepare_async_callback.
7104 * So, we need to disable webm format in "autoplug-select" */
7105 if (caps_str && strstr(caps_str, "webm")) {
7106 LOGW("webm is not supported");
7107 result = GST_AUTOPLUG_SELECT_SKIP;
7111 /* check factory class for filtering */
7112 /* NOTE : msl don't need to use image plugins.
7113 * So, those plugins should be skipped for error handling.
7115 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7116 LOGD("skipping [%s] by not required\n", factory_name);
7117 result = GST_AUTOPLUG_SELECT_SKIP;
7121 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7122 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7123 // TO CHECK : subtitle if needed, add subparse exception.
7124 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7125 result = GST_AUTOPLUG_SELECT_SKIP;
7129 if (g_strrstr(factory_name, "mpegpsdemux")) {
7130 LOGD("skipping PS container - not support\n");
7131 result = GST_AUTOPLUG_SELECT_SKIP;
7135 if (g_strrstr(factory_name, "mssdemux"))
7136 player->smooth_streaming = TRUE;
7138 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7139 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7142 GstStructure *str = NULL;
7143 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7145 /* don't make video because of not required */
7146 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7147 (!player->set_mode.media_packet_video_stream)) {
7148 LOGD("no need video decoding, expose pad");
7149 result = GST_AUTOPLUG_SELECT_EXPOSE;
7153 /* get w/h for omx state-tune */
7154 /* FIXME: deprecated? */
7155 str = gst_caps_get_structure(caps, 0);
7156 gst_structure_get_int(str, "width", &width);
7159 if (player->v_stream_caps) {
7160 gst_caps_unref(player->v_stream_caps);
7161 player->v_stream_caps = NULL;
7164 player->v_stream_caps = gst_caps_copy(caps);
7165 LOGD("take caps for video state tune");
7166 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7170 if (g_strrstr(klass, "Codec/Decoder")) {
7171 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7172 LOGD("skipping %s codec", factory_name);
7173 result = GST_AUTOPLUG_SELECT_SKIP;
7179 MMPLAYER_FREEIF(caps_str);
7185 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7188 //mm_player_t* player = (mm_player_t*)data;
7189 GstCaps* caps = NULL;
7191 LOGD("[Decodebin2] pad-removed signal\n");
7193 caps = gst_pad_query_caps(new_pad, NULL);
7195 gchar* caps_str = NULL;
7196 caps_str = gst_caps_to_string(caps);
7198 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7200 MMPLAYER_FREEIF(caps_str);
7201 gst_caps_unref(caps);
7206 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7208 mm_player_t* player = (mm_player_t*)data;
7209 GstIterator *iter = NULL;
7210 GValue item = { 0, };
7212 gboolean done = FALSE;
7213 gboolean is_all_drained = TRUE;
7216 MMPLAYER_RETURN_IF_FAIL(player);
7218 LOGD("__mmplayer_gst_decode_drained");
7220 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7221 LOGW("Fail to get cmd lock");
7225 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7226 !__mmplayer_verify_gapless_play_path(player)) {
7227 LOGD("decoding is finished.");
7228 __mmplayer_reset_gapless_state(player);
7229 MMPLAYER_CMD_UNLOCK(player);
7233 player->gapless.reconfigure = TRUE;
7235 /* check decodebin src pads whether they received EOS or not */
7236 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7239 switch (gst_iterator_next(iter, &item)) {
7240 case GST_ITERATOR_OK:
7241 pad = g_value_get_object(&item);
7242 if (pad && !GST_PAD_IS_EOS(pad)) {
7243 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7244 is_all_drained = FALSE;
7247 g_value_reset(&item);
7249 case GST_ITERATOR_RESYNC:
7250 gst_iterator_resync(iter);
7252 case GST_ITERATOR_ERROR:
7253 case GST_ITERATOR_DONE:
7258 g_value_unset(&item);
7259 gst_iterator_free(iter);
7261 if (!is_all_drained) {
7262 LOGD("Wait util the all pads get EOS.");
7263 MMPLAYER_CMD_UNLOCK(player);
7268 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7269 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7271 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7272 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7273 __mmplayer_deactivate_old_path(player);
7274 MMPLAYER_CMD_UNLOCK(player);
7280 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7282 mm_player_t* player = (mm_player_t*)data;
7283 const gchar* klass = NULL;
7284 gchar* factory_name = NULL;
7286 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7287 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7289 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7291 if (__mmplayer_add_dump_buffer_probe(player, element))
7292 LOGD("add buffer probe");
7295 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7296 gchar* selected = NULL;
7297 selected = g_strdup(GST_ELEMENT_NAME(element));
7298 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7302 if (g_strrstr(klass, "Parser")) {
7303 gchar* selected = NULL;
7305 selected = g_strdup(factory_name);
7306 player->parsers = g_list_append(player->parsers, selected);
7309 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7310 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7311 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7313 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7314 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7316 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7317 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7318 "max-video-width", player->adaptive_info.limit.width,
7319 "max-video-height", player->adaptive_info.limit.height, NULL);
7321 } else if (g_strrstr(klass, "Demux") || g_strrstr(klass, "Parse")) {
7322 /* FIXIT : first value will be overwritten if there's more
7323 * than 1 demuxer/parser
7326 //LOGD("plugged element is demuxer. take it\n");
7327 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7328 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7330 /*Added for multi audio support */ // Q. del?
7331 if (g_strrstr(klass, "Demux")) {
7332 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].id = MMPLAYER_M_DEMUX_EX;
7333 player->pipeline->mainbin[MMPLAYER_M_DEMUX_EX].gst = element;
7337 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7338 int surface_type = 0;
7340 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7343 // to support trust-zone only
7344 if (g_strrstr(factory_name, "asfdemux")) {
7345 LOGD("set file-location %s\n", player->profile.uri);
7346 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7347 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7348 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7349 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7350 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7351 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7352 (__mmplayer_is_only_mp3_type(player->type))) {
7353 LOGD("[mpegaudioparse] set streaming pull mode.");
7354 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7356 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7357 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7360 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7361 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7362 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7364 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7365 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7367 if (!MMPLAYER_IS_HTTP_PD(player) &&
7368 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7369 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7370 (MMPLAYER_IS_DASH_STREAMING(player)))) {
7371 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7372 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7373 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7382 __mmplayer_release_misc(mm_player_t* player)
7385 bool cur_mode = player->set_mode.rich_audio;
7388 MMPLAYER_RETURN_IF_FAIL(player);
7390 player->video_stream_cb = NULL;
7391 player->video_stream_cb_user_param = NULL;
7392 player->video_stream_prerolled = FALSE;
7394 player->audio_stream_render_cb = NULL;
7395 player->audio_stream_cb_user_param = NULL;
7396 player->audio_stream_sink_sync = false;
7398 player->video_stream_changed_cb = NULL;
7399 player->video_stream_changed_cb_user_param = NULL;
7401 player->audio_stream_changed_cb = NULL;
7402 player->audio_stream_changed_cb_user_param = NULL;
7404 player->sent_bos = FALSE;
7405 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7407 player->seek_state = MMPLAYER_SEEK_NONE;
7409 player->total_bitrate = 0;
7410 player->total_maximum_bitrate = 0;
7412 player->not_found_demuxer = 0;
7414 player->last_position = 0;
7415 player->duration = 0;
7416 player->http_content_size = 0;
7417 player->not_supported_codec = MISSING_PLUGIN_NONE;
7418 player->can_support_codec = FOUND_PLUGIN_NONE;
7419 player->pending_seek.is_pending = FALSE;
7420 player->pending_seek.pos = 0;
7421 player->msg_posted = FALSE;
7422 player->has_many_types = FALSE;
7423 player->is_subtitle_force_drop = FALSE;
7424 player->play_subtitle = FALSE;
7425 player->adjust_subtitle_pos = 0;
7426 player->last_multiwin_status = FALSE;
7427 player->has_closed_caption = FALSE;
7428 player->set_mode.media_packet_video_stream = false;
7429 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7430 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7432 player->set_mode.rich_audio = cur_mode;
7434 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7435 player->bitrate[i] = 0;
7436 player->maximum_bitrate[i] = 0;
7439 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7441 /* remove media stream cb(appsrc cb) */
7442 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7443 player->media_stream_buffer_status_cb[i] = NULL;
7444 player->media_stream_seek_data_cb[i] = NULL;
7445 player->buffer_cb_user_param[i] = NULL;
7446 player->seek_cb_user_param[i] = NULL;
7448 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7450 /* free memory related to audio effect */
7451 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7453 if (player->adaptive_info.var_list) {
7454 g_list_free_full(player->adaptive_info.var_list, g_free);
7455 player->adaptive_info.var_list = NULL;
7458 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7459 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7460 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7462 /* Reset video360 settings to their defaults in case if the pipeline is to be
7465 player->video360_metadata.is_spherical = -1;
7466 player->is_openal_plugin_used = FALSE;
7468 player->is_content_spherical = FALSE;
7469 player->is_video360_enabled = TRUE;
7470 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7471 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7472 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7473 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7474 player->video360_zoom = 1.0f;
7475 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7476 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7478 player->sound.rg_enable = false;
7480 __mmplayer_initialize_video_roi(player);
7485 __mmplayer_release_misc_post(mm_player_t* player)
7487 char *original_uri = NULL;
7490 /* player->pipeline is already released before. */
7492 MMPLAYER_RETURN_IF_FAIL(player);
7494 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7496 /* clean found parsers */
7497 if (player->parsers) {
7498 GList *parsers = player->parsers;
7499 for (; parsers; parsers = g_list_next(parsers)) {
7500 gchar *name = parsers->data;
7501 MMPLAYER_FREEIF(name);
7503 g_list_free(player->parsers);
7504 player->parsers = NULL;
7507 /* clean found audio decoders */
7508 if (player->audio_decoders) {
7509 GList *a_dec = player->audio_decoders;
7510 for (; a_dec; a_dec = g_list_next(a_dec)) {
7511 gchar *name = a_dec->data;
7512 MMPLAYER_FREEIF(name);
7514 g_list_free(player->audio_decoders);
7515 player->audio_decoders = NULL;
7518 /* clean the uri list except original uri */
7519 if (player->uri_info.uri_list) {
7520 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7522 if (player->attrs) {
7523 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7524 LOGD("restore original uri = %s\n", original_uri);
7526 if (mm_attrs_commit_all(player->attrs))
7527 LOGE("failed to commit the original uri.\n");
7530 GList *uri_list = player->uri_info.uri_list;
7531 for (; uri_list; uri_list = g_list_next(uri_list)) {
7532 gchar *uri = uri_list->data;
7533 MMPLAYER_FREEIF(uri);
7535 g_list_free(player->uri_info.uri_list);
7536 player->uri_info.uri_list = NULL;
7539 /* clear the audio stream buffer list */
7540 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7542 /* clear the video stream bo list */
7543 __mmplayer_video_stream_destroy_bo_list(player);
7544 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7546 if (player->profile.input_mem.buf) {
7547 free(player->profile.input_mem.buf);
7548 player->profile.input_mem.buf = NULL;
7550 player->profile.input_mem.len = 0;
7551 player->profile.input_mem.offset = 0;
7553 player->uri_info.uri_idx = 0;
7558 __mmplayer_check_subtitle(mm_player_t* player)
7560 MMHandleType attrs = 0;
7561 char *subtitle_uri = NULL;
7565 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7567 /* get subtitle attribute */
7568 attrs = MMPLAYER_GET_ATTRS(player);
7572 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7573 if (!subtitle_uri || !strlen(subtitle_uri))
7576 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7577 player->is_external_subtitle_present = TRUE;
7585 __mmplayer_cancel_eos_timer(mm_player_t* player)
7587 MMPLAYER_RETURN_IF_FAIL(player);
7589 if (player->eos_timer) {
7590 LOGD("cancel eos timer");
7591 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7592 player->eos_timer = 0;
7599 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7603 MMPLAYER_RETURN_IF_FAIL(player);
7604 MMPLAYER_RETURN_IF_FAIL(sink);
7606 player->sink_elements =
7607 g_list_append(player->sink_elements, sink);
7613 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7617 MMPLAYER_RETURN_IF_FAIL(player);
7618 MMPLAYER_RETURN_IF_FAIL(sink);
7620 player->sink_elements =
7621 g_list_remove(player->sink_elements, sink);
7627 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7628 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7630 MMPlayerSignalItem* item = NULL;
7633 MMPLAYER_RETURN_IF_FAIL(player);
7635 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7636 LOGE("invalid signal type [%d]", type);
7640 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7642 LOGE("cannot connect signal [%s]", signal);
7647 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7648 player->signals[type] = g_list_append(player->signals[type], item);
7654 /* NOTE : be careful with calling this api. please refer to below glib comment
7655 * glib comment : Note that there is a bug in GObject that makes this function much
7656 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7657 * will no longer be called, but, the signal handler is not currently disconnected.
7658 * If the instance is itself being freed at the same time than this doesn't matter,
7659 * since the signal will automatically be removed, but if instance persists,
7660 * then the signal handler will leak. You should not remove the signal yourself
7661 * because in a future versions of GObject, the handler will automatically be
7664 * It's possible to work around this problem in a way that will continue to work
7665 * with future versions of GObject by checking that the signal handler is still
7666 * connected before disconnected it:
7668 * if (g_signal_handler_is_connected(instance, id))
7669 * g_signal_handler_disconnect(instance, id);
7672 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7674 GList* sig_list = NULL;
7675 MMPlayerSignalItem* item = NULL;
7679 MMPLAYER_RETURN_IF_FAIL(player);
7681 LOGD("release signals type : %d", type);
7683 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7684 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7685 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7686 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7687 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7688 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7692 sig_list = player->signals[type];
7694 for (; sig_list; sig_list = sig_list->next) {
7695 item = sig_list->data;
7697 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7698 if (g_signal_handler_is_connected(item->obj, item->sig))
7699 g_signal_handler_disconnect(item->obj, item->sig);
7702 MMPLAYER_FREEIF(item);
7705 g_list_free(player->signals[type]);
7706 player->signals[type] = NULL;
7713 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7715 mm_player_t* player = 0;
7716 int prev_display_surface_type = 0;
7717 void *prev_display_overlay = NULL;
7721 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7722 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7724 player = MM_PLAYER_CAST(handle);
7726 /* check video sinkbin is created */
7727 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7728 LOGE("Videosink is already created");
7729 return MM_ERROR_NONE;
7732 LOGD("videosink element is not yet ready");
7734 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7735 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7737 return MM_ERROR_INVALID_ARGUMENT;
7740 /* load previous attributes */
7741 if (player->attrs) {
7742 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7743 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7744 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7745 if (prev_display_surface_type == surface_type) {
7746 LOGD("incoming display surface type is same as previous one, do nothing..");
7748 return MM_ERROR_NONE;
7751 LOGE("failed to load attributes");
7753 return MM_ERROR_PLAYER_INTERNAL;
7756 /* videobin is not created yet, so we just set attributes related to display surface */
7757 LOGD("store display attribute for given surface type(%d)", surface_type);
7758 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7759 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7760 if (mm_attrs_commit_all(player->attrs)) {
7761 LOGE("failed to commit attribute");
7763 return MM_ERROR_PLAYER_INTERNAL;
7767 return MM_ERROR_NONE;
7770 /* Note : if silent is true, then subtitle would not be displayed. :*/
7771 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7773 mm_player_t* player = (mm_player_t*) hplayer;
7777 /* check player handle */
7778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7780 player->set_mode.subtitle_off = silent;
7782 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7786 return MM_ERROR_NONE;
7789 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7791 MMPlayerGstElement* mainbin = NULL;
7792 MMPlayerGstElement* textbin = NULL;
7793 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7794 GstState current_state = GST_STATE_VOID_PENDING;
7795 GstState element_state = GST_STATE_VOID_PENDING;
7796 GstState element_pending_state = GST_STATE_VOID_PENDING;
7798 GstEvent *event = NULL;
7799 int result = MM_ERROR_NONE;
7801 GstClock *curr_clock = NULL;
7802 GstClockTime base_time, start_time, curr_time;
7807 /* check player handle */
7808 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7810 player->pipeline->mainbin &&
7811 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7813 mainbin = player->pipeline->mainbin;
7814 textbin = player->pipeline->textbin;
7816 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7818 // sync clock with current pipeline
7819 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7820 curr_time = gst_clock_get_time(curr_clock);
7822 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7823 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7825 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7826 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7828 if (current_state > GST_STATE_READY) {
7829 // sync state with current pipeline
7830 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7831 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7832 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7834 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7835 if (GST_STATE_CHANGE_FAILURE == ret) {
7836 LOGE("fail to state change.\n");
7837 result = MM_ERROR_PLAYER_INTERNAL;
7842 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7843 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7846 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7847 gst_object_unref(curr_clock);
7850 // seek to current position
7851 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7852 result = MM_ERROR_PLAYER_INVALID_STATE;
7853 LOGE("gst_element_query_position failed, invalid state\n");
7857 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7858 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);
7860 __mmplayer_gst_send_event_to_sink(player, event);
7862 result = MM_ERROR_PLAYER_INTERNAL;
7863 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7867 /* sync state with current pipeline */
7868 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7869 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7870 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7872 return MM_ERROR_NONE;
7875 /* release text pipeline resource */
7876 player->textsink_linked = 0;
7878 /* release signal */
7879 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7881 /* release textbin with it's childs */
7882 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7883 MMPLAYER_FREEIF(player->pipeline->textbin);
7884 player->pipeline->textbin = NULL;
7886 /* release subtitle elem */
7887 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7888 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7894 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7896 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7897 GstState current_state = GST_STATE_VOID_PENDING;
7899 MMHandleType attrs = 0;
7900 MMPlayerGstElement* mainbin = NULL;
7901 MMPlayerGstElement* textbin = NULL;
7903 gchar* subtitle_uri = NULL;
7904 int result = MM_ERROR_NONE;
7905 const gchar *charset = NULL;
7909 /* check player handle */
7910 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7912 player->pipeline->mainbin &&
7913 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7914 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7916 mainbin = player->pipeline->mainbin;
7917 textbin = player->pipeline->textbin;
7919 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7920 if (current_state < GST_STATE_READY) {
7921 result = MM_ERROR_PLAYER_INVALID_STATE;
7922 LOGE("Pipeline is not in proper state\n");
7926 attrs = MMPLAYER_GET_ATTRS(player);
7928 LOGE("cannot get content attribute\n");
7929 result = MM_ERROR_PLAYER_INTERNAL;
7933 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7934 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7935 LOGE("subtitle uri is not proper filepath\n");
7936 result = MM_ERROR_PLAYER_INVALID_URI;
7940 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7941 LOGE("failed to get storage info of subtitle path");
7942 result = MM_ERROR_PLAYER_INVALID_URI;
7946 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7947 LOGD("new subtitle file path is [%s]\n", filepath);
7949 if (!strcmp(filepath, subtitle_uri)) {
7950 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7953 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7954 if (mm_attrs_commit_all(player->attrs)) {
7955 LOGE("failed to commit.\n");
7960 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7961 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7962 player->subtitle_language_list = NULL;
7963 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7965 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7966 if (ret != GST_STATE_CHANGE_SUCCESS) {
7967 LOGE("failed to change state of textbin to READY");
7968 result = MM_ERROR_PLAYER_INTERNAL;
7972 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7973 if (ret != GST_STATE_CHANGE_SUCCESS) {
7974 LOGE("failed to change state of subparse to READY");
7975 result = MM_ERROR_PLAYER_INTERNAL;
7979 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7980 if (ret != GST_STATE_CHANGE_SUCCESS) {
7981 LOGE("failed to change state of filesrc to READY");
7982 result = MM_ERROR_PLAYER_INTERNAL;
7986 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7988 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7990 charset = util_get_charset(filepath);
7992 LOGD("detected charset is %s\n", charset);
7993 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7996 result = _mmplayer_sync_subtitle_pipeline(player);
8003 /* API to switch between external subtitles */
8004 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
8006 int result = MM_ERROR_NONE;
8007 mm_player_t* player = (mm_player_t*)hplayer;
8012 /* check player handle */
8013 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8015 /* filepath can be null in idle state */
8017 /* check file path */
8018 if ((path = strstr(filepath, "file://")))
8019 result = util_exist_file_path(path + 7);
8021 result = util_exist_file_path(filepath);
8023 if (result != MM_ERROR_NONE) {
8024 LOGE("invalid subtitle path 0x%X", result);
8025 return result; /* file not found or permission denied */
8029 if (!player->pipeline) {
8031 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8032 if (mm_attrs_commit_all(player->attrs)) {
8033 LOGE("failed to commit"); /* subtitle path will not be created */
8034 return MM_ERROR_PLAYER_INTERNAL;
8037 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8038 /* check filepath */
8039 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8041 if (!__mmplayer_check_subtitle(player)) {
8042 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8043 if (mm_attrs_commit_all(player->attrs)) {
8044 LOGE("failed to commit");
8045 return MM_ERROR_PLAYER_INTERNAL;
8048 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8049 LOGE("fail to create text pipeline");
8050 return MM_ERROR_PLAYER_INTERNAL;
8053 result = _mmplayer_sync_subtitle_pipeline(player);
8055 result = __mmplayer_change_external_subtitle_language(player, filepath);
8058 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8059 player->is_external_subtitle_added_now = TRUE;
8061 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8062 if (!player->subtitle_language_list) {
8063 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8064 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8065 LOGW("subtitle language list is not updated yet");
8067 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8075 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8077 int result = MM_ERROR_NONE;
8078 gchar* change_pad_name = NULL;
8079 GstPad* sinkpad = NULL;
8080 MMPlayerGstElement* mainbin = NULL;
8081 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8082 GstCaps* caps = NULL;
8083 gint total_track_num = 0;
8087 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8088 MM_ERROR_PLAYER_NOT_INITIALIZED);
8090 LOGD("Change Track(%d) to %d\n", type, index);
8092 mainbin = player->pipeline->mainbin;
8094 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8095 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8096 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8097 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8099 /* Changing Video Track is not supported. */
8100 LOGE("Track Type Error\n");
8104 if (mainbin[elem_idx].gst == NULL) {
8105 result = MM_ERROR_PLAYER_NO_OP;
8106 LOGD("Req track doesn't exist\n");
8110 total_track_num = player->selector[type].total_track_num;
8111 if (total_track_num <= 0) {
8112 result = MM_ERROR_PLAYER_NO_OP;
8113 LOGD("Language list is not available \n");
8117 if ((index < 0) || (index >= total_track_num)) {
8118 result = MM_ERROR_INVALID_ARGUMENT;
8119 LOGD("Not a proper index : %d \n", index);
8123 /*To get the new pad from the selector*/
8124 change_pad_name = g_strdup_printf("sink_%u", index);
8125 if (change_pad_name == NULL) {
8126 result = MM_ERROR_PLAYER_INTERNAL;
8127 LOGD("Pad does not exists\n");
8131 LOGD("new active pad name: %s\n", change_pad_name);
8133 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8134 if (sinkpad == NULL) {
8135 LOGD("sinkpad is NULL");
8136 result = MM_ERROR_PLAYER_INTERNAL;
8140 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8141 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8143 caps = gst_pad_get_current_caps(sinkpad);
8144 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8147 gst_object_unref(sinkpad);
8149 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8150 __mmplayer_set_audio_attrs(player, caps);
8154 MMPLAYER_FREEIF(change_pad_name);
8158 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8160 int result = MM_ERROR_NONE;
8161 mm_player_t* player = NULL;
8162 MMPlayerGstElement* mainbin = NULL;
8164 gint current_active_index = 0;
8166 GstState current_state = GST_STATE_VOID_PENDING;
8167 GstEvent* event = NULL;
8172 player = (mm_player_t*)hplayer;
8173 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8175 if (!player->pipeline) {
8176 LOGE("Track %d pre setting -> %d\n", type, index);
8178 player->selector[type].active_pad_index = index;
8182 mainbin = player->pipeline->mainbin;
8184 current_active_index = player->selector[type].active_pad_index;
8186 /*If index is same as running index no need to change the pad*/
8187 if (current_active_index == index)
8190 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8191 result = MM_ERROR_PLAYER_INVALID_STATE;
8195 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8196 if (current_state < GST_STATE_PAUSED) {
8197 result = MM_ERROR_PLAYER_INVALID_STATE;
8198 LOGW("Pipeline not in porper state\n");
8202 result = __mmplayer_change_selector_pad(player, type, index);
8203 if (result != MM_ERROR_NONE) {
8204 LOGE("change selector pad error\n");
8208 player->selector[type].active_pad_index = index;
8210 if (current_state == GST_STATE_PLAYING) {
8211 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);
8213 __mmplayer_gst_send_event_to_sink(player, event);
8215 result = MM_ERROR_PLAYER_INTERNAL;
8224 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8226 mm_player_t* player = (mm_player_t*) hplayer;
8230 /* check player handle */
8231 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8233 *silent = player->set_mode.subtitle_off;
8235 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8239 return MM_ERROR_NONE;
8243 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8245 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8246 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8248 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8249 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8253 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8254 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8255 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8256 mm_player_dump_t *dump_s;
8257 dump_s = g_malloc(sizeof(mm_player_dump_t));
8259 if (dump_s == NULL) {
8260 LOGE("malloc fail");
8264 dump_s->dump_element_file = NULL;
8265 dump_s->dump_pad = NULL;
8266 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8268 if (dump_s->dump_pad) {
8269 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8270 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]);
8271 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8272 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);
8273 /* add list for removed buffer probe and close FILE */
8274 player->dump_list = g_list_append(player->dump_list, dump_s);
8275 LOGD("%s sink pad added buffer probe for dump", factory_name);
8280 LOGE("failed to get %s sink pad added", factory_name);
8287 static GstPadProbeReturn
8288 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8290 FILE *dump_data = (FILE *) u_data;
8292 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8293 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8295 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8297 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8299 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8301 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8303 return GST_PAD_PROBE_OK;
8307 __mmplayer_release_dump_list(GList *dump_list)
8310 GList *d_list = dump_list;
8311 for (; d_list; d_list = g_list_next(d_list)) {
8312 mm_player_dump_t *dump_s = d_list->data;
8313 if (dump_s->dump_pad) {
8314 if (dump_s->probe_handle_id)
8315 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8317 if (dump_s->dump_element_file) {
8318 fclose(dump_s->dump_element_file);
8319 dump_s->dump_element_file = NULL;
8321 MMPLAYER_FREEIF(dump_s);
8323 g_list_free(dump_list);
8329 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8331 mm_player_t* player = (mm_player_t*) hplayer;
8335 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8336 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8338 *exist = player->has_closed_caption;
8342 return MM_ERROR_NONE;
8345 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8349 // LOGD("unref internal gst buffer %p", buffer);
8350 gst_buffer_unref((GstBuffer *)buffer);
8356 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
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(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8365 if (MMPLAYER_IS_HTTP_PD(player))
8366 /* consider the timeout both download pipeline and playback pipeline */
8367 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8368 else if (MMPLAYER_IS_STREAMING(player))
8369 *timeout = player->ini.live_state_change_timeout;
8371 *timeout = player->ini.localplayback_state_change_timeout;
8373 LOGD("timeout = %d\n", *timeout);
8376 return MM_ERROR_NONE;
8379 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8381 mm_player_t* player = (mm_player_t*) hplayer;
8385 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8386 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8388 *num = player->video_num_buffers;
8389 *extra_num = player->video_extra_num_buffers;
8391 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8394 return MM_ERROR_NONE;
8398 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8402 MMPLAYER_RETURN_IF_FAIL(player);
8404 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8406 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8407 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8408 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8409 player->storage_info[i].id = -1;
8410 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8412 if (path_type != MMPLAYER_PATH_MAX)
8420 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8422 int ret = MM_ERROR_NONE;
8423 mm_player_t* player = (mm_player_t*)hplayer;
8424 MMMessageParamType msg_param = {0, };
8427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8429 LOGW("state changed storage %d:%d", id, state);
8431 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8432 return MM_ERROR_NONE;
8434 /* FIXME: text path should be handled seperately. */
8435 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8436 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8437 LOGW("external storage is removed");
8439 if (player->msg_posted == FALSE) {
8440 memset(&msg_param, 0, sizeof(MMMessageParamType));
8441 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8442 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8443 player->msg_posted = TRUE;
8446 /* unrealize the player */
8447 ret = _mmplayer_unrealize(hplayer);
8448 if (ret != MM_ERROR_NONE)
8449 LOGE("failed to unrealize");
8456 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8458 int ret = MM_ERROR_NONE;
8459 mm_player_t* player = (mm_player_t*) hplayer;
8460 int idx = 0, total = 0;
8461 gchar *result = NULL, *tmp = NULL;
8464 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8465 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8467 total = *num = g_list_length(player->adaptive_info.var_list);
8469 LOGW("There is no stream variant info.");
8473 result = g_strdup("");
8474 for (idx = 0 ; idx < total ; idx++) {
8475 VariantData *v_data = NULL;
8476 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8479 gchar data[64] = {0};
8480 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8482 tmp = g_strconcat(result, data, NULL);
8486 LOGW("There is no variant data in %d", idx);
8491 *var_info = (char *)result;
8493 LOGD("variant info %d:%s", *num, *var_info);
8498 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8500 int ret = MM_ERROR_NONE;
8501 mm_player_t* player = (mm_player_t*) hplayer;
8504 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8506 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8508 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8509 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8510 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8512 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8513 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8514 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8515 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8517 /* FIXME: seek to current position for applying new variant limitation */
8525 int _mmplayer_get_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);
8532 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8534 *bandwidth = player->adaptive_info.limit.bandwidth;
8535 *width = player->adaptive_info.limit.width;
8536 *height = player->adaptive_info.limit.height;
8538 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8544 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8546 int ret = MM_ERROR_NONE;
8547 mm_player_t* player = (mm_player_t*) hplayer;
8550 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8552 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8553 LOGW("buffer_ms will not be applied.");
8556 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8558 if (player->streamer == NULL) {
8559 player->streamer = __mm_player_streaming_create();
8560 __mm_player_streaming_initialize(player->streamer);
8564 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8566 if (rebuffer_ms >= 0)
8567 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8574 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8576 int ret = MM_ERROR_NONE;
8577 mm_player_t* player = (mm_player_t*) hplayer;
8580 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8581 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8583 if (player->streamer == NULL) {
8584 player->streamer = __mm_player_streaming_create();
8585 __mm_player_streaming_initialize(player->streamer);
8588 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8589 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8591 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8597 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8599 #define IDX_FIRST_SW_CODEC 0
8600 mm_player_t* player = (mm_player_t*) hplayer;
8601 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8602 MMHandleType attrs = 0;
8605 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8607 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8608 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8609 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8611 switch (stream_type) {
8612 case MM_PLAYER_STREAM_TYPE_AUDIO:
8613 /* to support audio codec selection, codec info have to be added in ini file as below.
8614 audio codec element hw = xxxx
8615 audio codec element sw = avdec */
8616 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8617 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8618 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8619 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8620 LOGE("There is no audio codec info for codec_type %d", codec_type);
8621 return MM_ERROR_PLAYER_NO_OP;
8624 case MM_PLAYER_STREAM_TYPE_VIDEO:
8625 /* to support video codec selection, codec info have to be added in ini file as below.
8626 video codec element hw = omx
8627 video codec element sw = avdec */
8628 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8629 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8630 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8631 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8632 LOGE("There is no video codec info for codec_type %d", codec_type);
8633 return MM_ERROR_PLAYER_NO_OP;
8637 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8638 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8642 LOGD("update %s codec_type to %d", attr_name, codec_type);
8644 attrs = MMPLAYER_GET_ATTRS(player);
8645 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8647 if (mm_attrs_commit_all(player->attrs)) {
8648 LOGE("failed to commit codec_type attributes");
8649 return MM_ERROR_PLAYER_INTERNAL;
8653 return MM_ERROR_NONE;
8657 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8659 mm_player_t* player = (mm_player_t*) hplayer;
8660 GstElement* rg_vol_element = NULL;
8664 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8666 player->sound.rg_enable = enabled;
8668 /* just hold rgvolume enable value if pipeline is not ready */
8669 if (!player->pipeline || !player->pipeline->audiobin) {
8670 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8671 return MM_ERROR_NONE;
8674 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8676 if (!rg_vol_element) {
8677 LOGD("rgvolume element is not created");
8678 return MM_ERROR_PLAYER_INTERNAL;
8682 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8684 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8688 return MM_ERROR_NONE;
8692 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8694 mm_player_t* player = (mm_player_t*) hplayer;
8695 GstElement* rg_vol_element = NULL;
8696 gboolean enable = FALSE;
8700 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8701 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8703 /* just hold enable_rg value if pipeline is not ready */
8704 if (!player->pipeline || !player->pipeline->audiobin) {
8705 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8706 *enabled = player->sound.rg_enable;
8707 return MM_ERROR_NONE;
8710 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8712 if (!rg_vol_element) {
8713 LOGD("rgvolume element is not created");
8714 return MM_ERROR_PLAYER_INTERNAL;
8717 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8722 return MM_ERROR_NONE;
8726 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8728 mm_player_t* player = (mm_player_t*) hplayer;
8729 MMHandleType attrs = 0;
8730 void *handle = NULL;
8731 int ret = MM_ERROR_NONE;
8735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8737 attrs = MMPLAYER_GET_ATTRS(player);
8738 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8740 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8742 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8743 return MM_ERROR_PLAYER_INTERNAL;
8746 player->video_roi.scale_x = scale_x;
8747 player->video_roi.scale_y = scale_y;
8748 player->video_roi.scale_width = scale_width;
8749 player->video_roi.scale_height = scale_height;
8751 /* check video sinkbin is created */
8752 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8753 return MM_ERROR_NONE;
8755 if (!gst_video_overlay_set_video_roi_area(
8756 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8757 scale_x, scale_y, scale_width, scale_height))
8758 ret = MM_ERROR_PLAYER_INTERNAL;
8760 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8761 scale_x, scale_y, scale_width, scale_height);
8769 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8771 mm_player_t* player = (mm_player_t*) hplayer;
8772 int ret = MM_ERROR_NONE;
8776 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8777 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8779 *scale_x = player->video_roi.scale_x;
8780 *scale_y = player->video_roi.scale_y;
8781 *scale_width = player->video_roi.scale_width;
8782 *scale_height = player->video_roi.scale_height;
8784 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8785 *scale_x, *scale_y, *scale_width, *scale_height);
8791 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8793 gboolean ret = FALSE;
8794 gint64 dur_nsec = 0;
8795 LOGD("try to update duration");
8797 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8798 player->duration = dur_nsec;
8799 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8803 if (player->duration < 0) {
8804 LOGW("duration is Non-Initialized !!!");
8805 player->duration = 0;
8808 /* update streaming service type */
8809 player->streaming_type = __mmplayer_get_stream_service_type(player);
8811 /* check duration is OK */
8812 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8813 /* FIXIT : find another way to get duration here. */
8814 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8821 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8823 /* update audio params
8824 NOTE : We need original audio params and it can be only obtained from src pad of audio
8825 decoder. Below code only valid when we are not using 'resampler' just before
8826 'audioconverter'. */
8827 GstCaps *caps_a = NULL;
8829 gint samplerate = 0, channels = 0;
8830 GstStructure* p = NULL;
8832 LOGD("try to update audio attrs");
8834 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8835 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8837 pad = gst_element_get_static_pad(
8838 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8841 LOGW("failed to get pad from audiosink");
8845 caps_a = gst_pad_get_current_caps(pad);
8848 LOGW("not ready to get audio caps");
8849 gst_object_unref(pad);
8853 p = gst_caps_get_structure(caps_a, 0);
8855 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8857 gst_structure_get_int(p, "rate", &samplerate);
8858 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8860 gst_structure_get_int(p, "channels", &channels);
8861 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8863 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8865 gst_caps_unref(caps_a);
8866 gst_object_unref(pad);
8872 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8874 LOGD("try to update video attrs");
8876 GstCaps *caps_v = NULL;
8880 GstStructure* p = NULL;
8882 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8883 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8885 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8887 LOGD("no videosink sink pad");
8891 caps_v = gst_pad_get_current_caps(pad);
8892 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8893 if (!caps_v && player->v_stream_caps) {
8894 caps_v = player->v_stream_caps;
8895 gst_caps_ref(caps_v);
8899 LOGD("no negitiated caps from videosink");
8900 gst_object_unref(pad);
8904 p = gst_caps_get_structure(caps_v, 0);
8905 gst_structure_get_int(p, "width", &width);
8906 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8908 gst_structure_get_int(p, "height", &height);
8909 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8911 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8913 SECURE_LOGD("width : %d height : %d", width, height);
8915 gst_caps_unref(caps_v);
8916 gst_object_unref(pad);
8919 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8920 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8927 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8929 gboolean ret = FALSE;
8930 guint64 data_size = 0;
8934 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8935 if (!player->duration)
8938 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8939 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8940 if (stat(path, &sb) == 0)
8941 data_size = (guint64)sb.st_size;
8943 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8944 data_size = player->http_content_size;
8947 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8950 guint64 bitrate = 0;
8951 guint64 msec_dur = 0;
8953 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8955 bitrate = data_size * 8 * 1000 / msec_dur;
8956 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
8957 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8961 LOGD("player duration is less than 0");
8965 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8966 if (player->total_bitrate) {
8967 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8975 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8977 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8978 data->uri_type = uri_type;
8981 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8983 int ret = MM_ERROR_PLAYER_INVALID_URI;
8985 char *buffer = NULL;
8986 char *seperator = strchr(path, ',');
8987 char ext[100] = {0,}, size[100] = {0,};
8990 if ((buffer = strstr(path, "ext="))) {
8991 buffer += strlen("ext=");
8993 if (strlen(buffer)) {
8994 strncpy(ext, buffer, 99);
8996 if ((seperator = strchr(ext, ','))
8997 || (seperator = strchr(ext, ' '))
8998 || (seperator = strchr(ext, '\0'))) {
8999 seperator[0] = '\0';
9004 if ((buffer = strstr(path, "size="))) {
9005 buffer += strlen("size=");
9007 if (strlen(buffer) > 0) {
9008 strncpy(size, buffer, 99);
9010 if ((seperator = strchr(size, ','))
9011 || (seperator = strchr(size, ' '))
9012 || (seperator = strchr(size, '\0'))) {
9013 seperator[0] = '\0';
9016 mem_size = atoi(size);
9021 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
9023 if (mem_size && param) {
9024 if (data->input_mem.buf)
9025 free(data->input_mem.buf);
9026 data->input_mem.buf = malloc(mem_size);
9028 if (data->input_mem.buf) {
9029 memcpy(data->input_mem.buf, param, mem_size);
9030 data->input_mem.len = mem_size;
9031 ret = MM_ERROR_NONE;
9033 LOGE("failed to alloc mem %d", mem_size);
9034 ret = MM_ERROR_PLAYER_INTERNAL;
9037 data->input_mem.offset = 0;
9038 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9045 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9047 gchar *location = NULL;
9050 int ret = MM_ERROR_NONE;
9052 if ((path = strstr(uri, "file://"))) {
9053 location = g_filename_from_uri(uri, NULL, &err);
9054 if (!location || (err != NULL)) {
9055 LOGE("Invalid URI '%s' for filesrc: %s", path,
9056 (err != NULL) ? err->message : "unknown error");
9062 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9063 return MM_ERROR_PLAYER_INVALID_URI;
9065 LOGD("path from uri: %s", location);
9068 path = (location != NULL) ? (location) : ((char *)uri);
9071 ret = util_exist_file_path(path);
9073 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9074 if (ret == MM_ERROR_NONE) {
9075 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9076 if (util_is_sdp_file(path)) {
9077 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9078 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9080 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9082 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9083 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9085 LOGE("invalid uri, could not play..\n");
9086 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9095 static MMPlayerVideoStreamDataType*
9096 __mmplayer_create_stream_from_pad(GstPad *pad)
9098 GstCaps *caps = NULL;
9099 GstStructure *structure = NULL;
9100 unsigned int fourcc = 0;
9101 const gchar *string_format = NULL;
9102 MMPlayerVideoStreamDataType *stream = NULL;
9104 MMPixelFormatType format;
9106 caps = gst_pad_get_current_caps(pad);
9108 LOGE("Caps is NULL.");
9112 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9113 structure = gst_caps_get_structure(caps, 0);
9114 gst_structure_get_int(structure, "width", &width);
9115 gst_structure_get_int(structure, "height", &height);
9116 string_format = gst_structure_get_string(structure, "format");
9118 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9119 format = util_get_pixtype(fourcc);
9120 gst_caps_unref(caps);
9123 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9124 LOGE("Wrong condition!!");
9128 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9130 LOGE("failed to alloc mem for video data");
9134 stream->width = width;
9135 stream->height = height;
9136 stream->format = format;
9142 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9144 unsigned int pitch = 0;
9146 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9148 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9149 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9150 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9151 stream->stride[index] = pitch;
9152 stream->elevation[index] = stream->height;
9157 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9159 if (stream->format == MM_PIXEL_FORMAT_I420) {
9160 int ret = TBM_SURFACE_ERROR_NONE;
9161 tbm_surface_h surface;
9162 tbm_surface_info_s info;
9164 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9166 ret = tbm_surface_get_info(surface, &info);
9167 if (ret != TBM_SURFACE_ERROR_NONE) {
9168 tbm_surface_destroy(surface);
9172 tbm_surface_destroy(surface);
9173 stream->stride[0] = info.planes[0].stride;
9174 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9175 stream->stride[1] = info.planes[1].stride;
9176 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9177 stream->stride[2] = info.planes[2].stride;
9178 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9179 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9180 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9181 stream->stride[0] = stream->width * 4;
9182 stream->elevation[0] = stream->height;
9183 stream->bo_size = stream->stride[0] * stream->height;
9185 LOGE("Not support format %d", stream->format);
9193 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9195 tbm_bo_handle thandle;
9197 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9198 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9199 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9203 unsigned char *src = NULL;
9204 unsigned char *dest = NULL;
9205 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9207 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9209 LOGE("fail to gst_memory_map");
9213 if (!mapinfo.data) {
9214 LOGE("data pointer is wrong");
9218 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9219 if (!stream->bo[0]) {
9220 LOGE("Fail to tbm_bo_alloc!!");
9224 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9226 LOGE("thandle pointer is wrong");
9230 if (stream->format == MM_PIXEL_FORMAT_I420) {
9231 src_stride[0] = GST_ROUND_UP_4(stream->width);
9232 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9233 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9234 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9237 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9238 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9240 for (i = 0; i < 3; i++) {
9241 src = mapinfo.data + src_offset[i];
9242 dest = thandle.ptr + dest_offset[i];
9247 for (j = 0; j < stream->height >> k; j++) {
9248 memcpy(dest, src, stream->width>>k);
9249 src += src_stride[i];
9250 dest += stream->stride[i];
9253 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9254 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9256 LOGE("Not support format %d", stream->format);
9260 tbm_bo_unmap(stream->bo[0]);
9261 gst_memory_unmap(mem, &mapinfo);
9267 tbm_bo_unmap(stream->bo[0]);
9270 gst_memory_unmap(mem, &mapinfo);
9276 __mmplayer_set_pause_state(mm_player_t *player)
9278 if (player->sent_bos)
9281 /* rtsp case, get content attrs by GstMessage */
9282 if (MMPLAYER_IS_RTSP_STREAMING(player))
9285 /* it's first time to update all content attrs. */
9286 __mmplayer_update_content_attrs(player, ATTR_ALL);
9290 __mmplayer_set_playing_state(mm_player_t *player)
9292 gchar *audio_codec = NULL;
9294 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9295 /* initialize because auto resume is done well. */
9296 player->resumed_by_rewind = FALSE;
9297 player->playback_rate = 1.0;
9300 if (player->sent_bos)
9303 /* try to get content metadata */
9305 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9306 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9307 * legacy mmfw-player api
9309 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9311 if ((player->cmd == MMPLAYER_COMMAND_START)
9312 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9313 __mmplayer_handle_missed_plugin(player);
9316 /* check audio codec field is set or not
9317 * we can get it from typefinder or codec's caps.
9319 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9321 /* The codec format can't be sent for audio only case like amr, mid etc.
9322 * Because, parser don't make related TAG.
9323 * So, if it's not set yet, fill it with found data.
9326 if (g_strrstr(player->type, "audio/midi"))
9327 audio_codec = "MIDI";
9328 else if (g_strrstr(player->type, "audio/x-amr"))
9329 audio_codec = "AMR";
9330 else if (g_strrstr(player->type, "audio/mpeg")
9331 && !g_strrstr(player->type, "mpegversion= (int)1"))
9332 audio_codec = "AAC";
9334 audio_codec = "unknown";
9336 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9338 if (mm_attrs_commit_all(player->attrs))
9339 LOGE("failed to update attributes\n");
9341 LOGD("set audio codec type with caps\n");