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 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2690 /* audio effect element. if audio effect is enabled */
2691 if ((strcmp(player->ini.audioeffect_element, ""))
2693 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2696 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2698 if ((!player->bypass_audio_effect)
2699 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2700 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2701 if (!_mmplayer_audio_effect_custom_apply(player))
2702 LOGI("apply audio effect(custom) setting success");
2706 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2707 && (player->set_mode.rich_audio))
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2711 /* create audio sink */
2712 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2713 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2714 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2716 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2717 if (player->is_360_feature_enabled &&
2718 player->is_content_spherical &&
2720 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2721 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2722 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2724 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2726 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2729 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2730 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2731 gst_caps_unref(acaps);
2733 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2735 player->is_openal_plugin_used = TRUE;
2737 if (player->is_360_feature_enabled && player->is_content_spherical)
2738 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2739 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2742 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2743 (player->videodec_linked && player->ini.use_system_clock)) {
2744 LOGD("system clock will be used.");
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2748 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2749 __mmplayer_gst_set_pulsesink_property(player, attrs);
2750 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2751 __mmplayer_gst_set_openalsink_property(player);
2754 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2755 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2757 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2758 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2759 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2760 gst_object_unref(GST_OBJECT(sink_pad));
2762 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2765 *bucket = element_bucket;
2768 return MM_ERROR_NONE;
2771 g_list_free(element_bucket);
2775 return MM_ERROR_PLAYER_INTERNAL;
2779 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2781 MMPlayerGstElement *first_element = NULL;
2782 MMPlayerGstElement *audiobin = NULL;
2784 GstPad *ghostpad = NULL;
2785 GList *element_bucket = NULL;
2789 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2792 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2794 LOGE("failed to allocate memory for audiobin");
2795 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2799 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2800 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2801 if (!audiobin[MMPLAYER_A_BIN].gst) {
2802 LOGE("failed to create audiobin");
2807 player->pipeline->audiobin = audiobin;
2809 /* create audio filters and audiosink */
2810 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2813 /* adding created elements to bin */
2814 LOGD("adding created elements to bin");
2815 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2818 /* linking elements in the bucket by added order. */
2819 LOGD("Linking elements in the bucket by added order.");
2820 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2823 /* get first element's sinkpad for creating ghostpad */
2824 first_element = (MMPlayerGstElement *)element_bucket->data;
2825 if (!first_element) {
2826 LOGE("failed to get first elem");
2830 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2832 LOGE("failed to get pad from first element of audiobin");
2836 ghostpad = gst_ghost_pad_new("sink", pad);
2838 LOGE("failed to create ghostpad");
2842 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2843 LOGE("failed to add ghostpad to audiobin");
2847 gst_object_unref(pad);
2849 g_list_free(element_bucket);
2852 return MM_ERROR_NONE;
2855 LOGD("ERROR : releasing audiobin");
2858 gst_object_unref(GST_OBJECT(pad));
2861 gst_object_unref(GST_OBJECT(ghostpad));
2864 g_list_free(element_bucket);
2866 /* release element which are not added to bin */
2867 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2868 /* NOTE : skip bin */
2869 if (audiobin[i].gst) {
2870 GstObject* parent = NULL;
2871 parent = gst_element_get_parent(audiobin[i].gst);
2874 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2875 audiobin[i].gst = NULL;
2877 gst_object_unref(GST_OBJECT(parent));
2881 /* release audiobin with it's childs */
2882 if (audiobin[MMPLAYER_A_BIN].gst)
2883 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2885 MMPLAYER_FREEIF(audiobin);
2887 player->pipeline->audiobin = NULL;
2889 return MM_ERROR_PLAYER_INTERNAL;
2892 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2894 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2897 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2899 int ret = MM_ERROR_NONE;
2901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2902 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2904 MMPLAYER_VIDEO_BO_LOCK(player);
2906 if (player->video_bo_list) {
2907 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2908 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2909 if (tmp && tmp->bo == bo) {
2911 LOGD("release bo %p", bo);
2912 tbm_bo_unref(tmp->bo);
2913 MMPLAYER_VIDEO_BO_UNLOCK(player);
2914 MMPLAYER_VIDEO_BO_SIGNAL(player);
2919 /* hw codec is running or the list was reset for DRC. */
2920 LOGW("there is no bo list.");
2922 MMPLAYER_VIDEO_BO_UNLOCK(player);
2924 LOGW("failed to find bo %p", bo);
2929 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2934 MMPLAYER_RETURN_IF_FAIL(player);
2936 MMPLAYER_VIDEO_BO_LOCK(player);
2937 if (player->video_bo_list) {
2938 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2939 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2940 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2943 tbm_bo_unref(tmp->bo);
2947 g_list_free(player->video_bo_list);
2948 player->video_bo_list = NULL;
2950 player->video_bo_size = 0;
2951 MMPLAYER_VIDEO_BO_UNLOCK(player);
2958 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2961 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2962 gboolean ret = TRUE;
2964 /* check DRC, if it is, destroy the prev bo list to create again */
2965 if (player->video_bo_size != size) {
2966 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2967 __mmplayer_video_stream_destroy_bo_list(player);
2968 player->video_bo_size = size;
2971 MMPLAYER_VIDEO_BO_LOCK(player);
2973 if ((!player->video_bo_list) ||
2974 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2976 /* create bo list */
2978 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2980 if (player->video_bo_list) {
2981 /* if bo list did not created all, try it again. */
2982 idx = g_list_length(player->video_bo_list);
2983 LOGD("bo list exist(len: %d)", idx);
2986 for (; idx < player->ini.num_of_video_bo; idx++) {
2987 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
2989 LOGE("Fail to alloc bo_info.");
2992 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2994 LOGE("Fail to tbm_bo_alloc.");
2998 bo_info->used = FALSE;
2999 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3002 /* update video num buffers */
3003 player->video_num_buffers = idx;
3004 if (idx == player->ini.num_of_video_bo)
3005 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3008 MMPLAYER_VIDEO_BO_UNLOCK(player);
3012 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3016 /* get bo from list*/
3017 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3018 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3019 if (tmp && (tmp->used == FALSE)) {
3020 LOGD("found bo %p to use", tmp->bo);
3022 MMPLAYER_VIDEO_BO_UNLOCK(player);
3023 return tbm_bo_ref(tmp->bo);
3027 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3028 MMPLAYER_VIDEO_BO_UNLOCK(player);
3032 if (player->ini.video_bo_timeout <= 0) {
3033 MMPLAYER_VIDEO_BO_WAIT(player);
3035 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3036 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3043 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3045 mm_player_t* player = (mm_player_t*)data;
3047 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3049 /* send prerolled pkt */
3050 player->video_stream_prerolled = FALSE;
3052 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3054 /* not to send prerolled pkt again */
3055 player->video_stream_prerolled = TRUE;
3059 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3061 mm_player_t* player = (mm_player_t*)data;
3062 MMPlayerVideoStreamDataType *stream = NULL;
3063 GstMemory *mem = NULL;
3066 MMPLAYER_RETURN_IF_FAIL(player);
3067 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3069 if (player->video_stream_prerolled) {
3070 player->video_stream_prerolled = FALSE;
3071 LOGD("skip the prerolled pkt not to send it again");
3075 /* clear stream data structure */
3076 stream = __mmplayer_create_stream_from_pad(pad);
3078 LOGE("failed to alloc stream");
3082 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3084 /* set size and timestamp */
3085 mem = gst_buffer_peek_memory(buffer, 0);
3086 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3087 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3089 /* check zero-copy */
3090 if (player->set_mode.video_zc &&
3091 player->set_mode.media_packet_video_stream &&
3092 gst_is_tizen_memory(mem)) {
3093 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3094 stream->internal_buffer = gst_buffer_ref(buffer);
3095 } else { /* sw codec */
3096 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3099 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3103 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3104 LOGE("failed to send video stream data.");
3111 LOGE("release video stream resource.");
3112 if (gst_is_tizen_memory(mem)) {
3114 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3116 tbm_bo_unref(stream->bo[i]);
3119 /* unref gst buffer */
3120 if (stream->internal_buffer)
3121 gst_buffer_unref(stream->internal_buffer);
3124 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3131 __mmplayer_gst_set_video360_property(mm_player_t *player)
3133 MMPlayerGstElement *videobin = NULL;
3136 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3138 videobin = player->pipeline->videobin;
3140 /* Set spatial media metadata and/or user settings to the element.
3142 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3143 "projection-type", player->video360_metadata.projection_type, NULL);
3145 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3146 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3148 if (player->video360_metadata.full_pano_width_pixels &&
3149 player->video360_metadata.full_pano_height_pixels &&
3150 player->video360_metadata.cropped_area_image_width &&
3151 player->video360_metadata.cropped_area_image_height) {
3152 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3153 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3154 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3155 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3156 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3157 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3158 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3162 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3163 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3164 "horizontal-fov", player->video360_horizontal_fov,
3165 "vertical-fov", player->video360_vertical_fov, NULL);
3168 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3169 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3170 "zoom", 1.0f / player->video360_zoom, NULL);
3173 if (player->video360_yaw_radians <= M_PI &&
3174 player->video360_yaw_radians >= -M_PI &&
3175 player->video360_pitch_radians <= M_PI_2 &&
3176 player->video360_pitch_radians >= -M_PI_2) {
3177 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3178 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3179 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3180 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3181 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3182 "pose-yaw", player->video360_metadata.init_view_heading,
3183 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3186 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3187 "passthrough", !player->is_video360_enabled, NULL);
3194 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3196 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3197 GList *element_bucket = NULL;
3200 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3202 /* create video360 filter */
3203 if (player->is_360_feature_enabled && player->is_content_spherical) {
3204 LOGD("create video360 element");
3205 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3206 __mmplayer_gst_set_video360_property(player);
3210 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3211 LOGD("skip creating the videoconv and rotator");
3212 return MM_ERROR_NONE;
3215 /* in case of sw codec & overlay surface type, except 360 playback.
3216 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3217 LOGD("create video converter: %s", video_csc);
3218 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3220 /* set video rotator */
3221 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3224 *bucket = element_bucket;
3226 return MM_ERROR_NONE;
3228 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3229 g_list_free(element_bucket);
3233 return MM_ERROR_PLAYER_INTERNAL;
3237 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3239 gchar *factory_name = NULL;
3241 switch (surface_type) {
3242 case MM_DISPLAY_SURFACE_OVERLAY:
3243 if (strlen(player->ini.videosink_element_overlay) > 0)
3244 factory_name = player->ini.videosink_element_overlay;
3246 case MM_DISPLAY_SURFACE_REMOTE:
3247 case MM_DISPLAY_SURFACE_NULL:
3248 if (strlen(player->ini.videosink_element_fake) > 0)
3249 factory_name = player->ini.videosink_element_fake;
3252 LOGE("unidentified surface type");
3256 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3257 return factory_name;
3261 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3263 gchar *factory_name = NULL;
3264 MMPlayerGstElement *videobin = NULL;
3269 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3271 videobin = player->pipeline->videobin;
3272 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3274 attrs = MMPLAYER_GET_ATTRS(player);
3276 LOGE("cannot get content attribute");
3277 return MM_ERROR_PLAYER_INTERNAL;
3280 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3281 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3282 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3284 /* support shard memory with S/W codec on HawkP */
3285 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3286 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3287 "use-tbm", use_tbm, NULL);
3291 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3292 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3295 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3297 LOGD("disable last-sample");
3298 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3301 if (player->set_mode.media_packet_video_stream) {
3303 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3304 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3305 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3307 __mmplayer_add_signal_connection(player,
3308 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3309 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3311 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3314 __mmplayer_add_signal_connection(player,
3315 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3316 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3318 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3322 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3323 return MM_ERROR_PLAYER_INTERNAL;
3325 if (videobin[MMPLAYER_V_SINK].gst) {
3326 GstPad *sink_pad = NULL;
3327 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3329 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3330 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3331 gst_object_unref(GST_OBJECT(sink_pad));
3333 LOGE("failed to get sink pad from videosink");
3337 return MM_ERROR_NONE;
3342 * - video overlay surface(arm/x86) : tizenwlsink
3345 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3348 GList *element_bucket = NULL;
3349 MMPlayerGstElement *first_element = NULL;
3350 MMPlayerGstElement *videobin = NULL;
3351 gchar *videosink_factory_name = NULL;
3354 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3357 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3359 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3361 player->pipeline->videobin = videobin;
3364 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3365 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3366 if (!videobin[MMPLAYER_V_BIN].gst) {
3367 LOGE("failed to create videobin");
3371 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3374 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3375 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3377 /* additional setting for sink plug-in */
3378 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3379 LOGE("failed to set video property");
3383 /* store it as it's sink element */
3384 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3386 /* adding created elements to bin */
3387 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3388 LOGE("failed to add elements");
3392 /* Linking elements in the bucket by added order */
3393 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3394 LOGE("failed to link elements");
3398 /* get first element's sinkpad for creating ghostpad */
3399 first_element = (MMPlayerGstElement *)element_bucket->data;
3400 if (!first_element) {
3401 LOGE("failed to get first element from bucket");
3405 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3407 LOGE("failed to get pad from first element");
3411 /* create ghostpad */
3412 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3413 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3414 LOGE("failed to add ghostpad to videobin");
3417 gst_object_unref(pad);
3419 /* done. free allocated variables */
3420 g_list_free(element_bucket);
3424 return MM_ERROR_NONE;
3427 LOGE("ERROR : releasing videobin");
3428 g_list_free(element_bucket);
3431 gst_object_unref(GST_OBJECT(pad));
3433 /* release videobin with it's childs */
3434 if (videobin[MMPLAYER_V_BIN].gst)
3435 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3437 MMPLAYER_FREEIF(videobin);
3438 player->pipeline->videobin = NULL;
3440 return MM_ERROR_PLAYER_INTERNAL;
3443 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3445 GList *element_bucket = NULL;
3446 MMPlayerGstElement *textbin = player->pipeline->textbin;
3448 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3449 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3450 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3451 "signal-handoffs", FALSE,
3454 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3455 __mmplayer_add_signal_connection(player,
3456 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3457 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3459 G_CALLBACK(__mmplayer_update_subtitle),
3462 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3463 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3465 if (!player->play_subtitle) {
3466 LOGD("add textbin sink as sink element of whole pipeline.\n");
3467 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3470 /* adding created elements to bin */
3471 LOGD("adding created elements to bin\n");
3472 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3473 LOGE("failed to add elements\n");
3477 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3478 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3479 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3481 /* linking elements in the bucket by added order. */
3482 LOGD("Linking elements in the bucket by added order.\n");
3483 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3484 LOGE("failed to link elements\n");
3488 /* done. free allocated variables */
3489 g_list_free(element_bucket);
3491 if (textbin[MMPLAYER_T_QUEUE].gst) {
3493 GstPad *ghostpad = NULL;
3495 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3497 LOGE("failed to get sink pad of text queue");
3501 ghostpad = gst_ghost_pad_new("text_sink", pad);
3502 gst_object_unref(pad);
3505 LOGE("failed to create ghostpad of textbin\n");
3509 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3510 LOGE("failed to add ghostpad to textbin\n");
3511 gst_object_unref(ghostpad);
3516 return MM_ERROR_NONE;
3519 g_list_free(element_bucket);
3521 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3522 LOGE("remove textbin sink from sink list");
3523 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3526 /* release element at __mmplayer_gst_create_text_sink_bin */
3527 return MM_ERROR_PLAYER_INTERNAL;
3530 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3532 MMPlayerGstElement *textbin = NULL;
3533 GList *element_bucket = NULL;
3534 int surface_type = 0;
3539 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3542 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3544 LOGE("failed to allocate memory for textbin\n");
3545 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3549 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3550 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3551 if (!textbin[MMPLAYER_T_BIN].gst) {
3552 LOGE("failed to create textbin\n");
3557 player->pipeline->textbin = textbin;
3560 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3561 LOGD("surface type for subtitle : %d", surface_type);
3562 switch (surface_type) {
3563 case MM_DISPLAY_SURFACE_OVERLAY:
3564 case MM_DISPLAY_SURFACE_NULL:
3565 case MM_DISPLAY_SURFACE_REMOTE:
3566 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3567 LOGE("failed to make plain text elements\n");
3578 return MM_ERROR_NONE;
3582 LOGD("ERROR : releasing textbin\n");
3584 g_list_free(element_bucket);
3586 /* release signal */
3587 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3589 /* release element which are not added to bin */
3590 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3591 /* NOTE : skip bin */
3592 if (textbin[i].gst) {
3593 GstObject* parent = NULL;
3594 parent = gst_element_get_parent(textbin[i].gst);
3597 gst_object_unref(GST_OBJECT(textbin[i].gst));
3598 textbin[i].gst = NULL;
3600 gst_object_unref(GST_OBJECT(parent));
3605 /* release textbin with it's childs */
3606 if (textbin[MMPLAYER_T_BIN].gst)
3607 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3609 MMPLAYER_FREEIF(player->pipeline->textbin);
3610 player->pipeline->textbin = NULL;
3613 return MM_ERROR_PLAYER_INTERNAL;
3618 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3620 MMPlayerGstElement* mainbin = NULL;
3621 MMPlayerGstElement* textbin = NULL;
3622 MMHandleType attrs = 0;
3623 GstElement *subsrc = NULL;
3624 GstElement *subparse = NULL;
3625 gchar *subtitle_uri = NULL;
3626 const gchar *charset = NULL;
3632 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3634 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3636 mainbin = player->pipeline->mainbin;
3638 attrs = MMPLAYER_GET_ATTRS(player);
3640 LOGE("cannot get content attribute\n");
3641 return MM_ERROR_PLAYER_INTERNAL;
3644 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3645 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3646 LOGE("subtitle uri is not proper filepath.\n");
3647 return MM_ERROR_PLAYER_INVALID_URI;
3650 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3651 LOGE("failed to get storage info of subtitle path");
3652 return MM_ERROR_PLAYER_INVALID_URI;
3655 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3657 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3658 player->subtitle_language_list = NULL;
3659 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3661 /* create the subtitle source */
3662 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3664 LOGE("failed to create filesrc element\n");
3667 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3669 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3670 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3672 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3673 LOGW("failed to add queue\n");
3674 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3675 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3676 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3681 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3683 LOGE("failed to create subparse element\n");
3687 charset = util_get_charset(subtitle_uri);
3689 LOGD("detected charset is %s\n", charset);
3690 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3693 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3694 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3696 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3697 LOGW("failed to add subparse\n");
3698 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3699 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3700 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3704 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3705 LOGW("failed to link subsrc and subparse\n");
3709 player->play_subtitle = TRUE;
3710 player->adjust_subtitle_pos = 0;
3712 LOGD("play subtitle using subtitle file\n");
3714 if (player->pipeline->textbin == NULL) {
3715 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3716 LOGE("failed to create text sink bin. continuing without text\n");
3720 textbin = player->pipeline->textbin;
3722 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3723 LOGW("failed to add textbin\n");
3725 /* release signal */
3726 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3728 /* release textbin with it's childs */
3729 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3730 MMPLAYER_FREEIF(player->pipeline->textbin);
3731 player->pipeline->textbin = textbin = NULL;
3735 LOGD("link text input selector and textbin ghost pad");
3737 player->textsink_linked = 1;
3738 player->external_text_idx = 0;
3739 LOGI("player->textsink_linked set to 1\n");
3741 textbin = player->pipeline->textbin;
3742 LOGD("text bin has been created. reuse it.");
3743 player->external_text_idx = 1;
3746 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3747 LOGW("failed to link subparse and textbin\n");
3751 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3753 LOGE("failed to get sink pad from textsink to probe data");
3757 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3758 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3760 gst_object_unref(pad);
3763 /* create dot. for debugging */
3764 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3767 return MM_ERROR_NONE;
3770 /* release text pipeline resource */
3771 player->textsink_linked = 0;
3773 /* release signal */
3774 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3776 if (player->pipeline->textbin) {
3777 LOGE("remove textbin");
3779 /* release textbin with it's childs */
3780 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3781 MMPLAYER_FREEIF(player->pipeline->textbin);
3782 player->pipeline->textbin = NULL;
3786 /* release subtitle elem */
3787 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3788 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3790 return MM_ERROR_PLAYER_INTERNAL;
3794 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3796 mm_player_t* player = (mm_player_t*) data;
3797 MMMessageParamType msg = {0, };
3798 GstClockTime duration = 0;
3799 gpointer text = NULL;
3800 guint text_size = 0;
3801 gboolean ret = TRUE;
3802 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3806 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3807 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3809 if (player->is_subtitle_force_drop) {
3810 LOGW("subtitle is dropped forcedly.");
3814 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3815 text = mapinfo.data;
3816 text_size = mapinfo.size;
3817 duration = GST_BUFFER_DURATION(buffer);
3819 if (player->set_mode.subtitle_off) {
3820 LOGD("subtitle is OFF.\n");
3824 if (!text || (text_size == 0)) {
3825 LOGD("There is no subtitle to be displayed.\n");
3829 msg.data = (void *) text;
3830 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3832 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3834 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3835 gst_buffer_unmap(buffer, &mapinfo);
3842 static GstPadProbeReturn
3843 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3845 mm_player_t *player = (mm_player_t *) u_data;
3846 GstClockTime cur_timestamp = 0;
3847 gint64 adjusted_timestamp = 0;
3848 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3850 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3852 if (player->set_mode.subtitle_off) {
3853 LOGD("subtitle is OFF.\n");
3857 if (player->adjust_subtitle_pos == 0) {
3858 LOGD("nothing to do");
3862 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3863 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3865 if (adjusted_timestamp < 0) {
3866 LOGD("adjusted_timestamp under zero");
3871 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3872 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3873 GST_TIME_ARGS(cur_timestamp),
3874 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3876 return GST_PAD_PROBE_OK;
3878 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3882 /* check player and subtitlebin are created */
3883 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3886 if (position == 0) {
3887 LOGD("nothing to do\n");
3889 return MM_ERROR_NONE;
3893 case MM_PLAYER_POS_FORMAT_TIME:
3895 /* check current postion */
3896 player->adjust_subtitle_pos = position;
3898 LOGD("save adjust_subtitle_pos in player") ;
3904 LOGW("invalid format.\n");
3906 return MM_ERROR_INVALID_ARGUMENT;
3912 return MM_ERROR_NONE;
3916 * This function is to create audio or video pipeline for playing.
3918 * @param player [in] handle of player
3920 * @return This function returns zero on success.
3925 __mmplayer_gst_create_pipeline(mm_player_t* player)
3927 int ret = MM_ERROR_NONE;
3928 MMPlayerGstElement *mainbin = NULL;
3929 MMHandleType attrs = 0;
3930 gint mode = MM_PLAYER_PD_MODE_NONE;
3933 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3935 /* get profile attribute */
3936 attrs = MMPLAYER_GET_ATTRS(player);
3938 LOGE("failed to get content attribute");
3942 /* create pipeline handles */
3943 if (player->pipeline) {
3944 LOGE("pipeline should be released before create new one");
3948 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3949 if (player->pipeline == NULL)
3952 /* create mainbin */
3953 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3954 if (mainbin == NULL)
3957 /* create pipeline */
3958 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3959 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3960 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3961 LOGE("failed to create pipeline");
3966 player->pipeline->mainbin = mainbin;
3969 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
3970 player->pd_mode = mode;
3972 /* create the source and decoder elements */
3973 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3974 ret = __mmplayer_gst_build_es_pipeline(player);
3975 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
3976 ret = __mmplayer_gst_build_pd_pipeline(player);
3978 ret = __mmplayer_gst_build_pipeline(player);
3981 if (ret != MM_ERROR_NONE) {
3982 LOGE("failed to create some elements");
3986 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3987 if (__mmplayer_check_subtitle(player)) {
3988 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
3989 LOGE("failed to create text pipeline");
3993 ret = __mmplayer_gst_add_bus_watch(player);
3994 if (ret != MM_ERROR_NONE) {
3995 LOGE("failed to add bus watch");
4000 return MM_ERROR_NONE;
4003 __mmplayer_gst_destroy_pipeline(player);
4004 return MM_ERROR_PLAYER_INTERNAL;
4008 __mmplayer_reset_gapless_state(mm_player_t* player)
4011 MMPLAYER_RETURN_IF_FAIL(player
4013 && player->pipeline->audiobin
4014 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4016 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4023 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4026 int ret = MM_ERROR_NONE;
4030 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4032 /* cleanup stuffs */
4033 MMPLAYER_FREEIF(player->type);
4034 player->no_more_pad = FALSE;
4035 player->num_dynamic_pad = 0;
4036 player->demux_pad_index = 0;
4038 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4039 player->subtitle_language_list = NULL;
4040 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4042 __mmplayer_reset_gapless_state(player);
4044 if (player->streamer) {
4045 __mm_player_streaming_deinitialize(player->streamer);
4046 __mm_player_streaming_destroy(player->streamer);
4047 player->streamer = NULL;
4050 /* cleanup unlinked mime type */
4051 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4052 MMPLAYER_FREEIF(player->unlinked_video_mime);
4053 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4055 /* cleanup running stuffs */
4056 __mmplayer_cancel_eos_timer(player);
4058 /* cleanup gst stuffs */
4059 if (player->pipeline) {
4060 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4061 GstTagList* tag_list = player->pipeline->tag_list;
4063 /* first we need to disconnect all signal hander */
4064 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4067 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4068 MMPlayerGstElement* videobin = player->pipeline->videobin;
4069 MMPlayerGstElement* textbin = player->pipeline->textbin;
4070 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4071 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4072 gst_object_unref(bus);
4074 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4075 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4076 if (ret != MM_ERROR_NONE) {
4077 LOGE("fail to change state to NULL\n");
4078 return MM_ERROR_PLAYER_INTERNAL;
4081 LOGW("succeeded in changing state to NULL\n");
4083 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4086 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4087 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4089 /* free avsysaudiosink
4090 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4091 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4093 MMPLAYER_FREEIF(audiobin);
4094 MMPLAYER_FREEIF(videobin);
4095 MMPLAYER_FREEIF(textbin);
4096 MMPLAYER_FREEIF(mainbin);
4100 gst_tag_list_free(tag_list);
4102 MMPLAYER_FREEIF(player->pipeline);
4104 MMPLAYER_FREEIF(player->album_art);
4106 if (player->v_stream_caps) {
4107 gst_caps_unref(player->v_stream_caps);
4108 player->v_stream_caps = NULL;
4110 if (player->a_stream_caps) {
4111 gst_caps_unref(player->a_stream_caps);
4112 player->a_stream_caps = NULL;
4115 if (player->s_stream_caps) {
4116 gst_caps_unref(player->s_stream_caps);
4117 player->s_stream_caps = NULL;
4119 __mmplayer_track_destroy(player);
4121 if (player->sink_elements)
4122 g_list_free(player->sink_elements);
4123 player->sink_elements = NULL;
4125 if (player->bufmgr) {
4126 tbm_bufmgr_deinit(player->bufmgr);
4127 player->bufmgr = NULL;
4130 LOGW("finished destroy pipeline\n");
4137 static int __mmplayer_gst_realize(mm_player_t* player)
4140 int ret = MM_ERROR_NONE;
4144 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4146 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4148 ret = __mmplayer_gst_create_pipeline(player);
4150 LOGE("failed to create pipeline\n");
4154 /* set pipeline state to READY */
4155 /* NOTE : state change to READY must be performed sync. */
4156 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4157 ret = __mmplayer_gst_set_state(player,
4158 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4160 if (ret != MM_ERROR_NONE) {
4161 /* return error if failed to set state */
4162 LOGE("failed to set READY state");
4166 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4168 /* create dot before error-return. for debugging */
4169 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4176 static int __mmplayer_gst_unrealize(mm_player_t* player)
4178 int ret = MM_ERROR_NONE;
4182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4184 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4185 MMPLAYER_PRINT_STATE(player);
4187 /* release miscellaneous information */
4188 __mmplayer_release_misc(player);
4190 /* destroy pipeline */
4191 ret = __mmplayer_gst_destroy_pipeline(player);
4192 if (ret != MM_ERROR_NONE) {
4193 LOGE("failed to destory pipeline\n");
4197 /* release miscellaneous information.
4198 these info needs to be released after pipeline is destroyed. */
4199 __mmplayer_release_misc_post(player);
4201 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4209 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4214 LOGW("set_message_callback is called with invalid player handle\n");
4215 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4218 player->msg_cb = callback;
4219 player->msg_cb_param = user_param;
4221 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4225 return MM_ERROR_NONE;
4228 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4230 int ret = MM_ERROR_NONE;
4235 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4236 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4237 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4239 memset(data, 0, sizeof(MMPlayerParseProfile));
4241 if (strstr(uri, "es_buff://")) {
4242 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4243 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4244 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4245 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4247 tmp = g_ascii_strdown(uri, strlen(uri));
4248 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4249 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4251 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4253 } else if (strstr(uri, "mms://")) {
4254 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4255 } else if ((path = strstr(uri, "mem://"))) {
4256 ret = __mmplayer_set_mem_uri(data, path, param);
4258 ret = __mmplayer_set_file_uri(data, uri);
4261 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4262 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4263 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4264 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4266 /* dump parse result */
4267 SECURE_LOGW("incoming uri : %s\n", uri);
4268 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4269 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4277 __mmplayer_can_do_interrupt(mm_player_t *player)
4279 if (!player || !player->pipeline || !player->attrs) {
4280 LOGW("not initialized");
4284 if (player->audio_stream_render_cb) {
4285 LOGW("not support in pcm extraction mode");
4289 /* check if seeking */
4290 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4291 MMMessageParamType msg_param;
4292 memset(&msg_param, 0, sizeof(MMMessageParamType));
4293 msg_param.code = MM_ERROR_PLAYER_SEEK;
4294 player->seek_state = MMPLAYER_SEEK_NONE;
4295 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4299 /* check other thread */
4300 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4301 LOGW("locked already, cmd state : %d", player->cmd);
4303 /* check application command */
4304 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4305 LOGW("playing.. should wait cmd lock then, will be interrupted");
4307 /* lock will be released at mrp_resource_release_cb() */
4308 MMPLAYER_CMD_LOCK(player);
4311 LOGW("nothing to do");
4314 LOGW("can interrupt immediately");
4318 FAILED: /* with CMD UNLOCKED */
4321 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4326 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4329 mm_player_t *player = NULL;
4333 if (user_data == NULL) {
4334 LOGE("- user_data is null\n");
4337 player = (mm_player_t *)user_data;
4339 /* do something to release resource here.
4340 * player stop and interrupt forwarding */
4341 if (!__mmplayer_can_do_interrupt(player)) {
4342 LOGW("no need to interrupt, so leave");
4344 MMMessageParamType msg = {0, };
4347 player->interrupted_by_resource = TRUE;
4349 /* get last play position */
4350 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4351 LOGW("failed to get play position.");
4353 msg.union_type = MM_MSG_UNION_TIME;
4354 msg.time.elapsed = pos;
4355 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4357 LOGD("video resource conflict so, resource will be freed by unrealizing");
4358 if (_mmplayer_unrealize((MMHandleType)player))
4359 LOGW("failed to unrealize");
4361 /* lock is called in __mmplayer_can_do_interrupt() */
4362 MMPLAYER_CMD_UNLOCK(player);
4365 if (res == player->video_overlay_resource)
4366 player->video_overlay_resource = FALSE;
4368 player->video_decoder_resource = FALSE;
4376 __mmplayer_initialize_video_roi(mm_player_t *player)
4378 player->video_roi.scale_x = 0.0;
4379 player->video_roi.scale_y = 0.0;
4380 player->video_roi.scale_width = 1.0;
4381 player->video_roi.scale_height = 1.0;
4385 _mmplayer_create_player(MMHandleType handle)
4387 int ret = MM_ERROR_PLAYER_INTERNAL;
4388 bool enabled = false;
4390 mm_player_t* player = MM_PLAYER_CAST(handle);
4394 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4396 /* initialize player state */
4397 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4398 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4399 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4400 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4402 /* check current state */
4403 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4405 /* construct attributes */
4406 player->attrs = _mmplayer_construct_attribute(handle);
4408 if (!player->attrs) {
4409 LOGE("Failed to construct attributes\n");
4413 /* initialize gstreamer with configured parameter */
4414 if (!__mmplayer_init_gstreamer(player)) {
4415 LOGE("Initializing gstreamer failed\n");
4416 _mmplayer_deconstruct_attribute(handle);
4420 /* create lock. note that g_tread_init() has already called in gst_init() */
4421 g_mutex_init(&player->fsink_lock);
4423 /* create update tag lock */
4424 g_mutex_init(&player->update_tag_lock);
4426 /* create gapless play mutex */
4427 g_mutex_init(&player->gapless_play_thread_mutex);
4429 /* create gapless play cond */
4430 g_cond_init(&player->gapless_play_thread_cond);
4432 /* create gapless play thread */
4433 player->gapless_play_thread =
4434 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4435 if (!player->gapless_play_thread) {
4436 LOGE("failed to create gapless play thread");
4437 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4438 g_mutex_clear(&player->gapless_play_thread_mutex);
4439 g_cond_clear(&player->gapless_play_thread_cond);
4443 player->bus_msg_q = g_queue_new();
4444 if (!player->bus_msg_q) {
4445 LOGE("failed to create queue for bus_msg");
4446 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4450 ret = _mmplayer_initialize_video_capture(player);
4451 if (ret != MM_ERROR_NONE) {
4452 LOGE("failed to initialize video capture\n");
4456 /* initialize resource manager */
4457 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4458 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4459 &player->resource_manager)) {
4460 LOGE("failed to initialize resource manager\n");
4461 ret = MM_ERROR_PLAYER_INTERNAL;
4465 if (MMPLAYER_IS_HTTP_PD(player)) {
4466 player->pd_downloader = NULL;
4467 player->pd_file_save_path = NULL;
4470 /* create video bo lock and cond */
4471 g_mutex_init(&player->video_bo_mutex);
4472 g_cond_init(&player->video_bo_cond);
4474 /* create media stream callback mutex */
4475 g_mutex_init(&player->media_stream_cb_lock);
4477 /* create subtitle info lock and cond */
4478 g_mutex_init(&player->subtitle_info_mutex);
4479 g_cond_init(&player->subtitle_info_cond);
4481 player->streaming_type = STREAMING_SERVICE_NONE;
4483 /* give default value of audio effect setting */
4484 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4485 player->sound.rg_enable = false;
4486 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4488 player->play_subtitle = FALSE;
4489 player->has_closed_caption = FALSE;
4490 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4491 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4492 player->pending_resume = FALSE;
4493 if (player->ini.dump_element_keyword[0][0] == '\0')
4494 player->ini.set_dump_element_flag = FALSE;
4496 player->ini.set_dump_element_flag = TRUE;
4498 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4499 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4500 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4502 /* Set video360 settings to their defaults for just-created player.
4505 player->is_360_feature_enabled = FALSE;
4506 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4507 LOGI("spherical feature info: %d", enabled);
4509 player->is_360_feature_enabled = TRUE;
4511 LOGE("failed to get spherical feature info");
4514 player->is_content_spherical = FALSE;
4515 player->is_video360_enabled = TRUE;
4516 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4517 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4518 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4519 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4520 player->video360_zoom = 1.0f;
4521 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4522 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4524 __mmplayer_initialize_video_roi(player);
4526 /* set player state to null */
4527 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4528 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4530 return MM_ERROR_NONE;
4534 g_mutex_clear(&player->fsink_lock);
4536 /* free update tag lock */
4537 g_mutex_clear(&player->update_tag_lock);
4539 g_queue_free(player->bus_msg_q);
4541 /* free gapless play thread */
4542 if (player->gapless_play_thread) {
4543 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4544 player->gapless_play_thread_exit = TRUE;
4545 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4546 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4548 g_thread_join(player->gapless_play_thread);
4549 player->gapless_play_thread = NULL;
4551 g_mutex_clear(&player->gapless_play_thread_mutex);
4552 g_cond_clear(&player->gapless_play_thread_cond);
4555 /* release attributes */
4556 _mmplayer_deconstruct_attribute(handle);
4564 __mmplayer_init_gstreamer(mm_player_t* player)
4566 static gboolean initialized = FALSE;
4567 static const int max_argc = 50;
4569 gchar** argv = NULL;
4570 gchar** argv2 = NULL;
4576 LOGD("gstreamer already initialized.\n");
4581 argc = malloc(sizeof(int));
4582 argv = malloc(sizeof(gchar*) * max_argc);
4583 argv2 = malloc(sizeof(gchar*) * max_argc);
4585 if (!argc || !argv || !argv2)
4588 memset(argv, 0, sizeof(gchar*) * max_argc);
4589 memset(argv2, 0, sizeof(gchar*) * max_argc);
4593 argv[0] = g_strdup("mmplayer");
4596 for (i = 0; i < 5; i++) {
4597 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4598 if (strlen(player->ini.gst_param[i]) > 0) {
4599 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4604 /* we would not do fork for scanning plugins */
4605 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4608 /* check disable registry scan */
4609 if (player->ini.skip_rescan) {
4610 argv[*argc] = g_strdup("--gst-disable-registry-update");
4614 /* check disable segtrap */
4615 if (player->ini.disable_segtrap) {
4616 argv[*argc] = g_strdup("--gst-disable-segtrap");
4620 LOGD("initializing gstreamer with following parameter\n");
4621 LOGD("argc : %d\n", *argc);
4624 for (i = 0; i < arg_count; i++) {
4626 LOGD("argv[%d] : %s\n", i, argv2[i]);
4629 /* initializing gstreamer */
4630 if (!gst_init_check(argc, &argv, &err)) {
4631 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4638 for (i = 0; i < arg_count; i++) {
4639 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4640 MMPLAYER_FREEIF(argv2[i]);
4643 MMPLAYER_FREEIF(argv);
4644 MMPLAYER_FREEIF(argv2);
4645 MMPLAYER_FREEIF(argc);
4655 for (i = 0; i < arg_count; i++) {
4656 LOGD("free[%d] : %s\n", i, argv2[i]);
4657 MMPLAYER_FREEIF(argv2[i]);
4660 MMPLAYER_FREEIF(argv);
4661 MMPLAYER_FREEIF(argv2);
4662 MMPLAYER_FREEIF(argc);
4668 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4672 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4673 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4674 MMPLAYER_FREEIF(player->pd_file_save_path);
4677 return MM_ERROR_NONE;
4681 __mmplayer_check_async_state_transition(mm_player_t* player)
4683 GstState element_state = GST_STATE_VOID_PENDING;
4684 GstState element_pending_state = GST_STATE_VOID_PENDING;
4685 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4686 GstElement * element = NULL;
4687 gboolean async = FALSE;
4689 /* check player handle */
4690 MMPLAYER_RETURN_IF_FAIL(player &&
4692 player->pipeline->mainbin &&
4693 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4696 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4698 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4699 LOGD("don't need to check the pipeline state");
4703 MMPLAYER_PRINT_STATE(player);
4705 /* wait for state transition */
4706 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4707 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4709 if (ret == GST_STATE_CHANGE_FAILURE) {
4710 LOGE(" [%s] state : %s pending : %s \n",
4711 GST_ELEMENT_NAME(element),
4712 gst_element_state_get_name(element_state),
4713 gst_element_state_get_name(element_pending_state));
4715 /* dump state of all element */
4716 __mmplayer_dump_pipeline_state(player);
4721 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4726 _mmplayer_destroy(MMHandleType handle)
4728 mm_player_t* player = MM_PLAYER_CAST(handle);
4732 /* check player handle */
4733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4735 /* destroy can called at anytime */
4736 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4738 /* check async state transition */
4739 __mmplayer_check_async_state_transition(player);
4741 __mmplayer_destroy_streaming_ext(player);
4743 /* release gapless play thread */
4744 if (player->gapless_play_thread) {
4745 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4746 player->gapless_play_thread_exit = TRUE;
4747 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4748 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4750 LOGD("waitting for gapless play thread exit\n");
4751 g_thread_join(player->gapless_play_thread);
4752 g_mutex_clear(&player->gapless_play_thread_mutex);
4753 g_cond_clear(&player->gapless_play_thread_cond);
4754 LOGD("gapless play thread released\n");
4757 _mmplayer_release_video_capture(player);
4759 /* de-initialize resource manager */
4760 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4761 player->resource_manager))
4762 LOGE("failed to deinitialize resource manager\n");
4764 /* release pipeline */
4765 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4766 LOGE("failed to destory pipeline\n");
4767 return MM_ERROR_PLAYER_INTERNAL;
4770 g_queue_free(player->bus_msg_q);
4772 /* release subtitle info lock and cond */
4773 g_mutex_clear(&player->subtitle_info_mutex);
4774 g_cond_clear(&player->subtitle_info_cond);
4776 __mmplayer_release_dump_list(player->dump_list);
4778 /* release miscellaneous information */
4779 __mmplayer_release_misc(player);
4781 /* release miscellaneous information.
4782 these info needs to be released after pipeline is destroyed. */
4783 __mmplayer_release_misc_post(player);
4785 /* release attributes */
4786 _mmplayer_deconstruct_attribute(handle);
4789 g_mutex_clear(&player->fsink_lock);
4792 g_mutex_clear(&player->update_tag_lock);
4794 /* release video bo lock and cond */
4795 g_mutex_clear(&player->video_bo_mutex);
4796 g_cond_clear(&player->video_bo_cond);
4798 /* release media stream callback lock */
4799 g_mutex_clear(&player->media_stream_cb_lock);
4803 return MM_ERROR_NONE;
4807 __mmplayer_realize_streaming_ext(mm_player_t* player)
4809 int ret = MM_ERROR_NONE;
4812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4814 if (MMPLAYER_IS_HTTP_PD(player)) {
4815 gboolean bret = FALSE;
4817 player->pd_downloader = _mmplayer_create_pd_downloader();
4818 if (!player->pd_downloader) {
4819 LOGE("Unable to create PD Downloader...");
4820 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4823 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4825 if (FALSE == bret) {
4826 LOGE("Unable to create PD Downloader...");
4827 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
4836 _mmplayer_realize(MMHandleType hplayer)
4838 mm_player_t* player = (mm_player_t*)hplayer;
4841 MMHandleType attrs = 0;
4842 int ret = MM_ERROR_NONE;
4846 /* check player handle */
4847 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4849 /* check current state */
4850 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4852 attrs = MMPLAYER_GET_ATTRS(player);
4854 LOGE("fail to get attributes.\n");
4855 return MM_ERROR_PLAYER_INTERNAL;
4857 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4858 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4860 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4861 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4863 if (ret != MM_ERROR_NONE) {
4864 LOGE("failed to parse profile");
4869 if (uri && (strstr(uri, "es_buff://"))) {
4870 if (strstr(uri, "es_buff://push_mode"))
4871 player->es_player_push_mode = TRUE;
4873 player->es_player_push_mode = FALSE;
4876 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4877 LOGW("mms protocol is not supported format.\n");
4878 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4881 if (MMPLAYER_IS_HTTP_PD(player))
4882 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
4883 else if (MMPLAYER_IS_STREAMING(player))
4884 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4886 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4888 player->smooth_streaming = FALSE;
4889 player->videodec_linked = 0;
4890 player->audiodec_linked = 0;
4891 player->textsink_linked = 0;
4892 player->is_external_subtitle_present = FALSE;
4893 player->is_external_subtitle_added_now = FALSE;
4894 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4895 player->video360_metadata.is_spherical = -1;
4896 player->is_openal_plugin_used = FALSE;
4897 player->demux_pad_index = 0;
4898 player->subtitle_language_list = NULL;
4899 player->is_subtitle_force_drop = FALSE;
4900 player->last_multiwin_status = FALSE;
4902 __mmplayer_track_initialize(player);
4903 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4905 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4906 player->streamer = __mm_player_streaming_create();
4907 __mm_player_streaming_initialize(player->streamer);
4910 /* realize pipeline */
4911 ret = __mmplayer_gst_realize(player);
4912 if (ret != MM_ERROR_NONE)
4913 LOGE("fail to realize the player.\n");
4915 ret = __mmplayer_realize_streaming_ext(player);
4917 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4925 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
4928 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4930 /* destroy can called at anytime */
4931 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
4932 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
4935 return MM_ERROR_NONE;
4939 _mmplayer_unrealize(MMHandleType hplayer)
4941 mm_player_t* player = (mm_player_t*)hplayer;
4942 int ret = MM_ERROR_NONE;
4946 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4948 MMPLAYER_CMD_UNLOCK(player);
4949 /* destroy the gst bus msg thread which is created during realize.
4950 this funct have to be called before getting cmd lock. */
4951 __mmplayer_bus_msg_thread_destroy(player);
4952 MMPLAYER_CMD_LOCK(player);
4954 /* check current state */
4955 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4957 /* check async state transition */
4958 __mmplayer_check_async_state_transition(player);
4960 __mmplayer_unrealize_streaming_ext(player);
4962 /* unrealize pipeline */
4963 ret = __mmplayer_gst_unrealize(player);
4965 /* set asm stop if success */
4966 if (MM_ERROR_NONE == ret) {
4967 if (!player->interrupted_by_resource) {
4968 if (player->video_decoder_resource != NULL) {
4969 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4970 player->video_decoder_resource);
4971 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4972 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4974 player->video_decoder_resource = NULL;
4977 if (player->video_overlay_resource != NULL) {
4978 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4979 player->video_overlay_resource);
4980 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4981 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4983 player->video_overlay_resource = NULL;
4986 ret = mm_resource_manager_commit(player->resource_manager);
4987 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4988 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4991 LOGE("failed and don't change asm state to stop");
4999 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5001 mm_player_t* player = (mm_player_t*)hplayer;
5003 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5005 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5009 _mmplayer_get_state(MMHandleType hplayer, int* state)
5011 mm_player_t *player = (mm_player_t*)hplayer;
5013 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5015 *state = MMPLAYER_CURRENT_STATE(player);
5017 return MM_ERROR_NONE;
5022 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5024 mm_player_t* player = (mm_player_t*) hplayer;
5025 GstElement* vol_element = NULL;
5030 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5032 LOGD("volume [L]=%f:[R]=%f\n",
5033 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5035 /* invalid factor range or not */
5036 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5037 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5038 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5039 return MM_ERROR_INVALID_ARGUMENT;
5043 /* not support to set other value into each channel */
5044 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5045 return MM_ERROR_INVALID_ARGUMENT;
5047 /* Save volume to handle. Currently the first array element will be saved. */
5048 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5050 /* check pipeline handle */
5051 if (!player->pipeline || !player->pipeline->audiobin) {
5052 LOGD("audiobin is not created yet\n");
5053 LOGD("but, current stored volume will be set when it's created.\n");
5055 /* NOTE : stored volume will be used in create_audiobin
5056 * returning MM_ERROR_NONE here makes application to able to
5057 * set volume at anytime.
5059 return MM_ERROR_NONE;
5062 /* setting volume to volume element */
5063 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5066 LOGD("volume is set [%f]\n", player->sound.volume);
5067 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5072 return MM_ERROR_NONE;
5077 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5079 mm_player_t* player = (mm_player_t*) hplayer;
5084 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5085 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5087 /* returning stored volume */
5088 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5089 volume->level[i] = player->sound.volume;
5093 return MM_ERROR_NONE;
5097 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5099 mm_player_t* player = (mm_player_t*) hplayer;
5100 GstElement* vol_element = NULL;
5104 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5106 /* mute value shoud 0 or 1 */
5107 if (mute != 0 && mute != 1) {
5108 LOGE("bad mute value\n");
5110 /* FIXIT : definitly, we need _BAD_PARAM error code */
5111 return MM_ERROR_INVALID_ARGUMENT;
5114 player->sound.mute = mute;
5116 /* just hold mute value if pipeline is not ready */
5117 if (!player->pipeline || !player->pipeline->audiobin) {
5118 LOGD("pipeline is not ready. holding mute value\n");
5119 return MM_ERROR_NONE;
5122 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5124 /* NOTE : volume will only created when the bt is enabled */
5126 LOGD("mute : %d\n", mute);
5127 g_object_set(vol_element, "mute", mute, NULL);
5129 LOGD("volume elemnet is not created. using volume in audiosink\n");
5133 return MM_ERROR_NONE;
5137 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5139 mm_player_t* player = (mm_player_t*) hplayer;
5143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5144 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5146 /* just hold mute value if pipeline is not ready */
5147 if (!player->pipeline || !player->pipeline->audiobin) {
5148 LOGD("pipeline is not ready. returning stored value\n");
5149 *pmute = player->sound.mute;
5150 return MM_ERROR_NONE;
5153 *pmute = player->sound.mute;
5157 return MM_ERROR_NONE;
5161 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5163 mm_player_t* player = (mm_player_t*) hplayer;
5167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 player->video_stream_changed_cb = callback;
5170 player->video_stream_changed_cb_user_param = user_param;
5171 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5175 return MM_ERROR_NONE;
5179 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5181 mm_player_t* player = (mm_player_t*) hplayer;
5185 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5187 player->audio_stream_changed_cb = callback;
5188 player->audio_stream_changed_cb_user_param = user_param;
5189 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5193 return MM_ERROR_NONE;
5197 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5199 mm_player_t *player = (mm_player_t*) hplayer;
5203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5205 player->audio_stream_render_cb = callback;
5206 player->audio_stream_cb_user_param = user_param;
5207 player->audio_stream_sink_sync = sync;
5208 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5212 return MM_ERROR_NONE;
5216 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_stream_callback callback, void *user_param)
5218 mm_player_t* player = (mm_player_t*) hplayer;
5222 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5224 if (callback && !player->bufmgr)
5225 player->bufmgr = tbm_bufmgr_init(-1);
5227 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5228 player->video_stream_cb = callback;
5229 player->video_stream_cb_user_param = user_param;
5231 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5235 return MM_ERROR_NONE;
5239 __mmplayer_start_streaming_ext(mm_player_t *player)
5241 gint ret = MM_ERROR_NONE;
5244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5246 if (MMPLAYER_IS_HTTP_PD(player)) {
5247 if (!player->pd_downloader) {
5248 ret = __mmplayer_realize_streaming_ext(player);
5250 if (ret != MM_ERROR_NONE) {
5251 LOGE("failed to realize streaming ext\n");
5256 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5257 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5259 LOGE("ERROR while starting PD...\n");
5260 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5262 ret = MM_ERROR_NONE;
5271 _mmplayer_start(MMHandleType hplayer)
5273 mm_player_t* player = (mm_player_t*) hplayer;
5274 gint ret = MM_ERROR_NONE;
5278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 /* check current state */
5281 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5283 /* PD - start streaming */
5284 ret = __mmplayer_start_streaming_ext(player);
5285 if (ret != MM_ERROR_NONE) {
5286 LOGE("failed to start streaming ext 0x%X", ret);
5290 /* start pipeline */
5291 ret = __mmplayer_gst_start(player);
5292 if (ret != MM_ERROR_NONE)
5293 LOGE("failed to start player.\n");
5295 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5296 LOGD("force playing start even during buffering");
5297 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5305 /* NOTE: post "not supported codec message" to application
5306 * when one codec is not found during AUTOPLUGGING in MSL.
5307 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5308 * And, if any codec is not found, don't send message here.
5309 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5312 __mmplayer_handle_missed_plugin(mm_player_t* player)
5314 MMMessageParamType msg_param;
5315 memset(&msg_param, 0, sizeof(MMMessageParamType));
5316 gboolean post_msg_direct = FALSE;
5320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5322 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5323 player->not_supported_codec, player->can_support_codec);
5325 if (player->not_found_demuxer) {
5326 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5327 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5329 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5330 MMPLAYER_FREEIF(msg_param.data);
5332 return MM_ERROR_NONE;
5335 if (player->not_supported_codec) {
5336 if (player->can_support_codec) {
5337 // There is one codec to play
5338 post_msg_direct = TRUE;
5340 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5341 post_msg_direct = TRUE;
5344 if (post_msg_direct) {
5345 MMMessageParamType msg_param;
5346 memset(&msg_param, 0, sizeof(MMMessageParamType));
5348 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5349 LOGW("not found AUDIO codec, posting error code to application.\n");
5351 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5352 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5353 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5354 LOGW("not found VIDEO codec, posting error code to application.\n");
5356 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5357 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5360 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5362 MMPLAYER_FREEIF(msg_param.data);
5364 return MM_ERROR_NONE;
5366 // no any supported codec case
5367 LOGW("not found any codec, posting error code to application.\n");
5369 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5370 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5371 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5373 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5374 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5377 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5379 MMPLAYER_FREEIF(msg_param.data);
5385 return MM_ERROR_NONE;
5388 static void __mmplayer_check_pipeline(mm_player_t* player)
5390 GstState element_state = GST_STATE_VOID_PENDING;
5391 GstState element_pending_state = GST_STATE_VOID_PENDING;
5393 int ret = MM_ERROR_NONE;
5395 if (player->gapless.reconfigure) {
5396 LOGW("pipeline is under construction.\n");
5398 MMPLAYER_PLAYBACK_LOCK(player);
5399 MMPLAYER_PLAYBACK_UNLOCK(player);
5401 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5403 /* wait for state transition */
5404 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5406 if (ret == GST_STATE_CHANGE_FAILURE)
5407 LOGE("failed to change pipeline state within %d sec\n", timeout);
5411 /* NOTE : it should be able to call 'stop' anytime*/
5413 _mmplayer_stop(MMHandleType hplayer)
5415 mm_player_t* player = (mm_player_t*)hplayer;
5416 int ret = MM_ERROR_NONE;
5420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5422 /* check current state */
5423 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5425 /* check pipline building state */
5426 __mmplayer_check_pipeline(player);
5427 __mmplayer_reset_gapless_state(player);
5429 /* NOTE : application should not wait for EOS after calling STOP */
5430 __mmplayer_cancel_eos_timer(player);
5432 __mmplayer_unrealize_streaming_ext(player);
5435 player->seek_state = MMPLAYER_SEEK_NONE;
5438 ret = __mmplayer_gst_stop(player);
5440 if (ret != MM_ERROR_NONE)
5441 LOGE("failed to stop player.\n");
5449 _mmplayer_pause(MMHandleType hplayer)
5451 mm_player_t* player = (mm_player_t*)hplayer;
5452 gint64 pos_nsec = 0;
5453 gboolean async = FALSE;
5454 gint ret = MM_ERROR_NONE;
5458 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5460 /* check current state */
5461 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5463 /* check pipline building state */
5464 __mmplayer_check_pipeline(player);
5466 switch (MMPLAYER_CURRENT_STATE(player)) {
5467 case MM_PLAYER_STATE_READY:
5469 /* check prepare async or not.
5470 * In the case of streaming playback, it's recommned to avoid blocking wait.
5472 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5473 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5475 /* Changing back sync of rtspsrc to async */
5476 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5477 LOGD("async prepare working mode for rtsp");
5483 case MM_PLAYER_STATE_PLAYING:
5485 /* NOTE : store current point to overcome some bad operation
5486 *(returning zero when getting current position in paused state) of some
5489 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5490 LOGW("getting current position failed in paused\n");
5492 player->last_position = pos_nsec;
5494 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5495 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5496 This causes problem is position calculation during normal pause resume scenarios also.
5497 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5498 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5499 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5500 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5506 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5507 LOGD("doing async pause in case of ms buff src");
5511 /* pause pipeline */
5512 ret = __mmplayer_gst_pause(player, async);
5514 if (ret != MM_ERROR_NONE)
5515 LOGE("failed to pause player. ret : 0x%x\n", ret);
5517 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5518 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5519 LOGE("failed to update display_rotation");
5527 /* in case of streaming, pause could take long time.*/
5529 _mmplayer_abort_pause(MMHandleType hplayer)
5531 mm_player_t* player = (mm_player_t*)hplayer;
5532 int ret = MM_ERROR_NONE;
5536 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5538 player->pipeline->mainbin,
5539 MM_ERROR_PLAYER_NOT_INITIALIZED);
5541 LOGD("set the pipeline state to READY");
5543 /* set state to READY */
5544 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5545 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5546 if (ret != MM_ERROR_NONE) {
5547 LOGE("fail to change state to READY");
5548 return MM_ERROR_PLAYER_INTERNAL;
5551 LOGD("succeeded in changing state to READY");
5557 _mmplayer_resume(MMHandleType hplayer)
5559 mm_player_t* player = (mm_player_t*)hplayer;
5560 int ret = MM_ERROR_NONE;
5561 gboolean async = FALSE;
5565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5567 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5568 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5569 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5573 /* Changing back sync mode rtspsrc to async */
5574 LOGD("async resume for rtsp case");
5578 /* check current state */
5579 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5581 ret = __mmplayer_gst_resume(player, async);
5582 if (ret != MM_ERROR_NONE)
5583 LOGE("failed to resume player.\n");
5585 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5586 LOGD("force resume even during buffering");
5587 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5596 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5598 mm_player_t* player = (mm_player_t*)hplayer;
5599 gint64 pos_nsec = 0;
5600 int ret = MM_ERROR_NONE;
5602 signed long long start = 0, stop = 0;
5603 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5606 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5607 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5609 /* The sound of video is not supported under 0.0 and over 2.0. */
5610 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5611 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5614 _mmplayer_set_mute(hplayer, mute);
5616 if (player->playback_rate == rate)
5617 return MM_ERROR_NONE;
5619 /* If the position is reached at start potion during fast backward, EOS is posted.
5620 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5622 player->playback_rate = rate;
5624 current_state = MMPLAYER_CURRENT_STATE(player);
5626 if (current_state != MM_PLAYER_STATE_PAUSED)
5627 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5629 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5631 if ((current_state == MM_PLAYER_STATE_PAUSED)
5632 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5633 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5634 pos_nsec = player->last_position;
5639 stop = GST_CLOCK_TIME_NONE;
5641 start = GST_CLOCK_TIME_NONE;
5645 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5646 player->playback_rate,
5648 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5649 GST_SEEK_TYPE_SET, start,
5650 GST_SEEK_TYPE_SET, stop)) {
5651 LOGE("failed to set speed playback\n");
5652 return MM_ERROR_PLAYER_SEEK;
5655 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5659 return MM_ERROR_NONE;;
5663 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5665 mm_player_t* player = (mm_player_t*)hplayer;
5666 int ret = MM_ERROR_NONE;
5670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5672 /* check pipline building state */
5673 __mmplayer_check_pipeline(player);
5675 ret = __mmplayer_gst_set_position(player, position, FALSE);
5683 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5685 mm_player_t* player = (mm_player_t*)hplayer;
5686 int ret = MM_ERROR_NONE;
5688 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5690 ret = __mmplayer_gst_get_position(player, position);
5696 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5698 mm_player_t* player = (mm_player_t*)hplayer;
5699 int ret = MM_ERROR_NONE;
5701 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5702 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5704 *duration = player->duration;
5709 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5711 mm_player_t* player = (mm_player_t*)hplayer;
5712 int ret = MM_ERROR_NONE;
5714 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5722 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5724 mm_player_t* player = (mm_player_t*)hplayer;
5725 int ret = MM_ERROR_NONE;
5729 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5731 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5739 __mmplayer_is_midi_type(gchar* str_caps)
5741 if ((g_strrstr(str_caps, "audio/midi")) ||
5742 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5743 (g_strrstr(str_caps, "application/x-smaf")) ||
5744 (g_strrstr(str_caps, "audio/x-imelody")) ||
5745 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5746 (g_strrstr(str_caps, "audio/xmf")) ||
5747 (g_strrstr(str_caps, "audio/mxmf"))) {
5756 __mmplayer_is_only_mp3_type(gchar *str_caps)
5758 if (g_strrstr(str_caps, "application/x-id3") ||
5759 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5765 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5767 GstStructure* caps_structure = NULL;
5768 gint samplerate = 0;
5772 MMPLAYER_RETURN_IF_FAIL(player && caps);
5774 caps_structure = gst_caps_get_structure(caps, 0);
5776 /* set stream information */
5777 gst_structure_get_int(caps_structure, "rate", &samplerate);
5778 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5780 gst_structure_get_int(caps_structure, "channels", &channels);
5781 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5783 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5787 __mmplayer_update_content_type_info(mm_player_t* player)
5790 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5792 if (__mmplayer_is_midi_type(player->type)) {
5793 player->bypass_audio_effect = TRUE;
5794 } else if (g_strrstr(player->type, "application/x-hls")) {
5795 /* If it can't know exact type when it parses uri because of redirection case,
5796 * it will be fixed by typefinder or when doing autoplugging.
5798 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5799 if (player->streamer) {
5800 player->streamer->is_adaptive_streaming = TRUE;
5801 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5802 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5804 } else if (g_strrstr(player->type, "application/dash+xml")) {
5805 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5806 if (player->streamer) {
5807 player->streamer->is_adaptive_streaming = TRUE;
5808 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5812 LOGD("uri type : %d", player->profile.uri_type);
5817 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5818 GstCaps *caps, gpointer data)
5820 mm_player_t* player = (mm_player_t*)data;
5825 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5827 /* store type string */
5828 MMPLAYER_FREEIF(player->type);
5829 player->type = gst_caps_to_string(caps);
5831 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5832 player, player->type, probability, gst_caps_get_size(caps));
5835 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5836 (g_strrstr(player->type, "audio/x-raw-int"))) {
5837 LOGE("not support media format\n");
5839 if (player->msg_posted == FALSE) {
5840 MMMessageParamType msg_param;
5841 memset(&msg_param, 0, sizeof(MMMessageParamType));
5843 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5844 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5846 /* don't post more if one was sent already */
5847 player->msg_posted = TRUE;
5852 __mmplayer_update_content_type_info(player);
5854 pad = gst_element_get_static_pad(tf, "src");
5856 LOGE("fail to get typefind src pad.\n");
5860 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5861 gboolean async = FALSE;
5862 LOGE("failed to autoplug %s\n", player->type);
5864 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5866 if (async && player->msg_posted == FALSE)
5867 __mmplayer_handle_missed_plugin(player);
5873 gst_object_unref(GST_OBJECT(pad));
5881 __mmplayer_gst_make_decodebin(mm_player_t* player)
5883 GstElement *decodebin = NULL;
5887 /* create decodebin */
5888 decodebin = gst_element_factory_make("decodebin", NULL);
5891 LOGE("fail to create decodebin\n");
5895 /* raw pad handling signal */
5896 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5897 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5899 /* no-more-pad pad handling signal */
5900 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5901 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5903 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5904 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5906 /* This signal is emitted when a pad for which there is no further possible
5907 decoding is added to the decodebin.*/
5908 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5909 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5911 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5912 before looking for any elements that can handle that stream.*/
5913 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5914 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5916 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5917 before looking for any elements that can handle that stream.*/
5918 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5919 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5921 /* This signal is emitted once decodebin has finished decoding all the data.*/
5922 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5923 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5925 /* This signal is emitted when a element is added to the bin.*/
5926 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5927 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5934 __mmplayer_gst_make_queue2(mm_player_t *player)
5936 GstElement* queue2 = NULL;
5937 gint64 dur_bytes = 0L;
5938 guint max_buffer_size_bytes = 0;
5939 MMPlayerGstElement *mainbin = NULL;
5940 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5943 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5945 mainbin = player->pipeline->mainbin;
5947 queue2 = gst_element_factory_make("queue2", "queue2");
5949 LOGE("failed to create buffering queue element");
5953 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5954 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5956 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5958 if (dur_bytes > 0) {
5959 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5960 type = MUXED_BUFFER_TYPE_FILE;
5962 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5963 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5969 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5970 * skip the pull mode(file or ring buffering) setting. */
5971 if (!g_strrstr(player->type, "video/mpegts")) {
5972 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5973 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5975 __mm_player_streaming_set_queue2(player->streamer,
5978 max_buffer_size_bytes,
5979 player->ini.http_buffering_time,
5980 1.0, /* no meaning */
5981 player->ini.http_buffering_limit, /* no meaning */
5983 player->http_file_buffering_path,
5984 (guint64)dur_bytes);
5991 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5993 MMPlayerGstElement* mainbin = NULL;
5994 GstElement* decodebin = NULL;
5995 GstElement* queue2 = NULL;
5996 GstPad* sinkpad = NULL;
5997 GstPad* qsrcpad = NULL;
5998 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6001 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6003 mainbin = player->pipeline->mainbin;
6005 if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
6007 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6008 LOGW("need to check: muxed buffer is not null");
6011 queue2 = __mmplayer_gst_make_queue2(player);
6013 LOGE("failed to make queue2");
6017 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6018 LOGE("failed to add buffering queue");
6022 sinkpad = gst_element_get_static_pad(queue2, "sink");
6023 qsrcpad = gst_element_get_static_pad(queue2, "src");
6025 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6026 LOGE("failed to link [%s:%s]-[%s:%s]",
6027 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6031 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6032 LOGE("failed to sync queue2 state with parent");
6036 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6037 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6041 gst_object_unref(GST_OBJECT(sinkpad));
6045 /* create decodebin */
6046 decodebin = __mmplayer_gst_make_decodebin(player);
6048 LOGE("failed to make decodebin");
6052 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6053 LOGE("failed to add decodebin\n");
6057 /* to force caps on the decodebin element and avoid reparsing stuff by
6058 * typefind. It also avoids a deadlock in the way typefind activates pads in
6059 * the state change */
6060 g_object_set(decodebin, "sink-caps", caps, NULL);
6062 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6064 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6065 LOGE("failed to link [%s:%s]-[%s:%s]",
6066 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6070 gst_object_unref(GST_OBJECT(sinkpad));
6073 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6074 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6076 /* set decodebin property about buffer in streaming playback. *
6077 * in case of HLS/DASH, it does not need to have big buffer *
6078 * because it is kind of adaptive streaming. */
6079 if (!MMPLAYER_IS_HTTP_PD(player) &&
6080 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6081 gdouble high_percent = 0.0;
6083 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6084 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6086 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6087 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6089 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6090 "high-percent", (gint)high_percent,
6091 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6092 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6093 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6094 "max-size-buffers", 0, NULL); // disable or automatic
6097 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6098 LOGE("failed to sync decodebin state with parent\n");
6109 gst_object_unref(GST_OBJECT(sinkpad));
6112 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6113 * You need to explicitly set elements to the NULL state before
6114 * dropping the final reference, to allow them to clean up.
6116 gst_element_set_state(queue2, GST_STATE_NULL);
6118 /* And, it still has a parent "player".
6119 * You need to let the parent manage the object instead of unreffing the object directly.
6121 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6122 gst_object_unref(queue2);
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(decodebin, 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.
6137 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6138 gst_object_unref(decodebin);
6146 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6150 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6151 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6153 LOGD("class : %s, mime : %s \n", factory_class, mime);
6155 /* add missing plugin */
6156 /* NOTE : msl should check missing plugin for image mime type.
6157 * Some motion jpeg clips can have playable audio track.
6158 * So, msl have to play audio after displaying popup written video format not supported.
6160 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6161 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6162 LOGD("not found demuxer\n");
6163 player->not_found_demuxer = TRUE;
6164 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6170 if (!g_strrstr(factory_class, "Demuxer")) {
6171 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6172 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6173 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6175 /* check that clip have multi tracks or not */
6176 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6177 LOGD("video plugin is already linked\n");
6179 LOGW("add VIDEO to missing plugin\n");
6180 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6181 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6183 } else if (g_str_has_prefix(mime, "audio")) {
6184 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6185 LOGD("audio plugin is already linked\n");
6187 LOGW("add AUDIO to missing plugin\n");
6188 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6189 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6197 return MM_ERROR_NONE;
6202 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6204 mm_player_t* player = (mm_player_t*)data;
6208 MMPLAYER_RETURN_IF_FAIL(player);
6210 /* remove fakesink. */
6211 if (!__mmplayer_gst_remove_fakesink(player,
6212 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6213 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6214 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6215 * source element are not same. To overcome this situation, this function will called
6216 * several places and several times. Therefore, this is not an error case.
6221 LOGD("[handle: %p] pipeline has completely constructed", player);
6223 if ((player->ini.async_start) &&
6224 (player->msg_posted == FALSE) &&
6225 (player->cmd >= MMPLAYER_COMMAND_START))
6226 __mmplayer_handle_missed_plugin(player);
6228 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6232 __mmplayer_check_profile(void)
6235 static int profile_tv = -1;
6237 if (__builtin_expect(profile_tv != -1, 1))
6240 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6241 switch (*profileName) {
6256 __mmplayer_get_next_uri(mm_player_t *player)
6258 MMPlayerParseProfile profile;
6260 guint num_of_list = 0;
6263 num_of_list = g_list_length(player->uri_info.uri_list);
6264 uri_idx = player->uri_info.uri_idx;
6266 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6267 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6268 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6270 LOGW("next uri does not exist");
6274 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6275 LOGE("failed to parse profile");
6279 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6280 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6281 LOGW("uri type is not supported(%d)", profile.uri_type);
6285 LOGD("success to find next uri %d", uri_idx);
6289 if (uri_idx == num_of_list) {
6290 LOGE("failed to find next uri");
6294 player->uri_info.uri_idx = uri_idx;
6295 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6297 if (mm_attrs_commit_all(player->attrs)) {
6298 LOGE("failed to commit");
6302 SECURE_LOGD("next playback uri: %s", uri);
6307 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6309 #define REPEAT_COUNT_INFINITELY -1
6310 #define REPEAT_COUNT_MIN 2
6312 MMHandleType attrs = 0;
6313 gint mode = MM_PLAYER_PD_MODE_NONE;
6317 guint num_of_list = 0;
6318 int profile_tv = -1;
6322 LOGD("checking for gapless play option");
6324 if (player->pipeline->textbin) {
6325 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6329 attrs = MMPLAYER_GET_ATTRS(player);
6331 LOGE("fail to get attributes.\n");
6335 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6337 /* gapless playback is not supported in case of video at TV profile. */
6338 profile_tv = __mmplayer_check_profile();
6339 if (profile_tv && video) {
6340 LOGW("not support video gapless playback");
6344 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6351 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6352 LOGE("failed to get play count");
6354 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6355 LOGE("failed to get gapless mode");
6357 /* check repeat count in case of audio */
6359 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6360 LOGW("gapless is disabled");
6364 num_of_list = g_list_length(player->uri_info.uri_list);
6366 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6368 if (num_of_list == 0) {
6369 /* audio looping path */
6370 if (count >= REPEAT_COUNT_MIN) {
6371 /* decrease play count */
6372 /* we succeeded to rewind. update play count and then wait for next EOS */
6375 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6377 /* commit attribute */
6378 if (mm_attrs_commit_all(attrs))
6379 LOGE("failed to commit attribute");
6380 } else if (count != REPEAT_COUNT_INFINITELY) {
6381 LOGD("there is no next uri and no repeat");
6385 LOGD("looping cnt %d", count);
6387 /* gapless playback path */
6388 if (!__mmplayer_get_next_uri(player)) {
6389 LOGE("failed to get next uri");
6397 LOGE("unable to play gapless path. EOS will be posted soon");
6402 __mmplayer_initialize_gapless_play(mm_player_t *player)
6408 player->smooth_streaming = FALSE;
6409 player->videodec_linked = 0;
6410 player->audiodec_linked = 0;
6411 player->textsink_linked = 0;
6412 player->is_external_subtitle_present = FALSE;
6413 player->is_external_subtitle_added_now = FALSE;
6414 player->not_supported_codec = MISSING_PLUGIN_NONE;
6415 player->can_support_codec = FOUND_PLUGIN_NONE;
6416 player->pending_seek.is_pending = FALSE;
6417 player->pending_seek.pos = 0;
6418 player->msg_posted = FALSE;
6419 player->has_many_types = FALSE;
6420 player->no_more_pad = FALSE;
6421 player->not_found_demuxer = 0;
6422 player->seek_state = MMPLAYER_SEEK_NONE;
6423 player->is_subtitle_force_drop = FALSE;
6424 player->play_subtitle = FALSE;
6425 player->adjust_subtitle_pos = 0;
6427 player->total_bitrate = 0;
6428 player->total_maximum_bitrate = 0;
6430 __mmplayer_track_initialize(player);
6431 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6433 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6434 player->bitrate[i] = 0;
6435 player->maximum_bitrate[i] = 0;
6438 if (player->v_stream_caps) {
6439 gst_caps_unref(player->v_stream_caps);
6440 player->v_stream_caps = NULL;
6443 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6445 /* clean found parsers */
6446 if (player->parsers) {
6447 GList *parsers = player->parsers;
6448 for (; parsers; parsers = g_list_next(parsers)) {
6449 gchar *name = parsers->data;
6450 MMPLAYER_FREEIF(name);
6452 g_list_free(player->parsers);
6453 player->parsers = NULL;
6456 /* clean found audio decoders */
6457 if (player->audio_decoders) {
6458 GList *a_dec = player->audio_decoders;
6459 for (; a_dec; a_dec = g_list_next(a_dec)) {
6460 gchar *name = a_dec->data;
6461 MMPLAYER_FREEIF(name);
6463 g_list_free(player->audio_decoders);
6464 player->audio_decoders = NULL;
6471 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6473 MMPlayerGstElement *mainbin = NULL;
6474 MMMessageParamType msg_param = {0,};
6475 GstElement *element = NULL;
6476 MMHandleType attrs = 0;
6478 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6482 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6483 LOGE("player is not initialized");
6487 mainbin = player->pipeline->mainbin;
6488 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6490 attrs = MMPLAYER_GET_ATTRS(player);
6492 LOGE("fail to get attributes");
6496 /* Initialize Player values */
6497 __mmplayer_initialize_gapless_play(player);
6499 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6501 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6502 LOGE("failed to parse profile");
6503 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6507 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6508 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6509 LOGE("dash or hls is not supportable");
6510 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6514 element = __mmplayer_gst_create_source(player);
6516 LOGE("no source element was created");
6520 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6521 LOGE("failed to add source element to pipeline");
6522 gst_object_unref(GST_OBJECT(element));
6527 /* take source element */
6528 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6529 mainbin[MMPLAYER_M_SRC].gst = element;
6533 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6534 if (player->streamer == NULL) {
6535 player->streamer = __mm_player_streaming_create();
6536 __mm_player_streaming_initialize(player->streamer);
6539 elem_idx = MMPLAYER_M_TYPEFIND;
6540 element = gst_element_factory_make("typefind", "typefinder");
6541 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6542 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6544 elem_idx = MMPLAYER_M_AUTOPLUG;
6545 element = __mmplayer_gst_make_decodebin(player);
6548 /* check autoplug element is OK */
6550 LOGE("can not create element(%d)", elem_idx);
6554 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6555 LOGE("failed to add sinkbin to pipeline");
6556 gst_object_unref(GST_OBJECT(element));
6561 mainbin[elem_idx].id = elem_idx;
6562 mainbin[elem_idx].gst = element;
6564 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6565 LOGE("Failed to link src - autoplug(or typefind)");
6569 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6570 LOGE("Failed to change state of src element");
6574 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6575 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6576 LOGE("Failed to change state of decodebin");
6580 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6581 LOGE("Failed to change state of src element");
6586 player->gapless.stream_changed = TRUE;
6587 player->gapless.running = TRUE;
6593 MMPLAYER_PLAYBACK_UNLOCK(player);
6595 if (!player->msg_posted) {
6596 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6597 player->msg_posted = TRUE;
6604 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6606 mm_player_selector_t *selector = &player->selector[type];
6607 MMPlayerGstElement *sinkbin = NULL;
6608 enum MainElementID selectorId = MMPLAYER_M_NUM;
6609 enum MainElementID sinkId = MMPLAYER_M_NUM;
6610 GstPad *srcpad = NULL;
6611 GstPad *sinkpad = NULL;
6612 gboolean send_notice = FALSE;
6615 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6617 LOGD("type %d", type);
6620 case MM_PLAYER_TRACK_TYPE_AUDIO:
6621 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6622 sinkId = MMPLAYER_A_BIN;
6623 sinkbin = player->pipeline->audiobin;
6625 case MM_PLAYER_TRACK_TYPE_VIDEO:
6626 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6627 sinkId = MMPLAYER_V_BIN;
6628 sinkbin = player->pipeline->videobin;
6631 case MM_PLAYER_TRACK_TYPE_TEXT:
6632 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6633 sinkId = MMPLAYER_T_BIN;
6634 sinkbin = player->pipeline->textbin;
6637 LOGE("requested type is not supportable");
6642 if (player->pipeline->mainbin[selectorId].gst) {
6645 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6647 if (selector->event_probe_id != 0)
6648 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6649 selector->event_probe_id = 0;
6651 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6652 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6654 if (srcpad && sinkpad) {
6655 /* after getting drained signal there is no data flows, so no need to do pad_block */
6656 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6657 gst_pad_unlink(srcpad, sinkpad);
6659 /* send custom event to sink pad to handle it at video sink */
6661 LOGD("send custom event to sinkpad");
6662 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6663 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6664 gst_pad_send_event(sinkpad, event);
6668 gst_object_unref(sinkpad);
6671 gst_object_unref(srcpad);
6674 LOGD("selector release");
6676 /* release and unref requests pad from the selector */
6677 for (n = 0; n < selector->channels->len; n++) {
6678 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6679 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6681 g_ptr_array_set_size(selector->channels, 0);
6683 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6684 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6686 player->pipeline->mainbin[selectorId].gst = NULL;
6694 __mmplayer_deactivate_old_path(mm_player_t *player)
6697 MMPLAYER_RETURN_IF_FAIL(player);
6699 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6700 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6701 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6702 LOGE("deactivate selector error");
6706 __mmplayer_track_destroy(player);
6707 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6709 if (player->streamer) {
6710 __mm_player_streaming_deinitialize(player->streamer);
6711 __mm_player_streaming_destroy(player->streamer);
6712 player->streamer = NULL;
6715 MMPLAYER_PLAYBACK_LOCK(player);
6716 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6723 if (!player->msg_posted) {
6724 MMMessageParamType msg = {0,};
6727 msg.code = MM_ERROR_PLAYER_INTERNAL;
6728 LOGE("gapless_uri_play> deactivate error");
6730 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6731 player->msg_posted = TRUE;
6736 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6738 int result = MM_ERROR_NONE;
6739 mm_player_t* player = (mm_player_t*) hplayer;
6742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6745 player->http_file_buffering_path = (gchar*)file_path;
6746 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6752 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6754 int result = MM_ERROR_NONE;
6755 mm_player_t* player = (mm_player_t*) hplayer;
6758 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6760 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6761 if (mm_attrs_commit_all(player->attrs)) {
6762 LOGE("failed to commit the original uri.\n");
6763 result = MM_ERROR_PLAYER_INTERNAL;
6765 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6766 LOGE("failed to add the original uri in the uri list.\n");
6773 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6775 mm_player_t* player = (mm_player_t*) hplayer;
6776 guint num_of_list = 0;
6780 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6781 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6783 if (player->pipeline && player->pipeline->textbin) {
6784 LOGE("subtitle path is enabled.\n");
6785 return MM_ERROR_PLAYER_INVALID_STATE;
6788 num_of_list = g_list_length(player->uri_info.uri_list);
6790 if (is_first_path == TRUE) {
6791 if (num_of_list == 0) {
6792 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6793 LOGD("add original path : %s", uri);
6795 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6796 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6798 LOGD("change original path : %s", uri);
6801 MMHandleType attrs = 0;
6802 attrs = MMPLAYER_GET_ATTRS(player);
6804 if (num_of_list == 0) {
6805 char *original_uri = NULL;
6808 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6810 if (!original_uri) {
6811 LOGE("there is no original uri.");
6812 return MM_ERROR_PLAYER_INVALID_STATE;
6815 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6816 player->uri_info.uri_idx = 0;
6818 LOGD("add original path at first : %s(%d)", original_uri);
6822 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6823 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6827 return MM_ERROR_NONE;
6830 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6832 mm_player_t* player = (mm_player_t*) hplayer;
6833 char *next_uri = NULL;
6834 guint num_of_list = 0;
6837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6839 num_of_list = g_list_length(player->uri_info.uri_list);
6841 if (num_of_list > 0) {
6842 gint uri_idx = player->uri_info.uri_idx;
6844 if (uri_idx < num_of_list-1)
6849 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6850 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6852 *uri = g_strdup(next_uri);
6856 return MM_ERROR_NONE;
6860 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6861 GstCaps *caps, gpointer data)
6863 mm_player_t* player = (mm_player_t*)data;
6864 const gchar* klass = NULL;
6865 const gchar* mime = NULL;
6866 gchar* caps_str = NULL;
6868 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6869 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6870 caps_str = gst_caps_to_string(caps);
6872 LOGW("unknown type of caps : %s from %s",
6873 caps_str, GST_ELEMENT_NAME(elem));
6875 MMPLAYER_FREEIF(caps_str);
6877 /* There is no available codec. */
6878 __mmplayer_check_not_supported_codec(player, klass, mime);
6882 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6883 GstCaps * caps, gpointer data)
6885 mm_player_t* player = (mm_player_t*)data;
6886 const char* mime = NULL;
6887 gboolean ret = TRUE;
6889 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6890 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6892 if (g_str_has_prefix(mime, "audio")) {
6893 GstStructure* caps_structure = NULL;
6894 gint samplerate = 0;
6896 gchar *caps_str = NULL;
6898 caps_structure = gst_caps_get_structure(caps, 0);
6899 gst_structure_get_int(caps_structure, "rate", &samplerate);
6900 gst_structure_get_int(caps_structure, "channels", &channels);
6902 if ((channels > 0 && samplerate == 0)) {
6903 LOGD("exclude audio...");
6907 caps_str = gst_caps_to_string(caps);
6908 /* set it directly because not sent by TAG */
6909 if (g_strrstr(caps_str, "mobile-xmf"))
6910 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6911 MMPLAYER_FREEIF(caps_str);
6912 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6913 MMMessageParamType msg_param;
6914 memset(&msg_param, 0, sizeof(MMMessageParamType));
6915 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6916 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6917 LOGD("video file is not supported on this device");
6919 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6920 LOGD("already video linked");
6923 LOGD("found new stream");
6930 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6932 int ret = MM_ERROR_NONE;
6934 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6936 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6937 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6939 LOGD("audio codec type: %d", codec_type);
6940 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6941 /* sw codec will be skipped */
6942 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6943 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6944 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6945 ret = MM_ERROR_PLAYER_INTERNAL;
6949 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6950 /* hw codec will be skipped */
6951 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6952 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6953 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6954 ret = MM_ERROR_PLAYER_INTERNAL;
6959 /* set stream information */
6960 if (!player->audiodec_linked)
6961 __mmplayer_set_audio_attrs(player, caps);
6963 /* update codec info */
6964 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6965 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6966 player->audiodec_linked = 1;
6968 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6970 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6972 LOGD("video codec type: %d", codec_type);
6973 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6974 /* sw codec is skipped */
6975 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6976 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6977 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6978 ret = MM_ERROR_PLAYER_INTERNAL;
6982 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6983 /* hw codec is skipped */
6984 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6985 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6986 ret = MM_ERROR_PLAYER_INTERNAL;
6991 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6992 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6994 /* mark video decoder for acquire */
6995 if (player->video_decoder_resource == NULL) {
6996 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6997 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6998 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6999 &player->video_decoder_resource)
7000 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7001 LOGE("could not mark video_decoder resource for acquire");
7002 ret = MM_ERROR_PLAYER_INTERNAL;
7006 LOGW("video decoder resource is already acquired, skip it.");
7007 ret = MM_ERROR_PLAYER_INTERNAL;
7011 player->interrupted_by_resource = FALSE;
7012 /* acquire resources for video playing */
7013 if (mm_resource_manager_commit(player->resource_manager)
7014 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7015 LOGE("could not acquire resources for video decoding\n");
7016 ret = MM_ERROR_PLAYER_INTERNAL;
7021 /* update codec info */
7022 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7023 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7024 player->videodec_linked = 1;
7032 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7033 GstCaps* caps, GstElementFactory* factory, gpointer data)
7035 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7036 We are defining our own and will be removed when it actually exposed */
7038 GST_AUTOPLUG_SELECT_TRY,
7039 GST_AUTOPLUG_SELECT_EXPOSE,
7040 GST_AUTOPLUG_SELECT_SKIP
7041 } GstAutoplugSelectResult;
7043 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7044 mm_player_t* player = (mm_player_t*)data;
7046 gchar* factory_name = NULL;
7047 gchar* caps_str = NULL;
7048 const gchar* klass = NULL;
7051 factory_name = GST_OBJECT_NAME(factory);
7052 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7053 caps_str = gst_caps_to_string(caps);
7055 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7057 /* store type string */
7058 if (player->type == NULL) {
7059 player->type = gst_caps_to_string(caps);
7060 __mmplayer_update_content_type_info(player);
7063 /* filtering exclude keyword */
7064 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7065 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7066 LOGW("skipping [%s] by exculde keyword [%s]",
7067 factory_name, player->ini.exclude_element_keyword[idx]);
7069 result = GST_AUTOPLUG_SELECT_SKIP;
7074 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7075 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7076 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7077 factory_name, player->ini.unsupported_codec_keyword[idx]);
7078 result = GST_AUTOPLUG_SELECT_SKIP;
7083 /* exclude webm format */
7084 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7085 * because webm format is not supportable.
7086 * If webm is disabled in "autoplug-continue", there is no state change
7087 * failure or error because the decodebin will expose the pad directly.
7088 * It make MSL invoke _prepare_async_callback.
7089 * So, we need to disable webm format in "autoplug-select" */
7090 if (caps_str && strstr(caps_str, "webm")) {
7091 LOGW("webm is not supported");
7092 result = GST_AUTOPLUG_SELECT_SKIP;
7096 /* check factory class for filtering */
7097 /* NOTE : msl don't need to use image plugins.
7098 * So, those plugins should be skipped for error handling.
7100 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7101 LOGD("skipping [%s] by not required\n", factory_name);
7102 result = GST_AUTOPLUG_SELECT_SKIP;
7106 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7107 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7108 // TO CHECK : subtitle if needed, add subparse exception.
7109 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7110 result = GST_AUTOPLUG_SELECT_SKIP;
7114 if (g_strrstr(factory_name, "mpegpsdemux")) {
7115 LOGD("skipping PS container - not support\n");
7116 result = GST_AUTOPLUG_SELECT_SKIP;
7120 if (g_strrstr(factory_name, "mssdemux"))
7121 player->smooth_streaming = TRUE;
7123 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7124 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7127 GstStructure *str = NULL;
7128 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7130 /* don't make video because of not required */
7131 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7132 (!player->set_mode.media_packet_video_stream)) {
7133 LOGD("no need video decoding, expose pad");
7134 result = GST_AUTOPLUG_SELECT_EXPOSE;
7138 /* get w/h for omx state-tune */
7139 /* FIXME: deprecated? */
7140 str = gst_caps_get_structure(caps, 0);
7141 gst_structure_get_int(str, "width", &width);
7144 if (player->v_stream_caps) {
7145 gst_caps_unref(player->v_stream_caps);
7146 player->v_stream_caps = NULL;
7149 player->v_stream_caps = gst_caps_copy(caps);
7150 LOGD("take caps for video state tune");
7151 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7155 if (g_strrstr(klass, "Codec/Decoder")) {
7156 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7157 LOGD("skipping %s codec", factory_name);
7158 result = GST_AUTOPLUG_SELECT_SKIP;
7164 MMPLAYER_FREEIF(caps_str);
7170 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7173 //mm_player_t* player = (mm_player_t*)data;
7174 GstCaps* caps = NULL;
7176 LOGD("[Decodebin2] pad-removed signal\n");
7178 caps = gst_pad_query_caps(new_pad, NULL);
7180 gchar* caps_str = NULL;
7181 caps_str = gst_caps_to_string(caps);
7183 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7185 MMPLAYER_FREEIF(caps_str);
7186 gst_caps_unref(caps);
7191 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7193 mm_player_t* player = (mm_player_t*)data;
7194 GstIterator *iter = NULL;
7195 GValue item = { 0, };
7197 gboolean done = FALSE;
7198 gboolean is_all_drained = TRUE;
7201 MMPLAYER_RETURN_IF_FAIL(player);
7203 LOGD("__mmplayer_gst_decode_drained");
7205 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7206 LOGW("Fail to get cmd lock");
7210 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7211 !__mmplayer_verify_gapless_play_path(player)) {
7212 LOGD("decoding is finished.");
7213 __mmplayer_reset_gapless_state(player);
7214 MMPLAYER_CMD_UNLOCK(player);
7218 player->gapless.reconfigure = TRUE;
7220 /* check decodebin src pads whether they received EOS or not */
7221 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7224 switch (gst_iterator_next(iter, &item)) {
7225 case GST_ITERATOR_OK:
7226 pad = g_value_get_object(&item);
7227 if (pad && !GST_PAD_IS_EOS(pad)) {
7228 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7229 is_all_drained = FALSE;
7232 g_value_reset(&item);
7234 case GST_ITERATOR_RESYNC:
7235 gst_iterator_resync(iter);
7237 case GST_ITERATOR_ERROR:
7238 case GST_ITERATOR_DONE:
7243 g_value_unset(&item);
7244 gst_iterator_free(iter);
7246 if (!is_all_drained) {
7247 LOGD("Wait util the all pads get EOS.");
7248 MMPLAYER_CMD_UNLOCK(player);
7253 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7254 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7256 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7257 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7258 __mmplayer_deactivate_old_path(player);
7259 MMPLAYER_CMD_UNLOCK(player);
7265 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7267 mm_player_t* player = (mm_player_t*)data;
7268 const gchar* klass = NULL;
7269 gchar* factory_name = NULL;
7271 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7272 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7274 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7276 if (__mmplayer_add_dump_buffer_probe(player, element))
7277 LOGD("add buffer probe");
7280 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7281 gchar* selected = NULL;
7282 selected = g_strdup(GST_ELEMENT_NAME(element));
7283 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7287 if (g_strrstr(klass, "Parser")) {
7288 gchar* selected = NULL;
7290 selected = g_strdup(factory_name);
7291 player->parsers = g_list_append(player->parsers, selected);
7294 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7295 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7296 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7298 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7299 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7301 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7302 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7303 "max-video-width", player->adaptive_info.limit.width,
7304 "max-video-height", player->adaptive_info.limit.height, NULL);
7306 } else if (g_strrstr(klass, "Demuxer")) {
7307 //LOGD("plugged element is demuxer. take it");
7308 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7309 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7312 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7313 int surface_type = 0;
7315 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7318 // to support trust-zone only
7319 if (g_strrstr(factory_name, "asfdemux")) {
7320 LOGD("set file-location %s\n", player->profile.uri);
7321 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7322 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7323 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7324 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7325 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7326 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7327 (__mmplayer_is_only_mp3_type(player->type))) {
7328 LOGD("[mpegaudioparse] set streaming pull mode.");
7329 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7331 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7332 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7335 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7336 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7337 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7339 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7340 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7342 if (!MMPLAYER_IS_HTTP_PD(player) &&
7343 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7344 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7345 (MMPLAYER_IS_DASH_STREAMING(player)))) {
7346 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7347 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7348 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7357 __mmplayer_release_misc(mm_player_t* player)
7360 bool cur_mode = player->set_mode.rich_audio;
7363 MMPLAYER_RETURN_IF_FAIL(player);
7365 player->video_stream_cb = NULL;
7366 player->video_stream_cb_user_param = NULL;
7367 player->video_stream_prerolled = FALSE;
7369 player->audio_stream_render_cb = NULL;
7370 player->audio_stream_cb_user_param = NULL;
7371 player->audio_stream_sink_sync = false;
7373 player->video_stream_changed_cb = NULL;
7374 player->video_stream_changed_cb_user_param = NULL;
7376 player->audio_stream_changed_cb = NULL;
7377 player->audio_stream_changed_cb_user_param = NULL;
7379 player->sent_bos = FALSE;
7380 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7382 player->seek_state = MMPLAYER_SEEK_NONE;
7384 player->total_bitrate = 0;
7385 player->total_maximum_bitrate = 0;
7387 player->not_found_demuxer = 0;
7389 player->last_position = 0;
7390 player->duration = 0;
7391 player->http_content_size = 0;
7392 player->not_supported_codec = MISSING_PLUGIN_NONE;
7393 player->can_support_codec = FOUND_PLUGIN_NONE;
7394 player->pending_seek.is_pending = FALSE;
7395 player->pending_seek.pos = 0;
7396 player->msg_posted = FALSE;
7397 player->has_many_types = FALSE;
7398 player->is_subtitle_force_drop = FALSE;
7399 player->play_subtitle = FALSE;
7400 player->adjust_subtitle_pos = 0;
7401 player->last_multiwin_status = FALSE;
7402 player->has_closed_caption = FALSE;
7403 player->set_mode.media_packet_video_stream = false;
7404 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7405 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7407 player->set_mode.rich_audio = cur_mode;
7409 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7410 player->bitrate[i] = 0;
7411 player->maximum_bitrate[i] = 0;
7414 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7416 /* remove media stream cb(appsrc cb) */
7417 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7418 player->media_stream_buffer_status_cb[i] = NULL;
7419 player->media_stream_seek_data_cb[i] = NULL;
7420 player->buffer_cb_user_param[i] = NULL;
7421 player->seek_cb_user_param[i] = NULL;
7423 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7425 /* free memory related to audio effect */
7426 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7428 if (player->adaptive_info.var_list) {
7429 g_list_free_full(player->adaptive_info.var_list, g_free);
7430 player->adaptive_info.var_list = NULL;
7433 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7434 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7435 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7437 /* Reset video360 settings to their defaults in case if the pipeline is to be
7440 player->video360_metadata.is_spherical = -1;
7441 player->is_openal_plugin_used = FALSE;
7443 player->is_content_spherical = FALSE;
7444 player->is_video360_enabled = TRUE;
7445 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7446 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7447 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7448 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7449 player->video360_zoom = 1.0f;
7450 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7451 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7453 player->sound.rg_enable = false;
7455 __mmplayer_initialize_video_roi(player);
7460 __mmplayer_release_misc_post(mm_player_t* player)
7462 char *original_uri = NULL;
7465 /* player->pipeline is already released before. */
7467 MMPLAYER_RETURN_IF_FAIL(player);
7469 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7471 /* clean found parsers */
7472 if (player->parsers) {
7473 GList *parsers = player->parsers;
7474 for (; parsers; parsers = g_list_next(parsers)) {
7475 gchar *name = parsers->data;
7476 MMPLAYER_FREEIF(name);
7478 g_list_free(player->parsers);
7479 player->parsers = NULL;
7482 /* clean found audio decoders */
7483 if (player->audio_decoders) {
7484 GList *a_dec = player->audio_decoders;
7485 for (; a_dec; a_dec = g_list_next(a_dec)) {
7486 gchar *name = a_dec->data;
7487 MMPLAYER_FREEIF(name);
7489 g_list_free(player->audio_decoders);
7490 player->audio_decoders = NULL;
7493 /* clean the uri list except original uri */
7494 if (player->uri_info.uri_list) {
7495 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7497 if (player->attrs) {
7498 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7499 LOGD("restore original uri = %s\n", original_uri);
7501 if (mm_attrs_commit_all(player->attrs))
7502 LOGE("failed to commit the original uri.\n");
7505 GList *uri_list = player->uri_info.uri_list;
7506 for (; uri_list; uri_list = g_list_next(uri_list)) {
7507 gchar *uri = uri_list->data;
7508 MMPLAYER_FREEIF(uri);
7510 g_list_free(player->uri_info.uri_list);
7511 player->uri_info.uri_list = NULL;
7514 /* clear the audio stream buffer list */
7515 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7517 /* clear the video stream bo list */
7518 __mmplayer_video_stream_destroy_bo_list(player);
7519 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7521 if (player->profile.input_mem.buf) {
7522 free(player->profile.input_mem.buf);
7523 player->profile.input_mem.buf = NULL;
7525 player->profile.input_mem.len = 0;
7526 player->profile.input_mem.offset = 0;
7528 player->uri_info.uri_idx = 0;
7533 __mmplayer_check_subtitle(mm_player_t* player)
7535 MMHandleType attrs = 0;
7536 char *subtitle_uri = NULL;
7540 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7542 /* get subtitle attribute */
7543 attrs = MMPLAYER_GET_ATTRS(player);
7547 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7548 if (!subtitle_uri || !strlen(subtitle_uri))
7551 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7552 player->is_external_subtitle_present = TRUE;
7560 __mmplayer_cancel_eos_timer(mm_player_t* player)
7562 MMPLAYER_RETURN_IF_FAIL(player);
7564 if (player->eos_timer) {
7565 LOGD("cancel eos timer");
7566 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7567 player->eos_timer = 0;
7574 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7578 MMPLAYER_RETURN_IF_FAIL(player);
7579 MMPLAYER_RETURN_IF_FAIL(sink);
7581 player->sink_elements =
7582 g_list_append(player->sink_elements, sink);
7588 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7592 MMPLAYER_RETURN_IF_FAIL(player);
7593 MMPLAYER_RETURN_IF_FAIL(sink);
7595 player->sink_elements =
7596 g_list_remove(player->sink_elements, sink);
7602 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7603 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7605 MMPlayerSignalItem* item = NULL;
7608 MMPLAYER_RETURN_IF_FAIL(player);
7610 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7611 LOGE("invalid signal type [%d]", type);
7615 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7617 LOGE("cannot connect signal [%s]", signal);
7622 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7623 player->signals[type] = g_list_append(player->signals[type], item);
7629 /* NOTE : be careful with calling this api. please refer to below glib comment
7630 * glib comment : Note that there is a bug in GObject that makes this function much
7631 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7632 * will no longer be called, but, the signal handler is not currently disconnected.
7633 * If the instance is itself being freed at the same time than this doesn't matter,
7634 * since the signal will automatically be removed, but if instance persists,
7635 * then the signal handler will leak. You should not remove the signal yourself
7636 * because in a future versions of GObject, the handler will automatically be
7639 * It's possible to work around this problem in a way that will continue to work
7640 * with future versions of GObject by checking that the signal handler is still
7641 * connected before disconnected it:
7643 * if (g_signal_handler_is_connected(instance, id))
7644 * g_signal_handler_disconnect(instance, id);
7647 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7649 GList* sig_list = NULL;
7650 MMPlayerSignalItem* item = NULL;
7654 MMPLAYER_RETURN_IF_FAIL(player);
7656 LOGD("release signals type : %d", type);
7658 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7659 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7660 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7661 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7662 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7663 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7667 sig_list = player->signals[type];
7669 for (; sig_list; sig_list = sig_list->next) {
7670 item = sig_list->data;
7672 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7673 if (g_signal_handler_is_connected(item->obj, item->sig))
7674 g_signal_handler_disconnect(item->obj, item->sig);
7677 MMPLAYER_FREEIF(item);
7680 g_list_free(player->signals[type]);
7681 player->signals[type] = NULL;
7688 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7690 mm_player_t* player = 0;
7691 int prev_display_surface_type = 0;
7692 void *prev_display_overlay = NULL;
7696 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7697 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7699 player = MM_PLAYER_CAST(handle);
7701 /* check video sinkbin is created */
7702 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7703 LOGE("Videosink is already created");
7704 return MM_ERROR_NONE;
7707 LOGD("videosink element is not yet ready");
7709 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7710 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7712 return MM_ERROR_INVALID_ARGUMENT;
7715 /* load previous attributes */
7716 if (player->attrs) {
7717 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7718 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7719 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7720 if (prev_display_surface_type == surface_type) {
7721 LOGD("incoming display surface type is same as previous one, do nothing..");
7723 return MM_ERROR_NONE;
7726 LOGE("failed to load attributes");
7728 return MM_ERROR_PLAYER_INTERNAL;
7731 /* videobin is not created yet, so we just set attributes related to display surface */
7732 LOGD("store display attribute for given surface type(%d)", surface_type);
7733 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7734 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7735 if (mm_attrs_commit_all(player->attrs)) {
7736 LOGE("failed to commit attribute");
7738 return MM_ERROR_PLAYER_INTERNAL;
7742 return MM_ERROR_NONE;
7745 /* Note : if silent is true, then subtitle would not be displayed. :*/
7746 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7748 mm_player_t* player = (mm_player_t*) hplayer;
7752 /* check player handle */
7753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7755 player->set_mode.subtitle_off = silent;
7757 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7761 return MM_ERROR_NONE;
7764 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7766 MMPlayerGstElement* mainbin = NULL;
7767 MMPlayerGstElement* textbin = NULL;
7768 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7769 GstState current_state = GST_STATE_VOID_PENDING;
7770 GstState element_state = GST_STATE_VOID_PENDING;
7771 GstState element_pending_state = GST_STATE_VOID_PENDING;
7773 GstEvent *event = NULL;
7774 int result = MM_ERROR_NONE;
7776 GstClock *curr_clock = NULL;
7777 GstClockTime base_time, start_time, curr_time;
7782 /* check player handle */
7783 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7785 player->pipeline->mainbin &&
7786 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7788 mainbin = player->pipeline->mainbin;
7789 textbin = player->pipeline->textbin;
7791 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7793 // sync clock with current pipeline
7794 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7795 curr_time = gst_clock_get_time(curr_clock);
7797 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7798 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7800 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7801 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7803 if (current_state > GST_STATE_READY) {
7804 // sync state with current pipeline
7805 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7806 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7807 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7809 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7810 if (GST_STATE_CHANGE_FAILURE == ret) {
7811 LOGE("fail to state change.\n");
7812 result = MM_ERROR_PLAYER_INTERNAL;
7817 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7818 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7821 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7822 gst_object_unref(curr_clock);
7825 // seek to current position
7826 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7827 result = MM_ERROR_PLAYER_INVALID_STATE;
7828 LOGE("gst_element_query_position failed, invalid state\n");
7832 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7833 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);
7835 __mmplayer_gst_send_event_to_sink(player, event);
7837 result = MM_ERROR_PLAYER_INTERNAL;
7838 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7842 /* sync state with current pipeline */
7843 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7844 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7845 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7847 return MM_ERROR_NONE;
7850 /* release text pipeline resource */
7851 player->textsink_linked = 0;
7853 /* release signal */
7854 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7856 /* release textbin with it's childs */
7857 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7858 MMPLAYER_FREEIF(player->pipeline->textbin);
7859 player->pipeline->textbin = NULL;
7861 /* release subtitle elem */
7862 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7863 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7869 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7871 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7872 GstState current_state = GST_STATE_VOID_PENDING;
7874 MMHandleType attrs = 0;
7875 MMPlayerGstElement* mainbin = NULL;
7876 MMPlayerGstElement* textbin = NULL;
7878 gchar* subtitle_uri = NULL;
7879 int result = MM_ERROR_NONE;
7880 const gchar *charset = NULL;
7884 /* check player handle */
7885 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7887 player->pipeline->mainbin &&
7888 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7889 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7891 mainbin = player->pipeline->mainbin;
7892 textbin = player->pipeline->textbin;
7894 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7895 if (current_state < GST_STATE_READY) {
7896 result = MM_ERROR_PLAYER_INVALID_STATE;
7897 LOGE("Pipeline is not in proper state\n");
7901 attrs = MMPLAYER_GET_ATTRS(player);
7903 LOGE("cannot get content attribute\n");
7904 result = MM_ERROR_PLAYER_INTERNAL;
7908 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7909 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7910 LOGE("subtitle uri is not proper filepath\n");
7911 result = MM_ERROR_PLAYER_INVALID_URI;
7915 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7916 LOGE("failed to get storage info of subtitle path");
7917 result = MM_ERROR_PLAYER_INVALID_URI;
7921 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7922 LOGD("new subtitle file path is [%s]\n", filepath);
7924 if (!strcmp(filepath, subtitle_uri)) {
7925 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7928 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7929 if (mm_attrs_commit_all(player->attrs)) {
7930 LOGE("failed to commit.\n");
7935 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7936 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7937 player->subtitle_language_list = NULL;
7938 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7940 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7941 if (ret != GST_STATE_CHANGE_SUCCESS) {
7942 LOGE("failed to change state of textbin to READY");
7943 result = MM_ERROR_PLAYER_INTERNAL;
7947 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7948 if (ret != GST_STATE_CHANGE_SUCCESS) {
7949 LOGE("failed to change state of subparse to READY");
7950 result = MM_ERROR_PLAYER_INTERNAL;
7954 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7955 if (ret != GST_STATE_CHANGE_SUCCESS) {
7956 LOGE("failed to change state of filesrc to READY");
7957 result = MM_ERROR_PLAYER_INTERNAL;
7961 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7963 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7965 charset = util_get_charset(filepath);
7967 LOGD("detected charset is %s\n", charset);
7968 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7971 result = _mmplayer_sync_subtitle_pipeline(player);
7978 /* API to switch between external subtitles */
7979 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7981 int result = MM_ERROR_NONE;
7982 mm_player_t* player = (mm_player_t*)hplayer;
7987 /* check player handle */
7988 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7990 /* filepath can be null in idle state */
7992 /* check file path */
7993 if ((path = strstr(filepath, "file://")))
7994 result = util_exist_file_path(path + 7);
7996 result = util_exist_file_path(filepath);
7998 if (result != MM_ERROR_NONE) {
7999 LOGE("invalid subtitle path 0x%X", result);
8000 return result; /* file not found or permission denied */
8004 if (!player->pipeline) {
8006 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8007 if (mm_attrs_commit_all(player->attrs)) {
8008 LOGE("failed to commit"); /* subtitle path will not be created */
8009 return MM_ERROR_PLAYER_INTERNAL;
8012 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8013 /* check filepath */
8014 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8016 if (!__mmplayer_check_subtitle(player)) {
8017 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8018 if (mm_attrs_commit_all(player->attrs)) {
8019 LOGE("failed to commit");
8020 return MM_ERROR_PLAYER_INTERNAL;
8023 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8024 LOGE("fail to create text pipeline");
8025 return MM_ERROR_PLAYER_INTERNAL;
8028 result = _mmplayer_sync_subtitle_pipeline(player);
8030 result = __mmplayer_change_external_subtitle_language(player, filepath);
8033 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8034 player->is_external_subtitle_added_now = TRUE;
8036 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8037 if (!player->subtitle_language_list) {
8038 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8039 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8040 LOGW("subtitle language list is not updated yet");
8042 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8050 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8052 int result = MM_ERROR_NONE;
8053 gchar* change_pad_name = NULL;
8054 GstPad* sinkpad = NULL;
8055 MMPlayerGstElement* mainbin = NULL;
8056 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8057 GstCaps* caps = NULL;
8058 gint total_track_num = 0;
8062 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8063 MM_ERROR_PLAYER_NOT_INITIALIZED);
8065 LOGD("Change Track(%d) to %d\n", type, index);
8067 mainbin = player->pipeline->mainbin;
8069 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8070 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8071 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8072 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8074 /* Changing Video Track is not supported. */
8075 LOGE("Track Type Error\n");
8079 if (mainbin[elem_idx].gst == NULL) {
8080 result = MM_ERROR_PLAYER_NO_OP;
8081 LOGD("Req track doesn't exist\n");
8085 total_track_num = player->selector[type].total_track_num;
8086 if (total_track_num <= 0) {
8087 result = MM_ERROR_PLAYER_NO_OP;
8088 LOGD("Language list is not available \n");
8092 if ((index < 0) || (index >= total_track_num)) {
8093 result = MM_ERROR_INVALID_ARGUMENT;
8094 LOGD("Not a proper index : %d \n", index);
8098 /*To get the new pad from the selector*/
8099 change_pad_name = g_strdup_printf("sink_%u", index);
8100 if (change_pad_name == NULL) {
8101 result = MM_ERROR_PLAYER_INTERNAL;
8102 LOGD("Pad does not exists\n");
8106 LOGD("new active pad name: %s\n", change_pad_name);
8108 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8109 if (sinkpad == NULL) {
8110 LOGD("sinkpad is NULL");
8111 result = MM_ERROR_PLAYER_INTERNAL;
8115 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8116 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8118 caps = gst_pad_get_current_caps(sinkpad);
8119 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8122 gst_object_unref(sinkpad);
8124 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8125 __mmplayer_set_audio_attrs(player, caps);
8129 MMPLAYER_FREEIF(change_pad_name);
8133 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8135 int result = MM_ERROR_NONE;
8136 mm_player_t* player = NULL;
8137 MMPlayerGstElement* mainbin = NULL;
8139 gint current_active_index = 0;
8141 GstState current_state = GST_STATE_VOID_PENDING;
8142 GstEvent* event = NULL;
8147 player = (mm_player_t*)hplayer;
8148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8150 if (!player->pipeline) {
8151 LOGE("Track %d pre setting -> %d\n", type, index);
8153 player->selector[type].active_pad_index = index;
8157 mainbin = player->pipeline->mainbin;
8159 current_active_index = player->selector[type].active_pad_index;
8161 /*If index is same as running index no need to change the pad*/
8162 if (current_active_index == index)
8165 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8166 result = MM_ERROR_PLAYER_INVALID_STATE;
8170 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8171 if (current_state < GST_STATE_PAUSED) {
8172 result = MM_ERROR_PLAYER_INVALID_STATE;
8173 LOGW("Pipeline not in porper state\n");
8177 result = __mmplayer_change_selector_pad(player, type, index);
8178 if (result != MM_ERROR_NONE) {
8179 LOGE("change selector pad error\n");
8183 player->selector[type].active_pad_index = index;
8185 if (current_state == GST_STATE_PLAYING) {
8186 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);
8188 __mmplayer_gst_send_event_to_sink(player, event);
8190 result = MM_ERROR_PLAYER_INTERNAL;
8199 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8201 mm_player_t* player = (mm_player_t*) hplayer;
8205 /* check player handle */
8206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8208 *silent = player->set_mode.subtitle_off;
8210 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8214 return MM_ERROR_NONE;
8218 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8221 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8223 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8224 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8228 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8229 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8230 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8231 mm_player_dump_t *dump_s;
8232 dump_s = g_malloc(sizeof(mm_player_dump_t));
8234 if (dump_s == NULL) {
8235 LOGE("malloc fail");
8239 dump_s->dump_element_file = NULL;
8240 dump_s->dump_pad = NULL;
8241 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8243 if (dump_s->dump_pad) {
8244 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8245 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]);
8246 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8247 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);
8248 /* add list for removed buffer probe and close FILE */
8249 player->dump_list = g_list_append(player->dump_list, dump_s);
8250 LOGD("%s sink pad added buffer probe for dump", factory_name);
8255 LOGE("failed to get %s sink pad added", factory_name);
8262 static GstPadProbeReturn
8263 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8265 FILE *dump_data = (FILE *) u_data;
8267 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8268 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8270 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8272 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8274 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8276 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8278 return GST_PAD_PROBE_OK;
8282 __mmplayer_release_dump_list(GList *dump_list)
8285 GList *d_list = dump_list;
8286 for (; d_list; d_list = g_list_next(d_list)) {
8287 mm_player_dump_t *dump_s = d_list->data;
8288 if (dump_s->dump_pad) {
8289 if (dump_s->probe_handle_id)
8290 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8292 if (dump_s->dump_element_file) {
8293 fclose(dump_s->dump_element_file);
8294 dump_s->dump_element_file = NULL;
8296 MMPLAYER_FREEIF(dump_s);
8298 g_list_free(dump_list);
8304 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8306 mm_player_t* player = (mm_player_t*) hplayer;
8310 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8311 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8313 *exist = player->has_closed_caption;
8317 return MM_ERROR_NONE;
8320 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8324 // LOGD("unref internal gst buffer %p", buffer);
8325 gst_buffer_unref((GstBuffer *)buffer);
8331 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8333 mm_player_t* player = (mm_player_t*) hplayer;
8337 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8338 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8340 if (MMPLAYER_IS_HTTP_PD(player))
8341 /* consider the timeout both download pipeline and playback pipeline */
8342 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8343 else if (MMPLAYER_IS_STREAMING(player))
8344 *timeout = player->ini.live_state_change_timeout;
8346 *timeout = player->ini.localplayback_state_change_timeout;
8348 LOGD("timeout = %d\n", *timeout);
8351 return MM_ERROR_NONE;
8354 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8356 mm_player_t* player = (mm_player_t*) hplayer;
8360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8361 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8363 *num = player->video_num_buffers;
8364 *extra_num = player->video_extra_num_buffers;
8366 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8369 return MM_ERROR_NONE;
8373 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8377 MMPLAYER_RETURN_IF_FAIL(player);
8379 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8381 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8382 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8383 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8384 player->storage_info[i].id = -1;
8385 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8387 if (path_type != MMPLAYER_PATH_MAX)
8395 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8397 int ret = MM_ERROR_NONE;
8398 mm_player_t* player = (mm_player_t*)hplayer;
8399 MMMessageParamType msg_param = {0, };
8402 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8404 LOGW("state changed storage %d:%d", id, state);
8406 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8407 return MM_ERROR_NONE;
8409 /* FIXME: text path should be handled seperately. */
8410 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8411 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8412 LOGW("external storage is removed");
8414 if (player->msg_posted == FALSE) {
8415 memset(&msg_param, 0, sizeof(MMMessageParamType));
8416 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8417 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8418 player->msg_posted = TRUE;
8421 /* unrealize the player */
8422 ret = _mmplayer_unrealize(hplayer);
8423 if (ret != MM_ERROR_NONE)
8424 LOGE("failed to unrealize");
8431 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8433 int ret = MM_ERROR_NONE;
8434 mm_player_t* player = (mm_player_t*) hplayer;
8435 int idx = 0, total = 0;
8436 gchar *result = NULL, *tmp = NULL;
8439 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8440 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8442 total = *num = g_list_length(player->adaptive_info.var_list);
8444 LOGW("There is no stream variant info.");
8448 result = g_strdup("");
8449 for (idx = 0 ; idx < total ; idx++) {
8450 VariantData *v_data = NULL;
8451 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8454 gchar data[64] = {0};
8455 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8457 tmp = g_strconcat(result, data, NULL);
8461 LOGW("There is no variant data in %d", idx);
8466 *var_info = (char *)result;
8468 LOGD("variant info %d:%s", *num, *var_info);
8473 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8475 int ret = MM_ERROR_NONE;
8476 mm_player_t* player = (mm_player_t*) hplayer;
8479 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8481 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8483 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8484 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8485 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8487 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8488 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8489 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8490 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8492 /* FIXME: seek to current position for applying new variant limitation */
8500 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8502 int ret = MM_ERROR_NONE;
8503 mm_player_t* player = (mm_player_t*) hplayer;
8506 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8507 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8509 *bandwidth = player->adaptive_info.limit.bandwidth;
8510 *width = player->adaptive_info.limit.width;
8511 *height = player->adaptive_info.limit.height;
8513 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8519 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
8521 int ret = MM_ERROR_NONE;
8522 mm_player_t* player = (mm_player_t*) hplayer;
8525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8527 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8528 LOGW("buffer_ms will not be applied.");
8531 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8533 if (player->streamer == NULL) {
8534 player->streamer = __mm_player_streaming_create();
8535 __mm_player_streaming_initialize(player->streamer);
8539 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8541 if (rebuffer_ms >= 0)
8542 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8549 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8551 int ret = MM_ERROR_NONE;
8552 mm_player_t* player = (mm_player_t*) hplayer;
8555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8556 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8558 if (player->streamer == NULL) {
8559 player->streamer = __mm_player_streaming_create();
8560 __mm_player_streaming_initialize(player->streamer);
8563 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8564 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8566 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8572 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8574 #define IDX_FIRST_SW_CODEC 0
8575 mm_player_t* player = (mm_player_t*) hplayer;
8576 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8577 MMHandleType attrs = 0;
8580 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8582 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8583 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8584 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8586 switch (stream_type) {
8587 case MM_PLAYER_STREAM_TYPE_AUDIO:
8588 /* to support audio codec selection, codec info have to be added in ini file as below.
8589 audio codec element hw = xxxx
8590 audio codec element sw = avdec */
8591 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8592 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8593 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8594 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8595 LOGE("There is no audio codec info for codec_type %d", codec_type);
8596 return MM_ERROR_PLAYER_NO_OP;
8599 case MM_PLAYER_STREAM_TYPE_VIDEO:
8600 /* to support video codec selection, codec info have to be added in ini file as below.
8601 video codec element hw = omx
8602 video codec element sw = avdec */
8603 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8604 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8605 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8606 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8607 LOGE("There is no video codec info for codec_type %d", codec_type);
8608 return MM_ERROR_PLAYER_NO_OP;
8612 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8613 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8617 LOGD("update %s codec_type to %d", attr_name, codec_type);
8619 attrs = MMPLAYER_GET_ATTRS(player);
8620 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8622 if (mm_attrs_commit_all(player->attrs)) {
8623 LOGE("failed to commit codec_type attributes");
8624 return MM_ERROR_PLAYER_INTERNAL;
8628 return MM_ERROR_NONE;
8632 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8634 mm_player_t* player = (mm_player_t*) hplayer;
8635 GstElement* rg_vol_element = NULL;
8639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8641 player->sound.rg_enable = enabled;
8643 /* just hold rgvolume enable value if pipeline is not ready */
8644 if (!player->pipeline || !player->pipeline->audiobin) {
8645 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8646 return MM_ERROR_NONE;
8649 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8651 if (!rg_vol_element) {
8652 LOGD("rgvolume element is not created");
8653 return MM_ERROR_PLAYER_INTERNAL;
8657 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8659 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8663 return MM_ERROR_NONE;
8667 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8669 mm_player_t* player = (mm_player_t*) hplayer;
8670 GstElement* rg_vol_element = NULL;
8671 gboolean enable = FALSE;
8675 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8676 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8678 /* just hold enable_rg value if pipeline is not ready */
8679 if (!player->pipeline || !player->pipeline->audiobin) {
8680 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8681 *enabled = player->sound.rg_enable;
8682 return MM_ERROR_NONE;
8685 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8687 if (!rg_vol_element) {
8688 LOGD("rgvolume element is not created");
8689 return MM_ERROR_PLAYER_INTERNAL;
8692 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8697 return MM_ERROR_NONE;
8701 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8703 mm_player_t* player = (mm_player_t*) hplayer;
8704 MMHandleType attrs = 0;
8705 void *handle = NULL;
8706 int ret = MM_ERROR_NONE;
8710 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8712 attrs = MMPLAYER_GET_ATTRS(player);
8713 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8715 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8717 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8718 return MM_ERROR_PLAYER_INTERNAL;
8721 player->video_roi.scale_x = scale_x;
8722 player->video_roi.scale_y = scale_y;
8723 player->video_roi.scale_width = scale_width;
8724 player->video_roi.scale_height = scale_height;
8726 /* check video sinkbin is created */
8727 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8728 return MM_ERROR_NONE;
8730 if (!gst_video_overlay_set_video_roi_area(
8731 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8732 scale_x, scale_y, scale_width, scale_height))
8733 ret = MM_ERROR_PLAYER_INTERNAL;
8735 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8736 scale_x, scale_y, scale_width, scale_height);
8744 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8746 mm_player_t* player = (mm_player_t*) hplayer;
8747 int ret = MM_ERROR_NONE;
8751 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8752 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8754 *scale_x = player->video_roi.scale_x;
8755 *scale_y = player->video_roi.scale_y;
8756 *scale_width = player->video_roi.scale_width;
8757 *scale_height = player->video_roi.scale_height;
8759 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8760 *scale_x, *scale_y, *scale_width, *scale_height);
8766 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8768 gboolean ret = FALSE;
8769 gint64 dur_nsec = 0;
8770 LOGD("try to update duration");
8772 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8773 player->duration = dur_nsec;
8774 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8778 if (player->duration < 0) {
8779 LOGW("duration is Non-Initialized !!!");
8780 player->duration = 0;
8783 /* update streaming service type */
8784 player->streaming_type = __mmplayer_get_stream_service_type(player);
8786 /* check duration is OK */
8787 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8788 /* FIXIT : find another way to get duration here. */
8789 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8796 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8798 /* update audio params
8799 NOTE : We need original audio params and it can be only obtained from src pad of audio
8800 decoder. Below code only valid when we are not using 'resampler' just before
8801 'audioconverter'. */
8802 GstCaps *caps_a = NULL;
8804 gint samplerate = 0, channels = 0;
8805 GstStructure* p = NULL;
8807 LOGD("try to update audio attrs");
8809 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8810 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8812 pad = gst_element_get_static_pad(
8813 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8816 LOGW("failed to get pad from audiosink");
8820 caps_a = gst_pad_get_current_caps(pad);
8823 LOGW("not ready to get audio caps");
8824 gst_object_unref(pad);
8828 p = gst_caps_get_structure(caps_a, 0);
8830 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8832 gst_structure_get_int(p, "rate", &samplerate);
8833 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8835 gst_structure_get_int(p, "channels", &channels);
8836 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8838 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8840 gst_caps_unref(caps_a);
8841 gst_object_unref(pad);
8847 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8849 LOGD("try to update video attrs");
8851 GstCaps *caps_v = NULL;
8855 GstStructure* p = NULL;
8857 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8858 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8860 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8862 LOGD("no videosink sink pad");
8866 caps_v = gst_pad_get_current_caps(pad);
8867 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8868 if (!caps_v && player->v_stream_caps) {
8869 caps_v = player->v_stream_caps;
8870 gst_caps_ref(caps_v);
8874 LOGD("no negitiated caps from videosink");
8875 gst_object_unref(pad);
8879 p = gst_caps_get_structure(caps_v, 0);
8880 gst_structure_get_int(p, "width", &width);
8881 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8883 gst_structure_get_int(p, "height", &height);
8884 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8886 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8888 SECURE_LOGD("width : %d height : %d", width, height);
8890 gst_caps_unref(caps_v);
8891 gst_object_unref(pad);
8894 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8895 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8902 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8904 gboolean ret = FALSE;
8905 guint64 data_size = 0;
8909 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8910 if (!player->duration)
8913 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8914 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8915 if (stat(path, &sb) == 0)
8916 data_size = (guint64)sb.st_size;
8918 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8919 data_size = player->http_content_size;
8922 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8925 guint64 bitrate = 0;
8926 guint64 msec_dur = 0;
8928 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8930 bitrate = data_size * 8 * 1000 / msec_dur;
8931 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
8932 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8936 LOGD("player duration is less than 0");
8940 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8941 if (player->total_bitrate) {
8942 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8950 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8952 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8953 data->uri_type = uri_type;
8956 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8958 int ret = MM_ERROR_PLAYER_INVALID_URI;
8960 char *buffer = NULL;
8961 char *seperator = strchr(path, ',');
8962 char ext[100] = {0,}, size[100] = {0,};
8965 if ((buffer = strstr(path, "ext="))) {
8966 buffer += strlen("ext=");
8968 if (strlen(buffer)) {
8969 strncpy(ext, buffer, 99);
8971 if ((seperator = strchr(ext, ','))
8972 || (seperator = strchr(ext, ' '))
8973 || (seperator = strchr(ext, '\0'))) {
8974 seperator[0] = '\0';
8979 if ((buffer = strstr(path, "size="))) {
8980 buffer += strlen("size=");
8982 if (strlen(buffer) > 0) {
8983 strncpy(size, buffer, 99);
8985 if ((seperator = strchr(size, ','))
8986 || (seperator = strchr(size, ' '))
8987 || (seperator = strchr(size, '\0'))) {
8988 seperator[0] = '\0';
8991 mem_size = atoi(size);
8996 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8998 if (mem_size && param) {
8999 if (data->input_mem.buf)
9000 free(data->input_mem.buf);
9001 data->input_mem.buf = malloc(mem_size);
9003 if (data->input_mem.buf) {
9004 memcpy(data->input_mem.buf, param, mem_size);
9005 data->input_mem.len = mem_size;
9006 ret = MM_ERROR_NONE;
9008 LOGE("failed to alloc mem %d", mem_size);
9009 ret = MM_ERROR_PLAYER_INTERNAL;
9012 data->input_mem.offset = 0;
9013 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9020 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9022 gchar *location = NULL;
9025 int ret = MM_ERROR_NONE;
9027 if ((path = strstr(uri, "file://"))) {
9028 location = g_filename_from_uri(uri, NULL, &err);
9029 if (!location || (err != NULL)) {
9030 LOGE("Invalid URI '%s' for filesrc: %s", path,
9031 (err != NULL) ? err->message : "unknown error");
9037 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9038 return MM_ERROR_PLAYER_INVALID_URI;
9040 LOGD("path from uri: %s", location);
9043 path = (location != NULL) ? (location) : ((char *)uri);
9046 ret = util_exist_file_path(path);
9048 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9049 if (ret == MM_ERROR_NONE) {
9050 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9051 if (util_is_sdp_file(path)) {
9052 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9053 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9055 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9057 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9058 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9060 LOGE("invalid uri, could not play..\n");
9061 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9070 static MMPlayerVideoStreamDataType*
9071 __mmplayer_create_stream_from_pad(GstPad *pad)
9073 GstCaps *caps = NULL;
9074 GstStructure *structure = NULL;
9075 unsigned int fourcc = 0;
9076 const gchar *string_format = NULL;
9077 MMPlayerVideoStreamDataType *stream = NULL;
9079 MMPixelFormatType format;
9081 caps = gst_pad_get_current_caps(pad);
9083 LOGE("Caps is NULL.");
9087 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9088 structure = gst_caps_get_structure(caps, 0);
9089 gst_structure_get_int(structure, "width", &width);
9090 gst_structure_get_int(structure, "height", &height);
9091 string_format = gst_structure_get_string(structure, "format");
9093 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9094 format = util_get_pixtype(fourcc);
9095 gst_caps_unref(caps);
9098 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9099 LOGE("Wrong condition!!");
9103 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9105 LOGE("failed to alloc mem for video data");
9109 stream->width = width;
9110 stream->height = height;
9111 stream->format = format;
9117 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9119 unsigned int pitch = 0;
9121 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9123 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9124 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9125 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9126 stream->stride[index] = pitch;
9127 stream->elevation[index] = stream->height;
9132 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9134 if (stream->format == MM_PIXEL_FORMAT_I420) {
9135 int ret = TBM_SURFACE_ERROR_NONE;
9136 tbm_surface_h surface;
9137 tbm_surface_info_s info;
9139 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9141 ret = tbm_surface_get_info(surface, &info);
9142 if (ret != TBM_SURFACE_ERROR_NONE) {
9143 tbm_surface_destroy(surface);
9147 tbm_surface_destroy(surface);
9148 stream->stride[0] = info.planes[0].stride;
9149 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9150 stream->stride[1] = info.planes[1].stride;
9151 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9152 stream->stride[2] = info.planes[2].stride;
9153 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9154 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9155 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9156 stream->stride[0] = stream->width * 4;
9157 stream->elevation[0] = stream->height;
9158 stream->bo_size = stream->stride[0] * stream->height;
9160 LOGE("Not support format %d", stream->format);
9168 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9170 tbm_bo_handle thandle;
9172 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9173 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9174 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9178 unsigned char *src = NULL;
9179 unsigned char *dest = NULL;
9180 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9182 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9184 LOGE("fail to gst_memory_map");
9188 if (!mapinfo.data) {
9189 LOGE("data pointer is wrong");
9193 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9194 if (!stream->bo[0]) {
9195 LOGE("Fail to tbm_bo_alloc!!");
9199 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9201 LOGE("thandle pointer is wrong");
9205 if (stream->format == MM_PIXEL_FORMAT_I420) {
9206 src_stride[0] = GST_ROUND_UP_4(stream->width);
9207 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9208 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9209 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9212 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9213 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9215 for (i = 0; i < 3; i++) {
9216 src = mapinfo.data + src_offset[i];
9217 dest = thandle.ptr + dest_offset[i];
9222 for (j = 0; j < stream->height >> k; j++) {
9223 memcpy(dest, src, stream->width>>k);
9224 src += src_stride[i];
9225 dest += stream->stride[i];
9228 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9229 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9231 LOGE("Not support format %d", stream->format);
9235 tbm_bo_unmap(stream->bo[0]);
9236 gst_memory_unmap(mem, &mapinfo);
9242 tbm_bo_unmap(stream->bo[0]);
9245 gst_memory_unmap(mem, &mapinfo);
9251 __mmplayer_set_pause_state(mm_player_t *player)
9253 if (player->sent_bos)
9256 /* rtsp case, get content attrs by GstMessage */
9257 if (MMPLAYER_IS_RTSP_STREAMING(player))
9260 /* it's first time to update all content attrs. */
9261 __mmplayer_update_content_attrs(player, ATTR_ALL);
9265 __mmplayer_set_playing_state(mm_player_t *player)
9267 gchar *audio_codec = NULL;
9269 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9270 /* initialize because auto resume is done well. */
9271 player->resumed_by_rewind = FALSE;
9272 player->playback_rate = 1.0;
9275 if (player->sent_bos)
9278 /* try to get content metadata */
9280 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9281 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9282 * legacy mmfw-player api
9284 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9286 if ((player->cmd == MMPLAYER_COMMAND_START)
9287 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9288 __mmplayer_handle_missed_plugin(player);
9291 /* check audio codec field is set or not
9292 * we can get it from typefinder or codec's caps.
9294 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9296 /* The codec format can't be sent for audio only case like amr, mid etc.
9297 * Because, parser don't make related TAG.
9298 * So, if it's not set yet, fill it with found data.
9301 if (g_strrstr(player->type, "audio/midi"))
9302 audio_codec = "MIDI";
9303 else if (g_strrstr(player->type, "audio/x-amr"))
9304 audio_codec = "AMR";
9305 else if (g_strrstr(player->type, "audio/mpeg")
9306 && !g_strrstr(player->type, "mpegversion= (int)1"))
9307 audio_codec = "AAC";
9309 audio_codec = "unknown";
9311 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9313 if (mm_attrs_commit_all(player->attrs))
9314 LOGE("failed to update attributes\n");
9316 LOGD("set audio codec type with caps\n");