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 gboolean first_track = FALSE;
1079 gboolean caps_ret = TRUE;
1081 enum MainElementID elem_idx = MMPLAYER_M_NUM;
1082 MMPlayerTrackType stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1085 player = (mm_player_t*)data;
1088 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1089 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1091 LOGD("pad-added signal handling");
1093 /* get mimetype from caps */
1094 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1098 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1099 /* LOGD("detected mimetype : %s", name); */
1101 if (strstr(name, "video")) {
1103 gchar *caps_str = NULL;
1105 caps_str = gst_caps_to_string(caps);
1106 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1107 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1108 player->set_mode.video_zc = TRUE;
1110 MMPLAYER_FREEIF(caps_str);
1112 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1113 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1115 LOGD("surface type : %d", stype);
1117 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1118 __mmplayer_gst_create_sinkbin(elem, pad, player);
1122 /* in case of exporting video frame, it requires the 360 video filter.
1123 * it will be handled in _no_more_pads(). */
1124 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.media_packet_video_stream)){
1125 __mmplayer_gst_make_fakesink(player, pad, name);
1129 LOGD("video selector is required");
1130 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1131 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1132 } else if (strstr(name, "audio")) {
1133 gint samplerate = 0;
1136 gst_structure_get_int(str, "rate", &samplerate);
1137 gst_structure_get_int(str, "channels", &channels);
1139 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1140 __mmplayer_gst_create_sinkbin(elem, pad, player);
1144 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1145 __mmplayer_gst_make_fakesink(player, pad, name);
1149 LOGD("audio selector is required");
1150 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1151 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1153 } else if (strstr(name, "text")) {
1154 LOGD("text selector is required");
1155 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1156 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1158 LOGE("invalid caps info");
1162 /* check selector and create it */
1163 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1164 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1169 LOGD("input-selector is already created.");
1173 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1175 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1177 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1178 LOGE("failed to link selector");
1179 gst_object_unref(GST_OBJECT(selector));
1184 LOGD("this track will be activated");
1185 g_object_set(selector, "active-pad", sinkpad, NULL);
1188 __mmplayer_track_update_info(player, stream_type, sinkpad);
1194 gst_caps_unref(caps);
1197 gst_object_unref(GST_OBJECT(sinkpad));
1204 static gboolean __mmplayer_create_sink_path(mm_player_t* player, GstElement* selector, MMPlayerTrackType type)
1206 GstPad* srcpad = NULL;
1209 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1211 LOGD("type %d", type);
1214 LOGD("there is no %d track", type);
1218 srcpad = gst_element_get_static_pad(selector, "src");
1220 LOGE("failed to get srcpad from selector");
1224 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1226 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1228 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1229 if (player->selector[type].block_id) {
1230 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1231 player->selector[type].block_id = 0;
1235 gst_object_unref(GST_OBJECT(srcpad));
1243 static void __mmplayer_set_decode_track_info(mm_player_t* player, MMPlayerTrackType type)
1245 MMHandleType attrs = 0;
1246 gint active_index = 0;
1249 MMPLAYER_RETURN_IF_FAIL(player);
1251 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1253 /* change track to active pad */
1254 active_index = player->selector[type].active_pad_index;
1255 if ((active_index != DEFAULT_TRACK) &&
1256 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1257 LOGW("failed to change %d type track to %d", type, active_index);
1258 player->selector[type].active_pad_index = DEFAULT_TRACK;
1261 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1262 attrs = MMPLAYER_GET_ATTRS(player);
1264 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1265 if (mm_attrs_commit_all(attrs))
1266 LOGW("failed to commit attrs.");
1268 LOGW("cannot get content attribute");
1276 static gboolean __mmplayer_create_audio_sink_path(mm_player_t* player, GstElement* audio_selector)
1279 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1281 if (!audio_selector) {
1282 LOGD("there is no audio track");
1284 /* in case the source is changed, output can be changed. */
1285 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1286 LOGD("remove previous audiobin if it exist");
1288 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1289 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1291 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1292 MMPLAYER_FREEIF(player->pipeline->audiobin);
1295 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1296 __mmplayer_pipeline_complete(NULL, player);
1301 /* apply the audio track information */
1302 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1304 /* create audio sink path */
1305 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1306 LOGE("failed to create audio sink path");
1314 static gboolean __mmplayer_create_text_sink_path(mm_player_t* player, GstElement* text_selector)
1317 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1319 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1320 LOGD("text path is not supproted");
1324 /* apply the text track information */
1325 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1327 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1328 player->has_closed_caption = TRUE;
1330 /* create text decode path */
1331 player->no_more_pad = TRUE;
1333 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1334 LOGE("failed to create text sink path");
1343 __mmplayer_gst_set_queue2_buffering(mm_player_t *player)
1345 #define ESTIMATED_BUFFER_UNIT (1*1024*1024)
1347 gint init_buffering_time = 0;
1348 guint buffer_bytes = 0;
1349 gint64 dur_bytes = 0L;
1352 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1353 player->pipeline->mainbin && player->streamer, FALSE);
1355 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
1356 buffer_bytes = (guint)(init_buffering_time/1000) * ESTIMATED_BUFFER_UNIT;
1358 buffer_bytes = MAX(buffer_bytes, player->streamer->buffer_handle[BUFFER_TYPE_MUXED].buffering_bytes);
1359 LOGD("pre buffer time: %d ms, buffer size : %d", init_buffering_time, buffer_bytes);
1361 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
1363 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1364 LOGE("fail to get duration.");
1366 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1367 * use file information was already set on Q2 when it was created. */
1368 __mm_player_streaming_set_queue2(player->streamer,
1369 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1370 TRUE, /* use_buffering */
1372 init_buffering_time,
1373 1.0, /* low percent */
1374 player->ini.http_buffering_limit, /* high percent */
1375 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1377 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1384 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1386 mm_player_t *player = NULL;
1387 GstElement *video_selector = NULL;
1388 GstElement *audio_selector = NULL;
1389 GstElement *text_selector = NULL;
1392 player = (mm_player_t*) data;
1394 LOGD("no-more-pad signal handling");
1396 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1397 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1398 LOGW("player is shutting down");
1402 if ((!MMPLAYER_IS_HTTP_PD(player)) &&
1403 (MMPLAYER_IS_HTTP_STREAMING(player)) &&
1404 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1405 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1406 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1407 LOGE("failed to set queue2 buffering");
1412 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1413 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1414 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1416 /* create video path followed by video-select */
1417 if (video_selector && !audio_selector && !text_selector)
1418 player->no_more_pad = TRUE;
1420 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1423 /* create audio path followed by audio-select */
1424 if (audio_selector && !text_selector)
1425 player->no_more_pad = TRUE;
1427 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1431 /* create text path followed by text-select */
1432 __mmplayer_create_text_sink_path(player, text_selector);
1435 if (player->gapless.reconfigure) {
1436 player->gapless.reconfigure = FALSE;
1437 MMPLAYER_PLAYBACK_UNLOCK(player);
1444 __mmplayer_gst_add_sinkbin_to_pipeline(mm_player_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1446 gboolean ret = FALSE;
1447 GstElement *pipeline = NULL;
1448 GstPad *sinkpad = NULL;
1451 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1454 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1456 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1458 LOGE("failed to get pad from sinkbin");
1464 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1465 LOGE("failed to link sinkbin for reusing");
1466 goto EXIT; /* exit either pass or fail */
1470 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1471 LOGE("failed to set state(READY) to sinkbin");
1476 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1477 LOGE("failed to add sinkbin to pipeline");
1482 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1483 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1488 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1489 LOGE("failed to set state(PAUSED) to sinkbin");
1498 gst_object_unref(GST_OBJECT(sinkpad));
1505 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1507 mm_player_t *player = NULL;
1508 MMHandleType attrs = 0;
1509 GstCaps *caps = NULL;
1510 gchar *caps_str = NULL;
1511 GstStructure *str = NULL;
1512 const gchar *name = NULL;
1513 GstElement *sinkbin = NULL;
1514 gboolean reusing = FALSE;
1515 gboolean caps_ret = TRUE;
1516 gchar *sink_pad_name = "sink";
1519 player = (mm_player_t*) data;
1522 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1523 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1525 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1529 caps_str = gst_caps_to_string(caps);
1531 /* LOGD("detected mimetype : %s", name); */
1532 if (strstr(name, "audio")) {
1533 if (player->pipeline->audiobin == NULL) {
1534 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1535 LOGE("failed to create audiobin. continuing without audio");
1539 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1540 LOGD("creating audiobin success");
1543 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1544 LOGD("reusing audiobin");
1545 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1547 } else if (strstr(name, "video")) {
1548 /* 1. zero copy is updated at _decode_pad_added()
1549 * 2. NULL surface type is handled in _decode_pad_added() */
1550 LOGD("zero copy %d", player->set_mode.video_zc);
1551 if (player->pipeline->videobin == NULL) {
1552 int surface_type = 0;
1553 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1554 LOGD("display_surface_type (%d)", surface_type);
1556 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1557 LOGD("mark video overlay for acquire");
1558 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1559 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1560 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1561 &player->video_overlay_resource)
1562 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1563 LOGE("could not mark video_overlay resource for acquire");
1568 player->interrupted_by_resource = FALSE;
1570 if (mm_resource_manager_commit(player->resource_manager) !=
1571 MM_RESOURCE_MANAGER_ERROR_NONE) {
1572 LOGE("could not acquire resources for video playing");
1576 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1577 LOGE("failed to create videobin. continuing without video");
1581 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1582 LOGD("creating videosink bin success");
1585 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1586 LOGD("re-using videobin");
1587 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1589 } else if (strstr(name, "text")) {
1590 if (player->pipeline->textbin == NULL) {
1591 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1592 LOGE("failed to create text sink bin. continuing without text");
1596 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1597 player->textsink_linked = 1;
1598 LOGD("creating textsink bin success");
1600 if (!player->textsink_linked) {
1601 LOGD("re-using textbin");
1603 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1604 player->textsink_linked = 1;
1606 /* linked textbin exist which means that the external subtitle path exist already */
1607 LOGW("ignoring internal subtutle since external subtitle is available");
1610 sink_pad_name = "text_sink";
1612 LOGW("unknown mime type %s, ignoring it", name);
1616 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1619 LOGD("[handle: %p] success to create and link sink bin", player);
1621 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1622 * streaming task. if the task blocked, then buffer will not flow to the next element
1623 *(autoplugging element). so this is special hack for streaming. please try to remove it
1625 /* dec stream count. we can remove fakesink if it's zero */
1626 if (player->num_dynamic_pad)
1627 player->num_dynamic_pad--;
1629 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1631 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1632 __mmplayer_pipeline_complete(NULL, player);
1636 MMPLAYER_FREEIF(caps_str);
1639 gst_caps_unref(caps);
1641 /* flusing out new attributes */
1642 if (mm_attrs_commit_all(attrs))
1643 LOGE("failed to comit attributes");
1649 __mmplayer_get_property_value_for_rotation(mm_player_t* player, int display_angle, int orientation, int *value)
1651 int required_angle = 0; /* Angle required for straight view */
1652 int rotation_angle = 0;
1654 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1655 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1657 /* Counter clockwise */
1658 switch (orientation) {
1663 required_angle = 270;
1666 required_angle = 180;
1669 required_angle = 90;
1673 rotation_angle = display_angle + required_angle;
1674 if (rotation_angle >= 360)
1675 rotation_angle -= 360;
1677 /* chech if supported or not */
1678 if (rotation_angle % 90) {
1679 LOGD("not supported rotation angle = %d", rotation_angle);
1683 switch (rotation_angle) {
1685 *value = MM_DISPLAY_ROTATION_NONE;
1688 *value = MM_DISPLAY_ROTATION_90;
1691 *value = MM_DISPLAY_ROTATION_180;
1694 *value = MM_DISPLAY_ROTATION_270;
1698 LOGD("setting rotation property value : %d", value);
1704 __mmplayer_video_param_check_video_sink_bin(mm_player_t* player)
1706 /* check video sinkbin is created */
1707 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1709 player->pipeline->videobin &&
1710 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1711 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1712 MM_ERROR_PLAYER_NOT_INITIALIZED);
1714 return MM_ERROR_NONE;
1718 __mmplayer_get_video_angle(mm_player_t* player, int *display_angle, int *orientation)
1720 int display_rotation = 0;
1721 gchar *org_orient = NULL;
1722 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1725 LOGE("cannot get content attribute");
1726 return MM_ERROR_PLAYER_INTERNAL;
1729 if (display_angle) {
1730 /* update user roation */
1731 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1733 /* Counter clockwise */
1734 switch (display_rotation) {
1735 case MM_DISPLAY_ROTATION_NONE:
1738 case MM_DISPLAY_ROTATION_90:
1739 *display_angle = 90;
1741 case MM_DISPLAY_ROTATION_180:
1742 *display_angle = 180;
1744 case MM_DISPLAY_ROTATION_270:
1745 *display_angle = 270;
1748 LOGW("wrong angle type : %d", display_rotation);
1751 LOGD("check user angle: %d", *display_angle);
1755 /* Counter clockwise */
1756 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1759 if (!strcmp(org_orient, "rotate-90"))
1761 else if (!strcmp(org_orient, "rotate-180"))
1763 else if (!strcmp(org_orient, "rotate-270"))
1766 LOGD("original rotation is %s", org_orient);
1768 LOGD("content_video_orientation get fail");
1771 LOGD("check orientation: %d", *orientation);
1774 return MM_ERROR_NONE;
1778 __mmplayer_video_param_set_display_rotation(mm_player_t* player)
1780 int rotation_value = 0;
1781 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1782 int display_angle = 0;
1785 /* check video sinkbin is created */
1786 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1789 __mmplayer_get_video_angle(player, &display_angle, &orientations);
1791 /* get rotation value to set */
1792 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1793 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1794 LOGD("set video param : rotate %d", rotation_value);
1798 __mmplayer_video_param_set_display_visible(mm_player_t* player)
1800 MMHandleType attrs = 0;
1804 /* check video sinkbin is created */
1805 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1808 attrs = MMPLAYER_GET_ATTRS(player);
1809 MMPLAYER_RETURN_IF_FAIL(attrs);
1811 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1812 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1813 LOGD("set video param : visible %d", visible);
1817 __mmplayer_video_param_set_display_method(mm_player_t* player)
1819 MMHandleType attrs = 0;
1820 int display_method = 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_method", &display_method);
1831 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1832 LOGD("set video param : method %d", display_method);
1835 __mmplayer_video_param_set_video_roi_area(mm_player_t* player)
1837 MMHandleType attrs = 0;
1838 void *handle = NULL;
1841 /* check video sinkbin is created */
1842 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1843 LOGW("There is no video sink");
1847 attrs = MMPLAYER_GET_ATTRS(player);
1848 MMPLAYER_RETURN_IF_FAIL(attrs);
1849 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1851 gst_video_overlay_set_video_roi_area(
1852 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1853 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1854 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1855 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1860 __mmplayer_video_param_set_roi_area(mm_player_t* player)
1862 MMHandleType attrs = 0;
1863 void *handle = NULL;
1867 int win_roi_width = 0;
1868 int win_roi_height = 0;
1871 /* check video sinkbin is created */
1872 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1873 LOGW("There is no video sink");
1877 attrs = MMPLAYER_GET_ATTRS(player);
1878 MMPLAYER_RETURN_IF_FAIL(attrs);
1880 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1883 /* It should be set after setting window */
1884 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1885 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1886 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1887 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1889 /* After setting window handle, set display roi area */
1890 gst_video_overlay_set_display_roi_area(
1891 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1892 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1893 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1894 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1898 __mmplayer_video_param_set_display_overlay(mm_player_t* player)
1900 MMHandleType attrs = 0;
1901 void *handle = NULL;
1903 /* check video sinkbin is created */
1904 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1907 attrs = MMPLAYER_GET_ATTRS(player);
1908 MMPLAYER_RETURN_IF_FAIL(attrs);
1910 /* common case if using overlay surface */
1911 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1914 /* default is using wl_surface_id */
1915 unsigned int wl_surface_id = 0;
1916 wl_surface_id = *(int*)handle;
1917 LOGD("set video param : wl_surface_id %d %p", wl_surface_id, *(int*)handle);
1918 gst_video_overlay_set_wl_window_wl_surface_id(
1919 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1922 /* FIXIT : is it error case? */
1923 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1928 __mmplayer_update_wayland_videosink_video_param(mm_player_t* player, char *param_name)
1930 bool update_all_param = FALSE;
1933 /* check video sinkbin is created */
1934 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1935 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1937 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1938 LOGE("can not find tizenwlsink");
1939 return MM_ERROR_PLAYER_INTERNAL;
1942 LOGD("param_name : %s", param_name);
1943 if (!g_strcmp0(param_name, "update_all_param"))
1944 update_all_param = TRUE;
1946 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1947 __mmplayer_video_param_set_display_overlay(player);
1948 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1949 __mmplayer_video_param_set_display_method(player);
1950 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1951 __mmplayer_video_param_set_display_visible(player);
1952 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1953 __mmplayer_video_param_set_display_rotation(player);
1954 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1955 __mmplayer_video_param_set_roi_area(player);
1956 if (update_all_param)
1957 __mmplayer_video_param_set_video_roi_area(player);
1959 return MM_ERROR_NONE;
1963 _mmplayer_update_video_param(mm_player_t* player, char *param_name)
1965 MMHandleType attrs = 0;
1966 int surface_type = 0;
1967 int ret = MM_ERROR_NONE;
1971 /* check video sinkbin is created */
1972 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1973 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1975 attrs = MMPLAYER_GET_ATTRS(player);
1977 LOGE("cannot get content attribute");
1978 return MM_ERROR_PLAYER_INTERNAL;
1980 LOGD("param_name : %s", param_name);
1982 /* update display surface */
1983 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1984 LOGD("check display surface type attribute: %d", surface_type);
1986 /* configuring display */
1987 switch (surface_type) {
1988 case MM_DISPLAY_SURFACE_OVERLAY:
1990 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1991 if (ret != MM_ERROR_NONE)
1999 return MM_ERROR_NONE;
2003 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2005 gboolean disable_overlay = FALSE;
2006 mm_player_t* player = (mm_player_t*) hplayer;
2007 int ret = MM_ERROR_NONE;
2010 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2011 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2012 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2013 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2015 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2016 LOGW("Display control is not supported");
2017 return MM_ERROR_PLAYER_INTERNAL;
2020 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2022 if (audio_only == (bool)disable_overlay) {
2023 LOGE("It's the same with current setting: (%d)", audio_only);
2024 return MM_ERROR_NONE;
2028 LOGE("disable overlay");
2029 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2031 /* release overlay resource */
2032 if (player->video_overlay_resource != NULL) {
2033 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2034 player->video_overlay_resource);
2035 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2036 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
2039 player->video_overlay_resource = NULL;
2042 ret = mm_resource_manager_commit(player->resource_manager);
2043 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2044 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)\n", ret);
2048 /* mark video overlay for acquire */
2049 if (player->video_overlay_resource == NULL) {
2050 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2051 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2052 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2053 &player->video_overlay_resource);
2054 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2055 LOGE("could not prepare for video_overlay resource\n");
2060 player->interrupted_by_resource = FALSE;
2061 /* acquire resources for video overlay */
2062 ret = mm_resource_manager_commit(player->resource_manager);
2063 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2064 LOGE("could not acquire resources for video playing\n");
2068 LOGD("enable overlay");
2069 __mmplayer_video_param_set_display_overlay(player);
2070 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2075 return MM_ERROR_NONE;
2079 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2081 mm_player_t* player = (mm_player_t*) hplayer;
2082 gboolean disable_overlay = FALSE;
2086 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2087 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2088 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2089 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2090 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2092 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2093 LOGW("Display control is not supported");
2094 return MM_ERROR_PLAYER_INTERNAL;
2097 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2099 *paudio_only = (bool)(disable_overlay);
2101 LOGD("audio_only : %d", *paudio_only);
2105 return MM_ERROR_NONE;
2109 __mmplayer_gst_element_link_bucket(GList* element_bucket)
2111 GList* bucket = element_bucket;
2112 MMPlayerGstElement* element = NULL;
2113 MMPlayerGstElement* prv_element = NULL;
2114 gint successful_link_count = 0;
2118 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2120 prv_element = (MMPlayerGstElement*)bucket->data;
2121 bucket = bucket->next;
2123 for (; bucket; bucket = bucket->next) {
2124 element = (MMPlayerGstElement*)bucket->data;
2126 if (element && element->gst) {
2127 if (prv_element && prv_element->gst) {
2128 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2129 LOGD("linking [%s] to [%s] success\n",
2130 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2131 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2132 successful_link_count++;
2134 LOGD("linking [%s] to [%s] failed\n",
2135 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2136 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2142 prv_element = element;
2147 return successful_link_count;
2151 __mmplayer_gst_element_add_bucket_to_bin(GstBin* bin, GList* element_bucket)
2153 GList* bucket = element_bucket;
2154 MMPlayerGstElement* element = NULL;
2155 int successful_add_count = 0;
2159 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2160 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2162 for (; bucket; bucket = bucket->next) {
2163 element = (MMPlayerGstElement*)bucket->data;
2165 if (element && element->gst) {
2166 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2167 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed\n",
2168 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2169 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2172 successful_add_count++;
2178 return successful_add_count;
2181 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mm_player_t *player = (mm_player_t*) data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2218 if (player->video_stream_changed_cb) {
2219 LOGE("call the video stream changed cb");
2220 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2223 LOGW("invalid caps info");
2228 gst_caps_unref(caps);
2238 * This function is to create audio pipeline for playing.
2240 * @param player [in] handle of player
2242 * @return This function returns zero on success.
2244 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2246 /* macro for code readability. just for sinkbin-creation functions */
2247 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2249 x_bin[x_id].id = x_id;\
2250 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2251 if (!x_bin[x_id].gst) {\
2252 LOGE("failed to create %s \n", x_factory);\
2255 if (x_player->ini.set_dump_element_flag)\
2256 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2259 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2263 __mmplayer_audio_stream_clear_buffer(mm_player_t* player, gboolean send_all)
2268 MMPLAYER_RETURN_IF_FAIL(player);
2270 if (player->audio_stream_buff_list) {
2271 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2272 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2275 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2276 __mmplayer_audio_stream_send_data(player, tmp);
2279 g_free(tmp->pcm_data);
2283 g_list_free(player->audio_stream_buff_list);
2284 player->audio_stream_buff_list = NULL;
2291 __mmplayer_audio_stream_send_data(mm_player_t* player, mm_player_audio_stream_buff_t *a_buffer)
2293 MMPlayerAudioStreamDataType audio_stream = { 0, };
2296 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2298 audio_stream.bitrate = a_buffer->bitrate;
2299 audio_stream.channel = a_buffer->channel;
2300 audio_stream.depth = a_buffer->depth;
2301 audio_stream.is_little_endian = a_buffer->is_little_endian;
2302 audio_stream.channel_mask = a_buffer->channel_mask;
2303 audio_stream.data_size = a_buffer->data_size;
2304 audio_stream.data = a_buffer->pcm_data;
2306 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_stream_cb_user_param); */
2307 player->audio_stream_render_cb(&audio_stream, player->audio_stream_cb_user_param);
2313 __mmplayer_audio_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
2315 mm_player_t* player = (mm_player_t*) data;
2320 gint endianness = 0;
2321 guint64 channel_mask = 0;
2322 void *a_data = NULL;
2324 mm_player_audio_stream_buff_t *a_buffer = NULL;
2325 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2329 MMPLAYER_RETURN_IF_FAIL(player && player->audio_stream_render_cb);
2331 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2332 a_data = mapinfo.data;
2333 a_size = mapinfo.size;
2335 GstCaps *caps = gst_pad_get_current_caps(pad);
2336 GstStructure *structure = gst_caps_get_structure(caps, 0);
2338 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2339 gst_structure_get_int(structure, "rate", &rate);
2340 gst_structure_get_int(structure, "channels", &channel);
2341 gst_structure_get_int(structure, "depth", &depth);
2342 gst_structure_get_int(structure, "endianness", &endianness);
2343 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2344 gst_caps_unref(GST_CAPS(caps));
2346 /* In case of the sync is false, use buffer list. *
2347 * The num of buffer list depends on the num of audio channels */
2348 if (player->audio_stream_buff_list) {
2349 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2350 mm_player_audio_stream_buff_t *tmp = (mm_player_audio_stream_buff_t *)l->data;
2352 if (channel_mask == tmp->channel_mask) {
2353 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2354 if (tmp->data_size + a_size < tmp->buff_size) {
2355 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2356 tmp->data_size += a_size;
2358 /* send data to client */
2359 __mmplayer_audio_stream_send_data(player, tmp);
2361 if (a_size > tmp->buff_size) {
2362 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2363 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2364 if (tmp->pcm_data == NULL) {
2365 LOGE("failed to realloc data.");
2368 tmp->buff_size = a_size;
2370 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2371 memcpy(tmp->pcm_data, a_data, a_size);
2372 tmp->data_size = a_size;
2377 LOGE("data is empty in list.");
2383 /* create new audio stream data */
2384 a_buffer = (mm_player_audio_stream_buff_t*)g_malloc0(sizeof(mm_player_audio_stream_buff_t));
2385 if (a_buffer == NULL) {
2386 LOGE("failed to alloc data.");
2389 a_buffer->bitrate = rate;
2390 a_buffer->channel = channel;
2391 a_buffer->depth = depth;
2392 a_buffer->is_little_endian = (endianness == 1234 ? 1 : 0);
2393 a_buffer->channel_mask = channel_mask;
2394 a_buffer->data_size = a_size;
2396 if (!player->audio_stream_sink_sync) {
2397 /* If sync is FALSE, use buffer list to reduce the IPC. */
2398 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2399 a_buffer->pcm_data = g_malloc(a_buffer->buff_size);
2400 if (a_buffer->pcm_data == NULL) {
2401 LOGE("failed to alloc data.");
2405 memcpy(a_buffer->pcm_data, a_data, a_size);
2406 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2407 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2409 /* If sync is TRUE, send data directly. */
2410 a_buffer->pcm_data = a_data;
2411 __mmplayer_audio_stream_send_data(player, a_buffer);
2416 gst_buffer_unmap(buffer, &mapinfo);
2421 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2423 mm_player_t* player = (mm_player_t*)data;
2424 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
2425 GstPad* sinkpad = NULL;
2426 GstElement *queue = NULL, *sink = NULL;
2429 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2431 queue = gst_element_factory_make("queue", NULL);
2432 if (queue == NULL) {
2433 LOGD("fail make queue\n");
2437 sink = gst_element_factory_make("fakesink", NULL);
2439 LOGD("fail make fakesink\n");
2443 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2445 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2446 LOGW("failed to link queue & sink\n");
2450 sinkpad = gst_element_get_static_pad(queue, "sink");
2452 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2453 LOGW("failed to link [%s:%s] to queue\n", GST_DEBUG_PAD_NAME(pad));
2457 LOGE("player->audio_stream_sink_sync: %d\n", player->audio_stream_sink_sync);
2459 gst_object_unref(sinkpad);
2460 g_object_set(sink, "sync", player->audio_stream_sink_sync, NULL);
2461 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2463 gst_element_set_state(sink, GST_STATE_PAUSED);
2464 gst_element_set_state(queue, GST_STATE_PAUSED);
2466 __mmplayer_add_signal_connection(player,
2468 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2470 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2477 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR\n");
2479 gst_object_unref(GST_OBJECT(queue));
2483 gst_object_unref(GST_OBJECT(sink));
2487 gst_object_unref(GST_OBJECT(sinkpad));
2494 void __mmplayer_gst_set_pulsesink_property(mm_player_t* player, MMHandleType attrs)
2496 #define MAX_PROPS_LEN 128
2497 gint latency_mode = 0;
2498 gchar *stream_type = NULL;
2499 gchar *latency = NULL;
2501 gchar stream_props[MAX_PROPS_LEN] = {0,};
2502 GstStructure *props = NULL;
2505 * It should be set after player creation through attribute.
2506 * But, it can not be changed during playing.
2509 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2511 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2512 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2515 LOGE("stream_type is null.");
2517 if (player->sound.focus_id)
2518 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d, media.focus_id=%d",
2519 stream_type, stream_id, player->sound.focus_id);
2521 snprintf(stream_props, sizeof(stream_props)-1, "props,media.role=%s, media.parent_id=%d",
2522 stream_type, stream_id);
2523 props = gst_structure_from_string(stream_props, NULL);
2524 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2525 LOGI("stream_type[%s], stream_id[%d], focus_id[%d], result[%s].",
2526 stream_type, stream_id, player->sound.focus_id, stream_props);
2527 gst_structure_free(props);
2530 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2532 switch (latency_mode) {
2533 case AUDIO_LATENCY_MODE_LOW:
2534 latency = g_strndup("low", 3);
2536 case AUDIO_LATENCY_MODE_MID:
2537 latency = g_strndup("mid", 3);
2539 case AUDIO_LATENCY_MODE_HIGH:
2540 latency = g_strndup("high", 4);
2544 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2548 LOGD("audiosink property - latency=%s", latency);
2555 void __mmplayer_gst_set_openalsink_property(mm_player_t* player)
2557 MMPlayerGstElement *audiobin = NULL;
2560 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2562 audiobin = player->pipeline->audiobin;
2564 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2565 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2566 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2568 if (player->video360_yaw_radians <= M_PI &&
2569 player->video360_yaw_radians >= -M_PI &&
2570 player->video360_pitch_radians <= M_PI_2 &&
2571 player->video360_pitch_radians >= -M_PI_2) {
2572 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2573 "source-orientation-y", (int) (player->video360_yaw_radians * 180.0 / M_PI),
2574 "source-orientation-x", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
2575 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2576 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2577 "source-orientation-y", player->video360_metadata.init_view_heading,
2578 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2585 __mmplayer_gst_fill_audio_bucket(mm_player_t *player, GList **bucket)
2587 MMPlayerGstElement *audiobin = NULL;
2588 MMHandleType attrs = 0;
2589 GList *element_bucket = NULL;
2590 GstCaps *acaps = NULL;
2591 GstPad *sink_pad = NULL;
2594 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2595 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2597 audiobin = player->pipeline->audiobin;
2598 attrs = MMPLAYER_GET_ATTRS(player);
2601 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2603 /* replaygain volume */
2604 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2605 if (player->sound.rg_enable)
2606 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2608 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2611 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2613 if (player->audio_stream_render_cb) { /* pcm extraction only, no sound output */
2614 gchar *dst_format = NULL;
2616 int dst_samplerate = 0;
2617 int dst_channels = 0;
2618 GstCaps *caps = NULL;
2619 char *caps_str = NULL;
2621 /* get conf. values */
2622 mm_attrs_multiple_get(player->attrs, NULL,
2623 "pcm_audioformat", &dst_format, &dst_len,
2624 "pcm_extraction_samplerate", &dst_samplerate,
2625 "pcm_extraction_channels", &dst_channels,
2628 LOGD("pcm info - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2632 caps = gst_caps_new_simple("audio/x-raw",
2633 "format", G_TYPE_STRING, dst_format,
2634 "rate", G_TYPE_INT, dst_samplerate,
2635 "channels", G_TYPE_INT, dst_channels,
2638 caps_str = gst_caps_to_string(caps);
2639 LOGD("new caps : %s", caps_str);
2641 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2644 gst_caps_unref(caps);
2645 MMPLAYER_FREEIF(caps_str);
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2651 /* raw pad handling signal, audiosink will be added after getting signal */
2652 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2653 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2657 /* normal playback */
2660 /* for logical volume control */
2661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2664 if (player->sound.mute) {
2665 LOGD("mute enabled");
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2669 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2671 /* audio effect element. if audio effect is enabled */
2672 if ((strcmp(player->ini.audioeffect_element, ""))
2674 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2675 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2677 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2679 if ((!player->bypass_audio_effect)
2680 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2681 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2682 if (!_mmplayer_audio_effect_custom_apply(player))
2683 LOGI("apply audio effect(custom) setting success");
2687 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2688 && (player->set_mode.rich_audio))
2689 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2692 /* create audio sink */
2693 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2694 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2695 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2697 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2698 if (player->is_360_feature_enabled &&
2699 player->is_content_spherical &&
2701 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2702 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2703 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2705 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2707 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2710 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2712 gst_caps_unref(acaps);
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2716 player->is_openal_plugin_used = TRUE;
2718 if (player->is_360_feature_enabled && player->is_content_spherical)
2719 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2720 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2723 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2724 (player->videodec_linked && player->ini.use_system_clock)) {
2725 LOGD("system clock will be used.");
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2729 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2730 __mmplayer_gst_set_pulsesink_property(player, attrs);
2731 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2732 __mmplayer_gst_set_openalsink_property(player);
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2736 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2738 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2739 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2740 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2741 gst_object_unref(GST_OBJECT(sink_pad));
2743 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2746 *bucket = element_bucket;
2749 return MM_ERROR_NONE;
2752 g_list_free(element_bucket);
2756 return MM_ERROR_PLAYER_INTERNAL;
2760 __mmplayer_gst_create_audio_sink_bin(mm_player_t* player)
2762 MMPlayerGstElement *first_element = NULL;
2763 MMPlayerGstElement *audiobin = NULL;
2765 GstPad *ghostpad = NULL;
2766 GList *element_bucket = NULL;
2770 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2773 audiobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_A_NUM);
2775 LOGE("failed to allocate memory for audiobin");
2776 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2780 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2781 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2782 if (!audiobin[MMPLAYER_A_BIN].gst) {
2783 LOGE("failed to create audiobin");
2788 player->pipeline->audiobin = audiobin;
2790 /* create audio filters and audiosink */
2791 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2794 /* adding created elements to bin */
2795 LOGD("adding created elements to bin");
2796 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2799 /* linking elements in the bucket by added order. */
2800 LOGD("Linking elements in the bucket by added order.");
2801 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2804 /* get first element's sinkpad for creating ghostpad */
2805 first_element = (MMPlayerGstElement *)element_bucket->data;
2806 if (!first_element) {
2807 LOGE("failed to get first elem");
2811 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2813 LOGE("failed to get pad from first element of audiobin");
2817 ghostpad = gst_ghost_pad_new("sink", pad);
2819 LOGE("failed to create ghostpad");
2823 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2824 LOGE("failed to add ghostpad to audiobin");
2828 gst_object_unref(pad);
2830 g_list_free(element_bucket);
2833 return MM_ERROR_NONE;
2836 LOGD("ERROR : releasing audiobin");
2839 gst_object_unref(GST_OBJECT(pad));
2842 gst_object_unref(GST_OBJECT(ghostpad));
2845 g_list_free(element_bucket);
2847 /* release element which are not added to bin */
2848 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2849 /* NOTE : skip bin */
2850 if (audiobin[i].gst) {
2851 GstObject* parent = NULL;
2852 parent = gst_element_get_parent(audiobin[i].gst);
2855 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2856 audiobin[i].gst = NULL;
2858 gst_object_unref(GST_OBJECT(parent));
2862 /* release audiobin with it's childs */
2863 if (audiobin[MMPLAYER_A_BIN].gst)
2864 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2866 MMPLAYER_FREEIF(audiobin);
2868 player->pipeline->audiobin = NULL;
2870 return MM_ERROR_PLAYER_INTERNAL;
2873 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar* format_name)
2875 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2878 int _mmplayer_video_stream_release_bo(mm_player_t* player, void* bo)
2880 int ret = MM_ERROR_NONE;
2882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2883 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2885 MMPLAYER_VIDEO_BO_LOCK(player);
2887 if (player->video_bo_list) {
2888 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2889 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2890 if (tmp && tmp->bo == bo) {
2892 LOGD("release bo %p", bo);
2893 tbm_bo_unref(tmp->bo);
2894 MMPLAYER_VIDEO_BO_UNLOCK(player);
2895 MMPLAYER_VIDEO_BO_SIGNAL(player);
2900 /* hw codec is running or the list was reset for DRC. */
2901 LOGW("there is no bo list.");
2903 MMPLAYER_VIDEO_BO_UNLOCK(player);
2905 LOGW("failed to find bo %p", bo);
2910 __mmplayer_video_stream_destroy_bo_list(mm_player_t* player)
2915 MMPLAYER_RETURN_IF_FAIL(player);
2917 MMPLAYER_VIDEO_BO_LOCK(player);
2918 if (player->video_bo_list) {
2919 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2920 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2921 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
2924 tbm_bo_unref(tmp->bo);
2928 g_list_free(player->video_bo_list);
2929 player->video_bo_list = NULL;
2931 player->video_bo_size = 0;
2932 MMPLAYER_VIDEO_BO_UNLOCK(player);
2939 __mmplayer_video_stream_get_bo(mm_player_t* player, int size)
2942 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
2943 gboolean ret = TRUE;
2945 /* check DRC, if it is, destroy the prev bo list to create again */
2946 if (player->video_bo_size != size) {
2947 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
2948 __mmplayer_video_stream_destroy_bo_list(player);
2949 player->video_bo_size = size;
2952 MMPLAYER_VIDEO_BO_LOCK(player);
2954 if ((!player->video_bo_list) ||
2955 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
2957 /* create bo list */
2959 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
2961 if (player->video_bo_list) {
2962 /* if bo list did not created all, try it again. */
2963 idx = g_list_length(player->video_bo_list);
2964 LOGD("bo list exist(len: %d)", idx);
2967 for (; idx < player->ini.num_of_video_bo; idx++) {
2968 mm_player_video_bo_info_t* bo_info = g_new(mm_player_video_bo_info_t, 1);
2970 LOGE("Fail to alloc bo_info.");
2973 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
2975 LOGE("Fail to tbm_bo_alloc.");
2979 bo_info->used = FALSE;
2980 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
2983 /* update video num buffers */
2984 player->video_num_buffers = idx;
2985 if (idx == player->ini.num_of_video_bo)
2986 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
2989 MMPLAYER_VIDEO_BO_UNLOCK(player);
2993 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
2997 /* get bo from list*/
2998 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2999 mm_player_video_bo_info_t* tmp = (mm_player_video_bo_info_t *)l->data;
3000 if (tmp && (tmp->used == FALSE)) {
3001 LOGD("found bo %p to use", tmp->bo);
3003 MMPLAYER_VIDEO_BO_UNLOCK(player);
3004 return tbm_bo_ref(tmp->bo);
3008 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3009 MMPLAYER_VIDEO_BO_UNLOCK(player);
3013 if (player->ini.video_bo_timeout <= 0) {
3014 MMPLAYER_VIDEO_BO_WAIT(player);
3016 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout*G_TIME_SPAN_SECOND;
3017 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3024 __mmplayer_video_stream_decoded_preroll_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3026 mm_player_t* player = (mm_player_t*)data;
3028 MMPLAYER_RETURN_IF_FAIL(player && player->video_stream_cb);
3030 /* send prerolled pkt */
3031 player->video_stream_prerolled = FALSE;
3033 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3035 /* not to send prerolled pkt again */
3036 player->video_stream_prerolled = TRUE;
3040 __mmplayer_video_stream_decoded_render_cb(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3042 mm_player_t* player = (mm_player_t*)data;
3043 MMPlayerVideoStreamDataType *stream = NULL;
3044 GstMemory *mem = NULL;
3047 MMPLAYER_RETURN_IF_FAIL(player);
3048 MMPLAYER_RETURN_IF_FAIL(player->video_stream_cb);
3050 if (player->video_stream_prerolled) {
3051 player->video_stream_prerolled = FALSE;
3052 LOGD("skip the prerolled pkt not to send it again");
3056 /* clear stream data structure */
3057 stream = __mmplayer_create_stream_from_pad(pad);
3059 LOGE("failed to alloc stream");
3063 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3065 /* set size and timestamp */
3066 mem = gst_buffer_peek_memory(buffer, 0);
3067 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3068 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3070 /* check zero-copy */
3071 if (player->set_mode.video_zc &&
3072 player->set_mode.media_packet_video_stream &&
3073 gst_is_tizen_memory(mem)) {
3074 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3075 stream->internal_buffer = gst_buffer_ref(buffer);
3076 } else { /* sw codec */
3077 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3080 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3084 if (!player->video_stream_cb(stream, player->video_stream_cb_user_param)) {
3085 LOGE("failed to send video stream data.");
3092 LOGE("release video stream resource.");
3093 if (gst_is_tizen_memory(mem)) {
3095 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3097 tbm_bo_unref(stream->bo[i]);
3100 /* unref gst buffer */
3101 if (stream->internal_buffer)
3102 gst_buffer_unref(stream->internal_buffer);
3105 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3112 __mmplayer_gst_set_video360_property(mm_player_t *player)
3114 MMPlayerGstElement *videobin = NULL;
3117 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3119 videobin = player->pipeline->videobin;
3121 /* Set spatial media metadata and/or user settings to the element.
3123 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3124 "projection-type", player->video360_metadata.projection_type, NULL);
3126 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3127 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3129 if (player->video360_metadata.full_pano_width_pixels &&
3130 player->video360_metadata.full_pano_height_pixels &&
3131 player->video360_metadata.cropped_area_image_width &&
3132 player->video360_metadata.cropped_area_image_height) {
3133 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3134 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3135 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3136 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3137 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3138 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3139 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3143 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3144 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3145 "horizontal-fov", player->video360_horizontal_fov,
3146 "vertical-fov", player->video360_vertical_fov, NULL);
3149 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3150 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3151 "zoom", 1.0f / player->video360_zoom, NULL);
3154 if (player->video360_yaw_radians <= M_PI &&
3155 player->video360_yaw_radians >= -M_PI &&
3156 player->video360_pitch_radians <= M_PI_2 &&
3157 player->video360_pitch_radians >= -M_PI_2) {
3158 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3159 "pose-yaw", (int) (player->video360_yaw_radians * 180.0 / M_PI),
3160 "pose-pitch", (int) (player->video360_pitch_radians * 180.0 / M_PI), NULL);
3161 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3162 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3163 "pose-yaw", player->video360_metadata.init_view_heading,
3164 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3167 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3168 "passthrough", !player->is_video360_enabled, NULL);
3175 __mmplayer_gst_create_video_filters(mm_player_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3177 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3178 GList *element_bucket = NULL;
3181 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3183 /* create video360 filter */
3184 if (player->is_360_feature_enabled && player->is_content_spherical) {
3185 LOGD("create video360 element");
3186 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3187 __mmplayer_gst_set_video360_property(player);
3191 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3192 LOGD("skip creating the videoconv and rotator");
3193 return MM_ERROR_NONE;
3196 /* in case of sw codec & overlay surface type, except 360 playback.
3197 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3198 LOGD("create video converter: %s", video_csc);
3199 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3201 /* set video rotator */
3202 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_FLIP, "videoflip", "video rotator", TRUE, player);
3205 *bucket = element_bucket;
3207 return MM_ERROR_NONE;
3209 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3210 g_list_free(element_bucket);
3214 return MM_ERROR_PLAYER_INTERNAL;
3218 __mmplayer_get_videosink_factory_name(mm_player_t *player, MMDisplaySurfaceType surface_type)
3220 gchar *factory_name = NULL;
3222 switch (surface_type) {
3223 case MM_DISPLAY_SURFACE_OVERLAY:
3224 if (strlen(player->ini.videosink_element_overlay) > 0)
3225 factory_name = player->ini.videosink_element_overlay;
3227 case MM_DISPLAY_SURFACE_REMOTE:
3228 case MM_DISPLAY_SURFACE_NULL:
3229 if (strlen(player->ini.videosink_element_fake) > 0)
3230 factory_name = player->ini.videosink_element_fake;
3233 LOGE("unidentified surface type");
3237 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3238 return factory_name;
3242 __mmplayer_gst_set_videosink_property(mm_player_t *player, MMDisplaySurfaceType surface_type)
3244 gchar *factory_name = NULL;
3245 MMPlayerGstElement *videobin = NULL;
3250 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3252 videobin = player->pipeline->videobin;
3253 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3255 attrs = MMPLAYER_GET_ATTRS(player);
3257 LOGE("cannot get content attribute");
3258 return MM_ERROR_PLAYER_INTERNAL;
3261 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3262 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3263 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3265 /* support shard memory with S/W codec on HawkP */
3266 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3267 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3268 "use-tbm", use_tbm, NULL);
3272 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3273 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3276 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3278 LOGD("disable last-sample");
3279 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3282 if (player->set_mode.media_packet_video_stream) {
3284 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3285 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3286 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3288 __mmplayer_add_signal_connection(player,
3289 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3290 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3292 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3295 __mmplayer_add_signal_connection(player,
3296 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3297 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3299 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3303 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3304 return MM_ERROR_PLAYER_INTERNAL;
3306 if (videobin[MMPLAYER_V_SINK].gst) {
3307 GstPad *sink_pad = NULL;
3308 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3310 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3311 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3312 gst_object_unref(GST_OBJECT(sink_pad));
3314 LOGE("failed to get sink pad from videosink");
3318 return MM_ERROR_NONE;
3323 * - video overlay surface(arm/x86) : tizenwlsink
3326 __mmplayer_gst_create_video_sink_bin(mm_player_t* player, GstCaps* caps, MMDisplaySurfaceType surface_type)
3329 GList *element_bucket = NULL;
3330 MMPlayerGstElement *first_element = NULL;
3331 MMPlayerGstElement *videobin = NULL;
3332 gchar *videosink_factory_name = NULL;
3335 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3338 videobin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_V_NUM);
3340 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3342 player->pipeline->videobin = videobin;
3345 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3346 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3347 if (!videobin[MMPLAYER_V_BIN].gst) {
3348 LOGE("failed to create videobin");
3352 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3355 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3356 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3358 /* additional setting for sink plug-in */
3359 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3360 LOGE("failed to set video property");
3364 /* store it as it's sink element */
3365 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3367 /* adding created elements to bin */
3368 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3369 LOGE("failed to add elements");
3373 /* Linking elements in the bucket by added order */
3374 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3375 LOGE("failed to link elements");
3379 /* get first element's sinkpad for creating ghostpad */
3380 first_element = (MMPlayerGstElement *)element_bucket->data;
3381 if (!first_element) {
3382 LOGE("failed to get first element from bucket");
3386 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3388 LOGE("failed to get pad from first element");
3392 /* create ghostpad */
3393 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3394 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3395 LOGE("failed to add ghostpad to videobin");
3398 gst_object_unref(pad);
3400 /* done. free allocated variables */
3401 g_list_free(element_bucket);
3405 return MM_ERROR_NONE;
3408 LOGE("ERROR : releasing videobin");
3409 g_list_free(element_bucket);
3412 gst_object_unref(GST_OBJECT(pad));
3414 /* release videobin with it's childs */
3415 if (videobin[MMPLAYER_V_BIN].gst)
3416 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3418 MMPLAYER_FREEIF(videobin);
3419 player->pipeline->videobin = NULL;
3421 return MM_ERROR_PLAYER_INTERNAL;
3424 static int __mmplayer_gst_create_plain_text_elements(mm_player_t* player)
3426 GList *element_bucket = NULL;
3427 MMPlayerGstElement *textbin = player->pipeline->textbin;
3429 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3430 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3431 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3432 "signal-handoffs", FALSE,
3435 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3436 __mmplayer_add_signal_connection(player,
3437 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3438 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3440 G_CALLBACK(__mmplayer_update_subtitle),
3443 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3444 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3446 if (!player->play_subtitle) {
3447 LOGD("add textbin sink as sink element of whole pipeline.\n");
3448 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3451 /* adding created elements to bin */
3452 LOGD("adding created elements to bin\n");
3453 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3454 LOGE("failed to add elements\n");
3458 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3459 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3460 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3462 /* linking elements in the bucket by added order. */
3463 LOGD("Linking elements in the bucket by added order.\n");
3464 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3465 LOGE("failed to link elements\n");
3469 /* done. free allocated variables */
3470 g_list_free(element_bucket);
3472 if (textbin[MMPLAYER_T_QUEUE].gst) {
3474 GstPad *ghostpad = NULL;
3476 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3478 LOGE("failed to get sink pad of text queue");
3482 ghostpad = gst_ghost_pad_new("text_sink", pad);
3483 gst_object_unref(pad);
3486 LOGE("failed to create ghostpad of textbin\n");
3490 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3491 LOGE("failed to add ghostpad to textbin\n");
3492 gst_object_unref(ghostpad);
3497 return MM_ERROR_NONE;
3500 g_list_free(element_bucket);
3502 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3503 LOGE("remove textbin sink from sink list");
3504 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3507 /* release element at __mmplayer_gst_create_text_sink_bin */
3508 return MM_ERROR_PLAYER_INTERNAL;
3511 static int __mmplayer_gst_create_text_sink_bin(mm_player_t* player)
3513 MMPlayerGstElement *textbin = NULL;
3514 GList *element_bucket = NULL;
3515 int surface_type = 0;
3520 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3523 textbin = (MMPlayerGstElement*)g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_T_NUM);
3525 LOGE("failed to allocate memory for textbin\n");
3526 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3530 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3531 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3532 if (!textbin[MMPLAYER_T_BIN].gst) {
3533 LOGE("failed to create textbin\n");
3538 player->pipeline->textbin = textbin;
3541 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3542 LOGD("surface type for subtitle : %d", surface_type);
3543 switch (surface_type) {
3544 case MM_DISPLAY_SURFACE_OVERLAY:
3545 case MM_DISPLAY_SURFACE_NULL:
3546 case MM_DISPLAY_SURFACE_REMOTE:
3547 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3548 LOGE("failed to make plain text elements\n");
3559 return MM_ERROR_NONE;
3563 LOGD("ERROR : releasing textbin\n");
3565 g_list_free(element_bucket);
3567 /* release signal */
3568 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3570 /* release element which are not added to bin */
3571 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3572 /* NOTE : skip bin */
3573 if (textbin[i].gst) {
3574 GstObject* parent = NULL;
3575 parent = gst_element_get_parent(textbin[i].gst);
3578 gst_object_unref(GST_OBJECT(textbin[i].gst));
3579 textbin[i].gst = NULL;
3581 gst_object_unref(GST_OBJECT(parent));
3586 /* release textbin with it's childs */
3587 if (textbin[MMPLAYER_T_BIN].gst)
3588 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3590 MMPLAYER_FREEIF(player->pipeline->textbin);
3591 player->pipeline->textbin = NULL;
3594 return MM_ERROR_PLAYER_INTERNAL;
3599 __mmplayer_gst_create_text_pipeline(mm_player_t* player)
3601 MMPlayerGstElement* mainbin = NULL;
3602 MMPlayerGstElement* textbin = NULL;
3603 MMHandleType attrs = 0;
3604 GstElement *subsrc = NULL;
3605 GstElement *subparse = NULL;
3606 gchar *subtitle_uri = NULL;
3607 const gchar *charset = NULL;
3613 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3615 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3617 mainbin = player->pipeline->mainbin;
3619 attrs = MMPLAYER_GET_ATTRS(player);
3621 LOGE("cannot get content attribute\n");
3622 return MM_ERROR_PLAYER_INTERNAL;
3625 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3626 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3627 LOGE("subtitle uri is not proper filepath.\n");
3628 return MM_ERROR_PLAYER_INVALID_URI;
3631 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3632 LOGE("failed to get storage info of subtitle path");
3633 return MM_ERROR_PLAYER_INVALID_URI;
3636 SECURE_LOGD("subtitle file path is [%s].\n", subtitle_uri);
3638 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3639 player->subtitle_language_list = NULL;
3640 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3642 /* create the subtitle source */
3643 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3645 LOGE("failed to create filesrc element\n");
3648 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3650 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3651 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3653 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3654 LOGW("failed to add queue\n");
3655 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3656 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3657 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3662 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3664 LOGE("failed to create subparse element\n");
3668 charset = util_get_charset(subtitle_uri);
3670 LOGD("detected charset is %s\n", charset);
3671 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3674 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3675 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3677 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3678 LOGW("failed to add subparse\n");
3679 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3680 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3681 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3685 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3686 LOGW("failed to link subsrc and subparse\n");
3690 player->play_subtitle = TRUE;
3691 player->adjust_subtitle_pos = 0;
3693 LOGD("play subtitle using subtitle file\n");
3695 if (player->pipeline->textbin == NULL) {
3696 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3697 LOGE("failed to create text sink bin. continuing without text\n");
3701 textbin = player->pipeline->textbin;
3703 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3704 LOGW("failed to add textbin\n");
3706 /* release signal */
3707 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3709 /* release textbin with it's childs */
3710 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3711 MMPLAYER_FREEIF(player->pipeline->textbin);
3712 player->pipeline->textbin = textbin = NULL;
3716 LOGD("link text input selector and textbin ghost pad");
3718 player->textsink_linked = 1;
3719 player->external_text_idx = 0;
3720 LOGI("player->textsink_linked set to 1\n");
3722 textbin = player->pipeline->textbin;
3723 LOGD("text bin has been created. reuse it.");
3724 player->external_text_idx = 1;
3727 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3728 LOGW("failed to link subparse and textbin\n");
3732 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3734 LOGE("failed to get sink pad from textsink to probe data");
3738 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3739 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3741 gst_object_unref(pad);
3744 /* create dot. for debugging */
3745 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3748 return MM_ERROR_NONE;
3751 /* release text pipeline resource */
3752 player->textsink_linked = 0;
3754 /* release signal */
3755 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3757 if (player->pipeline->textbin) {
3758 LOGE("remove textbin");
3760 /* release textbin with it's childs */
3761 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3762 MMPLAYER_FREEIF(player->pipeline->textbin);
3763 player->pipeline->textbin = NULL;
3767 /* release subtitle elem */
3768 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3769 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3771 return MM_ERROR_PLAYER_INTERNAL;
3775 __mmplayer_update_subtitle(GstElement* object, GstBuffer *buffer, GstPad *pad, gpointer data)
3777 mm_player_t* player = (mm_player_t*) data;
3778 MMMessageParamType msg = {0, };
3779 GstClockTime duration = 0;
3780 gpointer text = NULL;
3781 guint text_size = 0;
3782 gboolean ret = TRUE;
3783 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3787 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3788 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3790 if (player->is_subtitle_force_drop) {
3791 LOGW("subtitle is dropped forcedly.");
3795 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3796 text = mapinfo.data;
3797 text_size = mapinfo.size;
3798 duration = GST_BUFFER_DURATION(buffer);
3800 if (player->set_mode.subtitle_off) {
3801 LOGD("subtitle is OFF.\n");
3805 if (!text || (text_size == 0)) {
3806 LOGD("There is no subtitle to be displayed.\n");
3810 msg.data = (void *) text;
3811 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3813 LOGD("update subtitle : [%ld msec] %s\n'", msg.subtitle.duration, (char*)msg.data);
3815 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3816 gst_buffer_unmap(buffer, &mapinfo);
3823 static GstPadProbeReturn
3824 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3826 mm_player_t *player = (mm_player_t *) u_data;
3827 GstClockTime cur_timestamp = 0;
3828 gint64 adjusted_timestamp = 0;
3829 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3831 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3833 if (player->set_mode.subtitle_off) {
3834 LOGD("subtitle is OFF.\n");
3838 if (player->adjust_subtitle_pos == 0) {
3839 LOGD("nothing to do");
3843 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3844 adjusted_timestamp = (gint64) cur_timestamp +((gint64) player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3846 if (adjusted_timestamp < 0) {
3847 LOGD("adjusted_timestamp under zero");
3852 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3853 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3854 GST_TIME_ARGS(cur_timestamp),
3855 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3857 return GST_PAD_PROBE_OK;
3859 static int __mmplayer_gst_adjust_subtitle_position(mm_player_t* player, int format, int position)
3863 /* check player and subtitlebin are created */
3864 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3865 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3867 if (position == 0) {
3868 LOGD("nothing to do\n");
3870 return MM_ERROR_NONE;
3874 case MM_PLAYER_POS_FORMAT_TIME:
3876 /* check current postion */
3877 player->adjust_subtitle_pos = position;
3879 LOGD("save adjust_subtitle_pos in player") ;
3885 LOGW("invalid format.\n");
3887 return MM_ERROR_INVALID_ARGUMENT;
3893 return MM_ERROR_NONE;
3897 * This function is to create audio or video pipeline for playing.
3899 * @param player [in] handle of player
3901 * @return This function returns zero on success.
3906 __mmplayer_gst_create_pipeline(mm_player_t* player)
3908 int ret = MM_ERROR_NONE;
3909 MMPlayerGstElement *mainbin = NULL;
3910 MMHandleType attrs = 0;
3911 gint mode = MM_PLAYER_PD_MODE_NONE;
3914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3916 /* get profile attribute */
3917 attrs = MMPLAYER_GET_ATTRS(player);
3919 LOGE("failed to get content attribute");
3923 /* create pipeline handles */
3924 if (player->pipeline) {
3925 LOGE("pipeline should be released before create new one");
3929 player->pipeline = (MMPlayerGstPipelineInfo*) g_malloc0(sizeof(MMPlayerGstPipelineInfo));
3930 if (player->pipeline == NULL)
3933 /* create mainbin */
3934 mainbin = (MMPlayerGstElement*) g_malloc0(sizeof(MMPlayerGstElement) * MMPLAYER_M_NUM);
3935 if (mainbin == NULL)
3938 /* create pipeline */
3939 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
3940 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
3941 if (!mainbin[MMPLAYER_M_PIPE].gst) {
3942 LOGE("failed to create pipeline");
3947 player->pipeline->mainbin = mainbin;
3950 mm_attrs_get_int_by_name(attrs, "pd_mode", &mode);
3951 player->pd_mode = mode;
3953 /* create the source and decoder elements */
3954 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
3955 ret = __mmplayer_gst_build_es_pipeline(player);
3956 } else if (MMPLAYER_IS_HTTP_STREAMING(player) && MMPLAYER_IS_HTTP_PD(player)) {
3957 ret = __mmplayer_gst_build_pd_pipeline(player);
3959 ret = __mmplayer_gst_build_pipeline(player);
3962 if (ret != MM_ERROR_NONE) {
3963 LOGE("failed to create some elements");
3967 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
3968 if (__mmplayer_check_subtitle(player)) {
3969 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE)
3970 LOGE("failed to create text pipeline");
3974 ret = __mmplayer_gst_add_bus_watch(player);
3975 if (ret != MM_ERROR_NONE) {
3976 LOGE("failed to add bus watch");
3981 return MM_ERROR_NONE;
3984 __mmplayer_gst_destroy_pipeline(player);
3985 return MM_ERROR_PLAYER_INTERNAL;
3989 __mmplayer_reset_gapless_state(mm_player_t* player)
3992 MMPLAYER_RETURN_IF_FAIL(player
3994 && player->pipeline->audiobin
3995 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
3997 memset(&player->gapless, 0, sizeof(mm_player_gapless_t));
4004 __mmplayer_gst_destroy_pipeline(mm_player_t* player)
4007 int ret = MM_ERROR_NONE;
4011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4013 /* cleanup stuffs */
4014 MMPLAYER_FREEIF(player->type);
4015 player->no_more_pad = FALSE;
4016 player->num_dynamic_pad = 0;
4017 player->demux_pad_index = 0;
4019 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4020 player->subtitle_language_list = NULL;
4021 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4023 __mmplayer_reset_gapless_state(player);
4025 if (player->streamer) {
4026 __mm_player_streaming_deinitialize(player->streamer);
4027 __mm_player_streaming_destroy(player->streamer);
4028 player->streamer = NULL;
4031 /* cleanup unlinked mime type */
4032 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4033 MMPLAYER_FREEIF(player->unlinked_video_mime);
4034 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4036 /* cleanup running stuffs */
4037 __mmplayer_cancel_eos_timer(player);
4039 /* cleanup gst stuffs */
4040 if (player->pipeline) {
4041 MMPlayerGstElement* mainbin = player->pipeline->mainbin;
4042 GstTagList* tag_list = player->pipeline->tag_list;
4044 /* first we need to disconnect all signal hander */
4045 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4048 MMPlayerGstElement* audiobin = player->pipeline->audiobin;
4049 MMPlayerGstElement* videobin = player->pipeline->videobin;
4050 MMPlayerGstElement* textbin = player->pipeline->textbin;
4051 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4052 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4053 gst_object_unref(bus);
4055 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4056 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4057 if (ret != MM_ERROR_NONE) {
4058 LOGE("fail to change state to NULL\n");
4059 return MM_ERROR_PLAYER_INTERNAL;
4062 LOGW("succeeded in changing state to NULL\n");
4064 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4067 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4068 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4070 /* free avsysaudiosink
4071 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4072 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4074 MMPLAYER_FREEIF(audiobin);
4075 MMPLAYER_FREEIF(videobin);
4076 MMPLAYER_FREEIF(textbin);
4077 MMPLAYER_FREEIF(mainbin);
4081 gst_tag_list_free(tag_list);
4083 MMPLAYER_FREEIF(player->pipeline);
4085 MMPLAYER_FREEIF(player->album_art);
4087 if (player->v_stream_caps) {
4088 gst_caps_unref(player->v_stream_caps);
4089 player->v_stream_caps = NULL;
4091 if (player->a_stream_caps) {
4092 gst_caps_unref(player->a_stream_caps);
4093 player->a_stream_caps = NULL;
4096 if (player->s_stream_caps) {
4097 gst_caps_unref(player->s_stream_caps);
4098 player->s_stream_caps = NULL;
4100 __mmplayer_track_destroy(player);
4102 if (player->sink_elements)
4103 g_list_free(player->sink_elements);
4104 player->sink_elements = NULL;
4106 if (player->bufmgr) {
4107 tbm_bufmgr_deinit(player->bufmgr);
4108 player->bufmgr = NULL;
4111 LOGW("finished destroy pipeline\n");
4118 static int __mmplayer_gst_realize(mm_player_t* player)
4121 int ret = MM_ERROR_NONE;
4125 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4127 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4129 ret = __mmplayer_gst_create_pipeline(player);
4131 LOGE("failed to create pipeline\n");
4135 /* set pipeline state to READY */
4136 /* NOTE : state change to READY must be performed sync. */
4137 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4138 ret = __mmplayer_gst_set_state(player,
4139 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4141 if (ret != MM_ERROR_NONE) {
4142 /* return error if failed to set state */
4143 LOGE("failed to set READY state");
4147 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4149 /* create dot before error-return. for debugging */
4150 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4157 static int __mmplayer_gst_unrealize(mm_player_t* player)
4159 int ret = MM_ERROR_NONE;
4163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4165 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4166 MMPLAYER_PRINT_STATE(player);
4168 /* release miscellaneous information */
4169 __mmplayer_release_misc(player);
4171 /* destroy pipeline */
4172 ret = __mmplayer_gst_destroy_pipeline(player);
4173 if (ret != MM_ERROR_NONE) {
4174 LOGE("failed to destory pipeline\n");
4178 /* release miscellaneous information.
4179 these info needs to be released after pipeline is destroyed. */
4180 __mmplayer_release_misc_post(player);
4182 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4190 __mmplayer_gst_set_message_callback(mm_player_t* player, MMMessageCallback callback, gpointer user_param)
4195 LOGW("set_message_callback is called with invalid player handle\n");
4196 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4199 player->msg_cb = callback;
4200 player->msg_cb_param = user_param;
4202 LOGD("msg_cb : %p msg_cb_param : %p\n", callback, user_param);
4206 return MM_ERROR_NONE;
4209 int __mmplayer_parse_profile(const char *uri, void *param, MMPlayerParseProfile* data)
4211 int ret = MM_ERROR_NONE;
4216 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4217 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4218 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4220 memset(data, 0, sizeof(MMPlayerParseProfile));
4222 if (strstr(uri, "es_buff://")) {
4223 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4224 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4225 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4226 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4228 tmp = g_ascii_strdown(uri, strlen(uri));
4229 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4230 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4232 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4234 } else if (strstr(uri, "mms://")) {
4235 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4236 } else if ((path = strstr(uri, "mem://"))) {
4237 ret = __mmplayer_set_mem_uri(data, path, param);
4239 ret = __mmplayer_set_file_uri(data, uri);
4242 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4243 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4244 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4245 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4247 /* dump parse result */
4248 SECURE_LOGW("incoming uri : %s\n", uri);
4249 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s\n",
4250 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4258 __mmplayer_can_do_interrupt(mm_player_t *player)
4260 if (!player || !player->pipeline || !player->attrs) {
4261 LOGW("not initialized");
4265 if (player->audio_stream_render_cb) {
4266 LOGW("not support in pcm extraction mode");
4270 /* check if seeking */
4271 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4272 MMMessageParamType msg_param;
4273 memset(&msg_param, 0, sizeof(MMMessageParamType));
4274 msg_param.code = MM_ERROR_PLAYER_SEEK;
4275 player->seek_state = MMPLAYER_SEEK_NONE;
4276 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4280 /* check other thread */
4281 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4282 LOGW("locked already, cmd state : %d", player->cmd);
4284 /* check application command */
4285 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4286 LOGW("playing.. should wait cmd lock then, will be interrupted");
4288 /* lock will be released at mrp_resource_release_cb() */
4289 MMPLAYER_CMD_LOCK(player);
4292 LOGW("nothing to do");
4295 LOGW("can interrupt immediately");
4299 FAILED: /* with CMD UNLOCKED */
4302 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4307 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4310 mm_player_t *player = NULL;
4314 if (user_data == NULL) {
4315 LOGE("- user_data is null\n");
4318 player = (mm_player_t *)user_data;
4320 /* do something to release resource here.
4321 * player stop and interrupt forwarding */
4322 if (!__mmplayer_can_do_interrupt(player)) {
4323 LOGW("no need to interrupt, so leave");
4325 MMMessageParamType msg = {0, };
4328 player->interrupted_by_resource = TRUE;
4330 /* get last play position */
4331 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4332 LOGW("failed to get play position.");
4334 msg.union_type = MM_MSG_UNION_TIME;
4335 msg.time.elapsed = pos;
4336 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4338 LOGD("video resource conflict so, resource will be freed by unrealizing");
4339 if (_mmplayer_unrealize((MMHandleType)player))
4340 LOGW("failed to unrealize");
4342 /* lock is called in __mmplayer_can_do_interrupt() */
4343 MMPLAYER_CMD_UNLOCK(player);
4346 if (res == player->video_overlay_resource)
4347 player->video_overlay_resource = FALSE;
4349 player->video_decoder_resource = FALSE;
4357 __mmplayer_initialize_video_roi(mm_player_t *player)
4359 player->video_roi.scale_x = 0.0;
4360 player->video_roi.scale_y = 0.0;
4361 player->video_roi.scale_width = 1.0;
4362 player->video_roi.scale_height = 1.0;
4366 _mmplayer_create_player(MMHandleType handle)
4368 int ret = MM_ERROR_PLAYER_INTERNAL;
4369 bool enabled = false;
4371 mm_player_t* player = MM_PLAYER_CAST(handle);
4375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4377 /* initialize player state */
4378 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4379 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4380 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4381 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4383 /* check current state */
4384 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4386 /* construct attributes */
4387 player->attrs = _mmplayer_construct_attribute(handle);
4389 if (!player->attrs) {
4390 LOGE("Failed to construct attributes\n");
4394 /* initialize gstreamer with configured parameter */
4395 if (!__mmplayer_init_gstreamer(player)) {
4396 LOGE("Initializing gstreamer failed\n");
4397 _mmplayer_deconstruct_attribute(handle);
4401 /* create lock. note that g_tread_init() has already called in gst_init() */
4402 g_mutex_init(&player->fsink_lock);
4404 /* create update tag lock */
4405 g_mutex_init(&player->update_tag_lock);
4407 /* create gapless play mutex */
4408 g_mutex_init(&player->gapless_play_thread_mutex);
4410 /* create gapless play cond */
4411 g_cond_init(&player->gapless_play_thread_cond);
4413 /* create gapless play thread */
4414 player->gapless_play_thread =
4415 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4416 if (!player->gapless_play_thread) {
4417 LOGE("failed to create gapless play thread");
4418 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4419 g_mutex_clear(&player->gapless_play_thread_mutex);
4420 g_cond_clear(&player->gapless_play_thread_cond);
4424 player->bus_msg_q = g_queue_new();
4425 if (!player->bus_msg_q) {
4426 LOGE("failed to create queue for bus_msg");
4427 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4431 ret = _mmplayer_initialize_video_capture(player);
4432 if (ret != MM_ERROR_NONE) {
4433 LOGE("failed to initialize video capture\n");
4437 /* initialize resource manager */
4438 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_create(
4439 MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, __resource_release_cb, player,
4440 &player->resource_manager)) {
4441 LOGE("failed to initialize resource manager\n");
4442 ret = MM_ERROR_PLAYER_INTERNAL;
4446 if (MMPLAYER_IS_HTTP_PD(player)) {
4447 player->pd_downloader = NULL;
4448 player->pd_file_save_path = NULL;
4451 /* create video bo lock and cond */
4452 g_mutex_init(&player->video_bo_mutex);
4453 g_cond_init(&player->video_bo_cond);
4455 /* create media stream callback mutex */
4456 g_mutex_init(&player->media_stream_cb_lock);
4458 /* create subtitle info lock and cond */
4459 g_mutex_init(&player->subtitle_info_mutex);
4460 g_cond_init(&player->subtitle_info_cond);
4462 player->streaming_type = STREAMING_SERVICE_NONE;
4464 /* give default value of audio effect setting */
4465 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4466 player->sound.rg_enable = false;
4467 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4469 player->play_subtitle = FALSE;
4470 player->has_closed_caption = FALSE;
4471 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4472 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4473 player->pending_resume = FALSE;
4474 if (player->ini.dump_element_keyword[0][0] == '\0')
4475 player->ini.set_dump_element_flag = FALSE;
4477 player->ini.set_dump_element_flag = TRUE;
4479 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4480 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4481 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4483 /* Set video360 settings to their defaults for just-created player.
4486 player->is_360_feature_enabled = FALSE;
4487 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4488 LOGI("spherical feature info: %d", enabled);
4490 player->is_360_feature_enabled = TRUE;
4492 LOGE("failed to get spherical feature info");
4495 player->is_content_spherical = FALSE;
4496 player->is_video360_enabled = TRUE;
4497 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4498 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4499 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4500 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4501 player->video360_zoom = 1.0f;
4502 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4503 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4505 __mmplayer_initialize_video_roi(player);
4507 /* set player state to null */
4508 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4509 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4511 return MM_ERROR_NONE;
4515 g_mutex_clear(&player->fsink_lock);
4517 /* free update tag lock */
4518 g_mutex_clear(&player->update_tag_lock);
4520 g_queue_free(player->bus_msg_q);
4522 /* free gapless play thread */
4523 if (player->gapless_play_thread) {
4524 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4525 player->gapless_play_thread_exit = TRUE;
4526 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4527 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4529 g_thread_join(player->gapless_play_thread);
4530 player->gapless_play_thread = NULL;
4532 g_mutex_clear(&player->gapless_play_thread_mutex);
4533 g_cond_clear(&player->gapless_play_thread_cond);
4536 /* release attributes */
4537 _mmplayer_deconstruct_attribute(handle);
4545 __mmplayer_init_gstreamer(mm_player_t* player)
4547 static gboolean initialized = FALSE;
4548 static const int max_argc = 50;
4550 gchar** argv = NULL;
4551 gchar** argv2 = NULL;
4557 LOGD("gstreamer already initialized.\n");
4562 argc = malloc(sizeof(int));
4563 argv = malloc(sizeof(gchar*) * max_argc);
4564 argv2 = malloc(sizeof(gchar*) * max_argc);
4566 if (!argc || !argv || !argv2)
4569 memset(argv, 0, sizeof(gchar*) * max_argc);
4570 memset(argv2, 0, sizeof(gchar*) * max_argc);
4574 argv[0] = g_strdup("mmplayer");
4577 for (i = 0; i < 5; i++) {
4578 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4579 if (strlen(player->ini.gst_param[i]) > 0) {
4580 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4585 /* we would not do fork for scanning plugins */
4586 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4589 /* check disable registry scan */
4590 if (player->ini.skip_rescan) {
4591 argv[*argc] = g_strdup("--gst-disable-registry-update");
4595 /* check disable segtrap */
4596 if (player->ini.disable_segtrap) {
4597 argv[*argc] = g_strdup("--gst-disable-segtrap");
4601 LOGD("initializing gstreamer with following parameter\n");
4602 LOGD("argc : %d\n", *argc);
4605 for (i = 0; i < arg_count; i++) {
4607 LOGD("argv[%d] : %s\n", i, argv2[i]);
4610 /* initializing gstreamer */
4611 if (!gst_init_check(argc, &argv, &err)) {
4612 LOGE("Could not initialize GStreamer: %s\n", err ? err->message : "unknown error occurred");
4619 for (i = 0; i < arg_count; i++) {
4620 //LOGD("release - argv[%d] : %s\n", i, argv2[i]);
4621 MMPLAYER_FREEIF(argv2[i]);
4624 MMPLAYER_FREEIF(argv);
4625 MMPLAYER_FREEIF(argv2);
4626 MMPLAYER_FREEIF(argc);
4636 for (i = 0; i < arg_count; i++) {
4637 LOGD("free[%d] : %s\n", i, argv2[i]);
4638 MMPLAYER_FREEIF(argv2[i]);
4641 MMPLAYER_FREEIF(argv);
4642 MMPLAYER_FREEIF(argv2);
4643 MMPLAYER_FREEIF(argc);
4649 __mmplayer_destroy_streaming_ext(mm_player_t* player)
4651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4653 if (player->pd_downloader || MMPLAYER_IS_HTTP_PD(player)) {
4654 _mmplayer_destroy_pd_downloader((MMHandleType)player);
4655 MMPLAYER_FREEIF(player->pd_file_save_path);
4658 return MM_ERROR_NONE;
4662 __mmplayer_check_async_state_transition(mm_player_t* player)
4664 GstState element_state = GST_STATE_VOID_PENDING;
4665 GstState element_pending_state = GST_STATE_VOID_PENDING;
4666 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4667 GstElement * element = NULL;
4668 gboolean async = FALSE;
4670 /* check player handle */
4671 MMPLAYER_RETURN_IF_FAIL(player &&
4673 player->pipeline->mainbin &&
4674 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4677 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4679 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4680 LOGD("don't need to check the pipeline state");
4684 MMPLAYER_PRINT_STATE(player);
4686 /* wait for state transition */
4687 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4688 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1*GST_SECOND);
4690 if (ret == GST_STATE_CHANGE_FAILURE) {
4691 LOGE(" [%s] state : %s pending : %s \n",
4692 GST_ELEMENT_NAME(element),
4693 gst_element_state_get_name(element_state),
4694 gst_element_state_get_name(element_pending_state));
4696 /* dump state of all element */
4697 __mmplayer_dump_pipeline_state(player);
4702 LOGD("[%s] element state has changed\n", GST_ELEMENT_NAME(element));
4707 _mmplayer_destroy(MMHandleType handle)
4709 mm_player_t* player = MM_PLAYER_CAST(handle);
4713 /* check player handle */
4714 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4716 /* destroy can called at anytime */
4717 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4719 /* check async state transition */
4720 __mmplayer_check_async_state_transition(player);
4722 __mmplayer_destroy_streaming_ext(player);
4724 /* release gapless play thread */
4725 if (player->gapless_play_thread) {
4726 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4727 player->gapless_play_thread_exit = TRUE;
4728 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4729 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4731 LOGD("waitting for gapless play thread exit\n");
4732 g_thread_join(player->gapless_play_thread);
4733 g_mutex_clear(&player->gapless_play_thread_mutex);
4734 g_cond_clear(&player->gapless_play_thread_cond);
4735 LOGD("gapless play thread released\n");
4738 _mmplayer_release_video_capture(player);
4740 /* de-initialize resource manager */
4741 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4742 player->resource_manager))
4743 LOGE("failed to deinitialize resource manager\n");
4745 /* release pipeline */
4746 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4747 LOGE("failed to destory pipeline\n");
4748 return MM_ERROR_PLAYER_INTERNAL;
4751 g_queue_free(player->bus_msg_q);
4753 /* release subtitle info lock and cond */
4754 g_mutex_clear(&player->subtitle_info_mutex);
4755 g_cond_clear(&player->subtitle_info_cond);
4757 __mmplayer_release_dump_list(player->dump_list);
4759 /* release miscellaneous information */
4760 __mmplayer_release_misc(player);
4762 /* release miscellaneous information.
4763 these info needs to be released after pipeline is destroyed. */
4764 __mmplayer_release_misc_post(player);
4766 /* release attributes */
4767 _mmplayer_deconstruct_attribute(handle);
4770 g_mutex_clear(&player->fsink_lock);
4773 g_mutex_clear(&player->update_tag_lock);
4775 /* release video bo lock and cond */
4776 g_mutex_clear(&player->video_bo_mutex);
4777 g_cond_clear(&player->video_bo_cond);
4779 /* release media stream callback lock */
4780 g_mutex_clear(&player->media_stream_cb_lock);
4784 return MM_ERROR_NONE;
4788 __mmplayer_realize_streaming_ext(mm_player_t* player)
4790 int ret = MM_ERROR_NONE;
4793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4795 if (MMPLAYER_IS_HTTP_PD(player)) {
4796 gboolean bret = FALSE;
4798 player->pd_downloader = _mmplayer_create_pd_downloader();
4799 if (!player->pd_downloader) {
4800 LOGE("Unable to create PD Downloader...");
4801 ret = MM_ERROR_PLAYER_NO_FREE_SPACE;
4804 bret = _mmplayer_realize_pd_downloader((MMHandleType)player, player->profile.uri, player->pd_file_save_path, player->pipeline->mainbin[MMPLAYER_M_SRC].gst);
4806 if (FALSE == bret) {
4807 LOGE("Unable to create PD Downloader...");
4808 ret = MM_ERROR_PLAYER_NOT_INITIALIZED;
4817 _mmplayer_realize(MMHandleType hplayer)
4819 mm_player_t* player = (mm_player_t*)hplayer;
4822 MMHandleType attrs = 0;
4823 int ret = MM_ERROR_NONE;
4827 /* check player handle */
4828 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4830 /* check current state */
4831 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4833 attrs = MMPLAYER_GET_ATTRS(player);
4835 LOGE("fail to get attributes.\n");
4836 return MM_ERROR_PLAYER_INTERNAL;
4838 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4839 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4841 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4842 ret = __mmplayer_parse_profile((const char*)uri, param, &player->profile);
4844 if (ret != MM_ERROR_NONE) {
4845 LOGE("failed to parse profile");
4850 if (uri && (strstr(uri, "es_buff://"))) {
4851 if (strstr(uri, "es_buff://push_mode"))
4852 player->es_player_push_mode = TRUE;
4854 player->es_player_push_mode = FALSE;
4857 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4858 LOGW("mms protocol is not supported format.\n");
4859 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4862 if (MMPLAYER_IS_HTTP_PD(player))
4863 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = PLAYER_PD_STATE_CHANGE_TIME;
4864 else if (MMPLAYER_IS_STREAMING(player))
4865 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4867 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4869 player->smooth_streaming = FALSE;
4870 player->videodec_linked = 0;
4871 player->audiodec_linked = 0;
4872 player->textsink_linked = 0;
4873 player->is_external_subtitle_present = FALSE;
4874 player->is_external_subtitle_added_now = FALSE;
4875 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4876 player->video360_metadata.is_spherical = -1;
4877 player->is_openal_plugin_used = FALSE;
4878 player->demux_pad_index = 0;
4879 player->subtitle_language_list = NULL;
4880 player->is_subtitle_force_drop = FALSE;
4881 player->last_multiwin_status = FALSE;
4883 __mmplayer_track_initialize(player);
4884 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4886 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4887 player->streamer = __mm_player_streaming_create();
4888 __mm_player_streaming_initialize(player->streamer);
4891 /* realize pipeline */
4892 ret = __mmplayer_gst_realize(player);
4893 if (ret != MM_ERROR_NONE)
4894 LOGE("fail to realize the player.\n");
4896 ret = __mmplayer_realize_streaming_ext(player);
4898 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4906 __mmplayer_unrealize_streaming_ext(mm_player_t *player)
4909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4911 /* destroy can called at anytime */
4912 if (player->pd_downloader && MMPLAYER_IS_HTTP_PD(player))
4913 _mmplayer_unrealize_pd_downloader((MMHandleType)player);
4916 return MM_ERROR_NONE;
4920 _mmplayer_unrealize(MMHandleType hplayer)
4922 mm_player_t* player = (mm_player_t*)hplayer;
4923 int ret = MM_ERROR_NONE;
4927 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4929 MMPLAYER_CMD_UNLOCK(player);
4930 /* destroy the gst bus msg thread which is created during realize.
4931 this funct have to be called before getting cmd lock. */
4932 __mmplayer_bus_msg_thread_destroy(player);
4933 MMPLAYER_CMD_LOCK(player);
4935 /* check current state */
4936 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4938 /* check async state transition */
4939 __mmplayer_check_async_state_transition(player);
4941 __mmplayer_unrealize_streaming_ext(player);
4943 /* unrealize pipeline */
4944 ret = __mmplayer_gst_unrealize(player);
4946 /* set asm stop if success */
4947 if (MM_ERROR_NONE == ret) {
4948 if (!player->interrupted_by_resource) {
4949 if (player->video_decoder_resource != NULL) {
4950 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4951 player->video_decoder_resource);
4952 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4953 LOGE("failed to mark decoder resource for release, ret(0x%x)\n", ret);
4955 player->video_decoder_resource = NULL;
4958 if (player->video_overlay_resource != NULL) {
4959 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4960 player->video_overlay_resource);
4961 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4962 LOGE("failed to mark overlay resource for release, ret(0x%x)\n", ret);
4964 player->video_overlay_resource = NULL;
4967 ret = mm_resource_manager_commit(player->resource_manager);
4968 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4969 LOGE("failed to commit resource releases, ret(0x%x)\n", ret);
4972 LOGE("failed and don't change asm state to stop");
4980 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4982 mm_player_t* player = (mm_player_t*)hplayer;
4984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4986 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4990 _mmplayer_get_state(MMHandleType hplayer, int* state)
4992 mm_player_t *player = (mm_player_t*)hplayer;
4994 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
4996 *state = MMPLAYER_CURRENT_STATE(player);
4998 return MM_ERROR_NONE;
5003 _mmplayer_set_volume(MMHandleType hplayer, MMPlayerVolumeType volume)
5005 mm_player_t* player = (mm_player_t*) hplayer;
5006 GstElement* vol_element = NULL;
5011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5013 LOGD("volume [L]=%f:[R]=%f\n",
5014 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5016 /* invalid factor range or not */
5017 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5018 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5019 LOGE("Invalid factor!(valid factor:0~1.0)\n");
5020 return MM_ERROR_INVALID_ARGUMENT;
5024 /* not support to set other value into each channel */
5025 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5026 return MM_ERROR_INVALID_ARGUMENT;
5028 /* Save volume to handle. Currently the first array element will be saved. */
5029 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5031 /* check pipeline handle */
5032 if (!player->pipeline || !player->pipeline->audiobin) {
5033 LOGD("audiobin is not created yet\n");
5034 LOGD("but, current stored volume will be set when it's created.\n");
5036 /* NOTE : stored volume will be used in create_audiobin
5037 * returning MM_ERROR_NONE here makes application to able to
5038 * set volume at anytime.
5040 return MM_ERROR_NONE;
5043 /* setting volume to volume element */
5044 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5047 LOGD("volume is set [%f]\n", player->sound.volume);
5048 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5053 return MM_ERROR_NONE;
5058 _mmplayer_get_volume(MMHandleType hplayer, MMPlayerVolumeType* volume)
5060 mm_player_t* player = (mm_player_t*) hplayer;
5065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5066 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5068 /* returning stored volume */
5069 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5070 volume->level[i] = player->sound.volume;
5074 return MM_ERROR_NONE;
5078 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5080 mm_player_t* player = (mm_player_t*) hplayer;
5081 GstElement* vol_element = NULL;
5085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5087 /* mute value shoud 0 or 1 */
5088 if (mute != 0 && mute != 1) {
5089 LOGE("bad mute value\n");
5091 /* FIXIT : definitly, we need _BAD_PARAM error code */
5092 return MM_ERROR_INVALID_ARGUMENT;
5095 player->sound.mute = mute;
5097 /* just hold mute value if pipeline is not ready */
5098 if (!player->pipeline || !player->pipeline->audiobin) {
5099 LOGD("pipeline is not ready. holding mute value\n");
5100 return MM_ERROR_NONE;
5103 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5105 /* NOTE : volume will only created when the bt is enabled */
5107 LOGD("mute : %d\n", mute);
5108 g_object_set(vol_element, "mute", mute, NULL);
5110 LOGD("volume elemnet is not created. using volume in audiosink\n");
5114 return MM_ERROR_NONE;
5118 _mmplayer_get_mute(MMHandleType hplayer, int* pmute)
5120 mm_player_t* player = (mm_player_t*) hplayer;
5124 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5125 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5127 /* just hold mute value if pipeline is not ready */
5128 if (!player->pipeline || !player->pipeline->audiobin) {
5129 LOGD("pipeline is not ready. returning stored value\n");
5130 *pmute = player->sound.mute;
5131 return MM_ERROR_NONE;
5134 *pmute = player->sound.mute;
5138 return MM_ERROR_NONE;
5142 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5144 mm_player_t* player = (mm_player_t*) hplayer;
5148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5150 player->video_stream_changed_cb = callback;
5151 player->video_stream_changed_cb_user_param = user_param;
5152 LOGD("Handle value is %p : %p\n", player, player->video_stream_changed_cb);
5156 return MM_ERROR_NONE;
5160 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5162 mm_player_t* player = (mm_player_t*) hplayer;
5166 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5168 player->audio_stream_changed_cb = callback;
5169 player->audio_stream_changed_cb_user_param = user_param;
5170 LOGD("Handle value is %p : %p\n", player, player->audio_stream_changed_cb);
5174 return MM_ERROR_NONE;
5178 _mmplayer_set_audiostream_cb(MMHandleType hplayer, bool sync, mm_player_audio_stream_callback callback, void *user_param)
5180 mm_player_t *player = (mm_player_t*) hplayer;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186 player->audio_stream_render_cb = callback;
5187 player->audio_stream_cb_user_param = user_param;
5188 player->audio_stream_sink_sync = sync;
5189 LOGD("handle: %p, cb: %p, sync: %d", player, player->audio_stream_render_cb, player->audio_stream_sink_sync);
5193 return MM_ERROR_NONE;
5197 _mmplayer_set_videostream_cb(MMHandleType hplayer, mm_player_video_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 if (callback && !player->bufmgr)
5206 player->bufmgr = tbm_bufmgr_init(-1);
5208 player->set_mode.media_packet_video_stream = (callback) ? true : false;
5209 player->video_stream_cb = callback;
5210 player->video_stream_cb_user_param = user_param;
5212 LOGD("Stream cb Handle value is %p : %p, enable:%d\n", player, player->video_stream_cb, player->set_mode.media_packet_video_stream);
5216 return MM_ERROR_NONE;
5220 __mmplayer_start_streaming_ext(mm_player_t *player)
5222 gint ret = MM_ERROR_NONE;
5225 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5227 if (MMPLAYER_IS_HTTP_PD(player)) {
5228 if (!player->pd_downloader) {
5229 ret = __mmplayer_realize_streaming_ext(player);
5231 if (ret != MM_ERROR_NONE) {
5232 LOGE("failed to realize streaming ext\n");
5237 if (player->pd_downloader && player->pd_mode == MM_PLAYER_PD_MODE_URI) {
5238 ret = _mmplayer_start_pd_downloader((MMHandleType)player);
5240 LOGE("ERROR while starting PD...\n");
5241 return MM_ERROR_PLAYER_NOT_INITIALIZED;
5243 ret = MM_ERROR_NONE;
5252 _mmplayer_start(MMHandleType hplayer)
5254 mm_player_t* player = (mm_player_t*) hplayer;
5255 gint ret = MM_ERROR_NONE;
5259 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5261 /* check current state */
5262 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5264 /* PD - start streaming */
5265 ret = __mmplayer_start_streaming_ext(player);
5266 if (ret != MM_ERROR_NONE) {
5267 LOGE("failed to start streaming ext 0x%X", ret);
5271 /* start pipeline */
5272 ret = __mmplayer_gst_start(player);
5273 if (ret != MM_ERROR_NONE)
5274 LOGE("failed to start player.\n");
5276 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5277 LOGD("force playing start even during buffering");
5278 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5286 /* NOTE: post "not supported codec message" to application
5287 * when one codec is not found during AUTOPLUGGING in MSL.
5288 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5289 * And, if any codec is not found, don't send message here.
5290 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5293 __mmplayer_handle_missed_plugin(mm_player_t* player)
5295 MMMessageParamType msg_param;
5296 memset(&msg_param, 0, sizeof(MMMessageParamType));
5297 gboolean post_msg_direct = FALSE;
5301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5303 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x\n",
5304 player->not_supported_codec, player->can_support_codec);
5306 if (player->not_found_demuxer) {
5307 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5308 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5310 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5311 MMPLAYER_FREEIF(msg_param.data);
5313 return MM_ERROR_NONE;
5316 if (player->not_supported_codec) {
5317 if (player->can_support_codec) {
5318 // There is one codec to play
5319 post_msg_direct = TRUE;
5321 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5322 post_msg_direct = TRUE;
5325 if (post_msg_direct) {
5326 MMMessageParamType msg_param;
5327 memset(&msg_param, 0, sizeof(MMMessageParamType));
5329 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5330 LOGW("not found AUDIO codec, posting error code to application.\n");
5332 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5333 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5334 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5335 LOGW("not found VIDEO codec, posting error code to application.\n");
5337 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5338 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5341 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5343 MMPLAYER_FREEIF(msg_param.data);
5345 return MM_ERROR_NONE;
5347 // no any supported codec case
5348 LOGW("not found any codec, posting error code to application.\n");
5350 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5351 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5352 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5354 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5355 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5358 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5360 MMPLAYER_FREEIF(msg_param.data);
5366 return MM_ERROR_NONE;
5369 static void __mmplayer_check_pipeline(mm_player_t* player)
5371 GstState element_state = GST_STATE_VOID_PENDING;
5372 GstState element_pending_state = GST_STATE_VOID_PENDING;
5374 int ret = MM_ERROR_NONE;
5376 if (player->gapless.reconfigure) {
5377 LOGW("pipeline is under construction.\n");
5379 MMPLAYER_PLAYBACK_LOCK(player);
5380 MMPLAYER_PLAYBACK_UNLOCK(player);
5382 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5384 /* wait for state transition */
5385 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5387 if (ret == GST_STATE_CHANGE_FAILURE)
5388 LOGE("failed to change pipeline state within %d sec\n", timeout);
5392 /* NOTE : it should be able to call 'stop' anytime*/
5394 _mmplayer_stop(MMHandleType hplayer)
5396 mm_player_t* player = (mm_player_t*)hplayer;
5397 int ret = MM_ERROR_NONE;
5401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5403 /* check current state */
5404 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5406 /* check pipline building state */
5407 __mmplayer_check_pipeline(player);
5408 __mmplayer_reset_gapless_state(player);
5410 /* NOTE : application should not wait for EOS after calling STOP */
5411 __mmplayer_cancel_eos_timer(player);
5413 __mmplayer_unrealize_streaming_ext(player);
5416 player->seek_state = MMPLAYER_SEEK_NONE;
5419 ret = __mmplayer_gst_stop(player);
5421 if (ret != MM_ERROR_NONE)
5422 LOGE("failed to stop player.\n");
5430 _mmplayer_pause(MMHandleType hplayer)
5432 mm_player_t* player = (mm_player_t*)hplayer;
5433 gint64 pos_nsec = 0;
5434 gboolean async = FALSE;
5435 gint ret = MM_ERROR_NONE;
5439 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5441 /* check current state */
5442 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5444 /* check pipline building state */
5445 __mmplayer_check_pipeline(player);
5447 switch (MMPLAYER_CURRENT_STATE(player)) {
5448 case MM_PLAYER_STATE_READY:
5450 /* check prepare async or not.
5451 * In the case of streaming playback, it's recommned to avoid blocking wait.
5453 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5454 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5456 /* Changing back sync of rtspsrc to async */
5457 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5458 LOGD("async prepare working mode for rtsp");
5464 case MM_PLAYER_STATE_PLAYING:
5466 /* NOTE : store current point to overcome some bad operation
5467 *(returning zero when getting current position in paused state) of some
5470 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5471 LOGW("getting current position failed in paused\n");
5473 player->last_position = pos_nsec;
5475 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5476 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5477 This causes problem is position calculation during normal pause resume scenarios also.
5478 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5479 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5480 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5481 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5487 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5488 LOGD("doing async pause in case of ms buff src");
5492 /* pause pipeline */
5493 ret = __mmplayer_gst_pause(player, async);
5495 if (ret != MM_ERROR_NONE)
5496 LOGE("failed to pause player. ret : 0x%x\n", ret);
5498 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5499 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5500 LOGE("failed to update display_rotation");
5508 /* in case of streaming, pause could take long time.*/
5510 _mmplayer_abort_pause(MMHandleType hplayer)
5512 mm_player_t* player = (mm_player_t*)hplayer;
5513 int ret = MM_ERROR_NONE;
5517 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5519 player->pipeline->mainbin,
5520 MM_ERROR_PLAYER_NOT_INITIALIZED);
5522 LOGD("set the pipeline state to READY");
5524 /* set state to READY */
5525 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5526 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5527 if (ret != MM_ERROR_NONE) {
5528 LOGE("fail to change state to READY");
5529 return MM_ERROR_PLAYER_INTERNAL;
5532 LOGD("succeeded in changing state to READY");
5538 _mmplayer_resume(MMHandleType hplayer)
5540 mm_player_t* player = (mm_player_t*)hplayer;
5541 int ret = MM_ERROR_NONE;
5542 gboolean async = FALSE;
5546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5548 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5549 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5550 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5554 /* Changing back sync mode rtspsrc to async */
5555 LOGD("async resume for rtsp case");
5559 /* check current state */
5560 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5562 ret = __mmplayer_gst_resume(player, async);
5563 if (ret != MM_ERROR_NONE)
5564 LOGE("failed to resume player.\n");
5566 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5567 LOGD("force resume even during buffering");
5568 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5577 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5579 mm_player_t* player = (mm_player_t*)hplayer;
5580 gint64 pos_nsec = 0;
5581 int ret = MM_ERROR_NONE;
5583 signed long long start = 0, stop = 0;
5584 MMPlayerStateType current_state = MM_PLAYER_STATE_NONE;
5587 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5588 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5590 /* The sound of video is not supported under 0.0 and over 2.0. */
5591 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5592 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5595 _mmplayer_set_mute(hplayer, mute);
5597 if (player->playback_rate == rate)
5598 return MM_ERROR_NONE;
5600 /* If the position is reached at start potion during fast backward, EOS is posted.
5601 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5603 player->playback_rate = rate;
5605 current_state = MMPLAYER_CURRENT_STATE(player);
5607 if (current_state != MM_PLAYER_STATE_PAUSED)
5608 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5610 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5612 if ((current_state == MM_PLAYER_STATE_PAUSED)
5613 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5614 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5615 pos_nsec = player->last_position;
5620 stop = GST_CLOCK_TIME_NONE;
5622 start = GST_CLOCK_TIME_NONE;
5626 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5627 player->playback_rate,
5629 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5630 GST_SEEK_TYPE_SET, start,
5631 GST_SEEK_TYPE_SET, stop)) {
5632 LOGE("failed to set speed playback\n");
5633 return MM_ERROR_PLAYER_SEEK;
5636 LOGD("succeeded to set speed playback as %0.1f\n", rate);
5640 return MM_ERROR_NONE;;
5644 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5646 mm_player_t* player = (mm_player_t*)hplayer;
5647 int ret = MM_ERROR_NONE;
5651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5653 /* check pipline building state */
5654 __mmplayer_check_pipeline(player);
5656 ret = __mmplayer_gst_set_position(player, position, FALSE);
5664 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5666 mm_player_t* player = (mm_player_t*)hplayer;
5667 int ret = MM_ERROR_NONE;
5669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5671 ret = __mmplayer_gst_get_position(player, position);
5677 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5679 mm_player_t* player = (mm_player_t*)hplayer;
5680 int ret = MM_ERROR_NONE;
5682 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5683 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5685 *duration = player->duration;
5690 _mmplayer_get_buffer_position(MMHandleType hplayer, int format, unsigned long* start_pos, unsigned long* stop_pos)
5692 mm_player_t* player = (mm_player_t*)hplayer;
5693 int ret = MM_ERROR_NONE;
5695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5697 ret = __mmplayer_gst_get_buffer_position(player, format, start_pos, stop_pos);
5703 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int format, int position)
5705 mm_player_t* player = (mm_player_t*)hplayer;
5706 int ret = MM_ERROR_NONE;
5710 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712 ret = __mmplayer_gst_adjust_subtitle_position(player, format, position);
5720 __mmplayer_is_midi_type(gchar* str_caps)
5722 if ((g_strrstr(str_caps, "audio/midi")) ||
5723 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5724 (g_strrstr(str_caps, "application/x-smaf")) ||
5725 (g_strrstr(str_caps, "audio/x-imelody")) ||
5726 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5727 (g_strrstr(str_caps, "audio/xmf")) ||
5728 (g_strrstr(str_caps, "audio/mxmf"))) {
5737 __mmplayer_is_only_mp3_type(gchar *str_caps)
5739 if (g_strrstr(str_caps, "application/x-id3") ||
5740 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion= (int)1")))
5746 __mmplayer_set_audio_attrs(mm_player_t* player, GstCaps* caps)
5748 GstStructure* caps_structure = NULL;
5749 gint samplerate = 0;
5753 MMPLAYER_RETURN_IF_FAIL(player && caps);
5755 caps_structure = gst_caps_get_structure(caps, 0);
5757 /* set stream information */
5758 gst_structure_get_int(caps_structure, "rate", &samplerate);
5759 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5761 gst_structure_get_int(caps_structure, "channels", &channels);
5762 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5764 LOGD("audio samplerate : %d channels : %d\n", samplerate, channels);
5768 __mmplayer_update_content_type_info(mm_player_t* player)
5771 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5773 if (__mmplayer_is_midi_type(player->type)) {
5774 player->bypass_audio_effect = TRUE;
5775 } else if (g_strrstr(player->type, "application/x-hls")) {
5776 /* If it can't know exact type when it parses uri because of redirection case,
5777 * it will be fixed by typefinder or when doing autoplugging.
5779 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5780 if (player->streamer) {
5781 player->streamer->is_adaptive_streaming = TRUE;
5782 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5783 player->streamer->buffering_req.rebuffer_time = 5 * 1000;
5785 } else if (g_strrstr(player->type, "application/dash+xml")) {
5786 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5787 if (player->streamer) {
5788 player->streamer->is_adaptive_streaming = TRUE;
5789 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5793 LOGD("uri type : %d", player->profile.uri_type);
5798 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5799 GstCaps *caps, gpointer data)
5801 mm_player_t* player = (mm_player_t*)data;
5806 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5808 /* store type string */
5809 MMPLAYER_FREEIF(player->type);
5810 player->type = gst_caps_to_string(caps);
5812 LOGD("[handle: %p] media type %s found, probability %d%% / %d\n",
5813 player, player->type, probability, gst_caps_get_size(caps));
5816 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5817 (g_strrstr(player->type, "audio/x-raw-int"))) {
5818 LOGE("not support media format\n");
5820 if (player->msg_posted == FALSE) {
5821 MMMessageParamType msg_param;
5822 memset(&msg_param, 0, sizeof(MMMessageParamType));
5824 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5825 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5827 /* don't post more if one was sent already */
5828 player->msg_posted = TRUE;
5833 __mmplayer_update_content_type_info(player);
5835 pad = gst_element_get_static_pad(tf, "src");
5837 LOGE("fail to get typefind src pad.\n");
5841 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5842 gboolean async = FALSE;
5843 LOGE("failed to autoplug %s\n", player->type);
5845 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5847 if (async && player->msg_posted == FALSE)
5848 __mmplayer_handle_missed_plugin(player);
5854 gst_object_unref(GST_OBJECT(pad));
5862 __mmplayer_gst_make_decodebin(mm_player_t* player)
5864 GstElement *decodebin = NULL;
5868 /* create decodebin */
5869 decodebin = gst_element_factory_make("decodebin", NULL);
5872 LOGE("fail to create decodebin\n");
5876 /* raw pad handling signal */
5877 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5878 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5880 /* no-more-pad pad handling signal */
5881 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5882 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5884 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5885 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5887 /* This signal is emitted when a pad for which there is no further possible
5888 decoding is added to the decodebin.*/
5889 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5890 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5892 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5893 before looking for any elements that can handle that stream.*/
5894 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5895 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5897 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5898 before looking for any elements that can handle that stream.*/
5899 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5900 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5902 /* This signal is emitted once decodebin has finished decoding all the data.*/
5903 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5904 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5906 /* This signal is emitted when a element is added to the bin.*/
5907 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5908 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5915 __mmplayer_gst_make_queue2(mm_player_t *player)
5917 GstElement* queue2 = NULL;
5918 gint64 dur_bytes = 0L;
5919 guint max_buffer_size_bytes = 0;
5920 MMPlayerGstElement *mainbin = NULL;
5921 MuxedBufferType type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5924 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5926 mainbin = player->pipeline->mainbin;
5928 queue2 = gst_element_factory_make("queue2", "queue2");
5930 LOGE("failed to create buffering queue element");
5934 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5935 LOGE("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5937 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5939 if (dur_bytes > 0) {
5940 if (MMPLAYER_USE_FILE_FOR_BUFFERING(player)) {
5941 type = MUXED_BUFFER_TYPE_FILE;
5943 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5944 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5950 /* NOTE : in case of ts streaming, player cannot get the correct duration info *
5951 * skip the pull mode(file or ring buffering) setting. */
5952 if (!g_strrstr(player->type, "video/mpegts")) {
5953 max_buffer_size_bytes = (type == MUXED_BUFFER_TYPE_FILE) ? (player->ini.http_max_size_bytes) : (5*1024*1024);
5954 LOGD("max_buffer_size_bytes = %d", max_buffer_size_bytes);
5956 __mm_player_streaming_set_queue2(player->streamer,
5959 max_buffer_size_bytes,
5960 player->ini.http_buffering_time,
5961 1.0, /* no meaning */
5962 player->ini.http_buffering_limit, /* no meaning */
5964 player->http_file_buffering_path,
5965 (guint64)dur_bytes);
5972 __mmplayer_gst_create_decoder(mm_player_t* player, GstPad *srcpad, const GstCaps *caps)
5974 MMPlayerGstElement* mainbin = NULL;
5975 GstElement* decodebin = NULL;
5976 GstElement* queue2 = NULL;
5977 GstPad* sinkpad = NULL;
5978 GstPad* qsrcpad = NULL;
5979 gint init_buffering_time = player->streamer->buffering_req.prebuffer_time;
5982 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5984 mainbin = player->pipeline->mainbin;
5986 if ((!MMPLAYER_IS_HTTP_PD(player)) && (MMPLAYER_IS_HTTP_STREAMING(player))) {
5988 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5989 LOGW("need to check: muxed buffer is not null");
5992 queue2 = __mmplayer_gst_make_queue2(player);
5994 LOGE("failed to make queue2");
5998 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5999 LOGE("failed to add buffering queue");
6003 sinkpad = gst_element_get_static_pad(queue2, "sink");
6004 qsrcpad = gst_element_get_static_pad(queue2, "src");
6006 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6007 LOGE("failed to link [%s:%s]-[%s:%s]",
6008 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6012 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6013 LOGE("failed to sync queue2 state with parent");
6017 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6018 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6022 gst_object_unref(GST_OBJECT(sinkpad));
6026 /* create decodebin */
6027 decodebin = __mmplayer_gst_make_decodebin(player);
6029 LOGE("failed to make decodebin");
6033 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6034 LOGE("failed to add decodebin\n");
6038 /* to force caps on the decodebin element and avoid reparsing stuff by
6039 * typefind. It also avoids a deadlock in the way typefind activates pads in
6040 * the state change */
6041 g_object_set(decodebin, "sink-caps", caps, NULL);
6043 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6045 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6046 LOGE("failed to link [%s:%s]-[%s:%s]",
6047 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6051 gst_object_unref(GST_OBJECT(sinkpad));
6054 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6055 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6057 /* set decodebin property about buffer in streaming playback. *
6058 * in case of HLS/DASH, it does not need to have big buffer *
6059 * because it is kind of adaptive streaming. */
6060 if (!MMPLAYER_IS_HTTP_PD(player) &&
6061 (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player))) {
6062 gdouble high_percent = 0.0;
6064 init_buffering_time = (init_buffering_time != 0) ? (init_buffering_time) : (player->ini.http_buffering_time);
6065 high_percent = (gdouble)(init_buffering_time * 100) / GET_MAX_BUFFER_TIME(player->streamer);
6067 LOGD("decodebin setting - bytes: %d, time: %d ms, per: 1~%d",
6068 GET_MAX_BUFFER_BYTES(player->streamer), GET_MAX_BUFFER_TIME(player->streamer), (gint)high_percent);
6070 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6071 "high-percent", (gint)high_percent,
6072 "low-percent", (gint)DEFAULT_BUFFER_LOW_PERCENT,
6073 "max-size-bytes", GET_MAX_BUFFER_BYTES(player->streamer),
6074 "max-size-time", (guint64)(GET_MAX_BUFFER_TIME(player->streamer) * GST_MSECOND),
6075 "max-size-buffers", 0, NULL); // disable or automatic
6078 if (GST_STATE_CHANGE_FAILURE == gst_element_sync_state_with_parent(decodebin)) {
6079 LOGE("failed to sync decodebin state with parent\n");
6090 gst_object_unref(GST_OBJECT(sinkpad));
6093 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6094 * You need to explicitly set elements to the NULL state before
6095 * dropping the final reference, to allow them to clean up.
6097 gst_element_set_state(queue2, GST_STATE_NULL);
6099 /* And, it still has a parent "player".
6100 * You need to let the parent manage the object instead of unreffing the object directly.
6102 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6103 gst_object_unref(queue2);
6108 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6109 * You need to explicitly set elements to the NULL state before
6110 * dropping the final reference, to allow them to clean up.
6112 gst_element_set_state(decodebin, GST_STATE_NULL);
6114 /* And, it still has a parent "player".
6115 * You need to let the parent manage the object instead of unreffing the object directly.
6118 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6119 gst_object_unref(decodebin);
6127 __mmplayer_check_not_supported_codec(mm_player_t* player, const gchar* factory_class, const gchar* mime)
6131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6132 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6134 LOGD("class : %s, mime : %s \n", factory_class, mime);
6136 /* add missing plugin */
6137 /* NOTE : msl should check missing plugin for image mime type.
6138 * Some motion jpeg clips can have playable audio track.
6139 * So, msl have to play audio after displaying popup written video format not supported.
6141 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6142 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6143 LOGD("not found demuxer\n");
6144 player->not_found_demuxer = TRUE;
6145 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6151 if (!g_strrstr(factory_class, "Demuxer")) {
6152 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6153 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d\n",
6154 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6156 /* check that clip have multi tracks or not */
6157 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6158 LOGD("video plugin is already linked\n");
6160 LOGW("add VIDEO to missing plugin\n");
6161 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6162 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6164 } else if (g_str_has_prefix(mime, "audio")) {
6165 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6166 LOGD("audio plugin is already linked\n");
6168 LOGW("add AUDIO to missing plugin\n");
6169 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6170 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6178 return MM_ERROR_NONE;
6183 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6185 mm_player_t* player = (mm_player_t*)data;
6189 MMPLAYER_RETURN_IF_FAIL(player);
6191 /* remove fakesink. */
6192 if (!__mmplayer_gst_remove_fakesink(player,
6193 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6194 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6195 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6196 * source element are not same. To overcome this situation, this function will called
6197 * several places and several times. Therefore, this is not an error case.
6202 LOGD("[handle: %p] pipeline has completely constructed", player);
6204 if ((player->ini.async_start) &&
6205 (player->msg_posted == FALSE) &&
6206 (player->cmd >= MMPLAYER_COMMAND_START))
6207 __mmplayer_handle_missed_plugin(player);
6209 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6213 __mmplayer_check_profile(void)
6216 static int profile_tv = -1;
6218 if (__builtin_expect(profile_tv != -1, 1))
6221 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6222 switch (*profileName) {
6237 __mmplayer_get_next_uri(mm_player_t *player)
6239 MMPlayerParseProfile profile;
6241 guint num_of_list = 0;
6244 num_of_list = g_list_length(player->uri_info.uri_list);
6245 uri_idx = player->uri_info.uri_idx;
6247 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6248 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6249 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6251 LOGW("next uri does not exist");
6255 if (__mmplayer_parse_profile((const char*)uri, NULL, &profile) != MM_ERROR_NONE) {
6256 LOGE("failed to parse profile");
6260 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6261 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6262 LOGW("uri type is not supported(%d)", profile.uri_type);
6266 LOGD("success to find next uri %d", uri_idx);
6270 if (uri_idx == num_of_list) {
6271 LOGE("failed to find next uri");
6275 player->uri_info.uri_idx = uri_idx;
6276 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6278 if (mm_attrs_commit_all(player->attrs)) {
6279 LOGE("failed to commit");
6283 SECURE_LOGD("next playback uri: %s", uri);
6288 __mmplayer_verify_gapless_play_path(mm_player_t *player)
6290 #define REPEAT_COUNT_INFINITELY -1
6291 #define REPEAT_COUNT_MIN 2
6293 MMHandleType attrs = 0;
6294 gint mode = MM_PLAYER_PD_MODE_NONE;
6298 guint num_of_list = 0;
6299 int profile_tv = -1;
6303 LOGD("checking for gapless play option");
6305 if (player->pipeline->textbin) {
6306 LOGE("subtitle path is enabled. gapless play is not supported.\n");
6310 attrs = MMPLAYER_GET_ATTRS(player);
6312 LOGE("fail to get attributes.\n");
6316 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6318 /* gapless playback is not supported in case of video at TV profile. */
6319 profile_tv = __mmplayer_check_profile();
6320 if (profile_tv && video) {
6321 LOGW("not support video gapless playback");
6325 if (mm_attrs_get_int_by_name(attrs, "pd_mode", &mode) == MM_ERROR_NONE) {
6332 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6333 LOGE("failed to get play count");
6335 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6336 LOGE("failed to get gapless mode");
6338 /* check repeat count in case of audio */
6340 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6341 LOGW("gapless is disabled");
6345 num_of_list = g_list_length(player->uri_info.uri_list);
6347 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6349 if (num_of_list == 0) {
6350 /* audio looping path */
6351 if (count >= REPEAT_COUNT_MIN) {
6352 /* decrease play count */
6353 /* we succeeded to rewind. update play count and then wait for next EOS */
6356 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6358 /* commit attribute */
6359 if (mm_attrs_commit_all(attrs))
6360 LOGE("failed to commit attribute");
6361 } else if (count != REPEAT_COUNT_INFINITELY) {
6362 LOGD("there is no next uri and no repeat");
6366 LOGD("looping cnt %d", count);
6368 /* gapless playback path */
6369 if (!__mmplayer_get_next_uri(player)) {
6370 LOGE("failed to get next uri");
6378 LOGE("unable to play gapless path. EOS will be posted soon");
6383 __mmplayer_initialize_gapless_play(mm_player_t *player)
6389 player->smooth_streaming = FALSE;
6390 player->videodec_linked = 0;
6391 player->audiodec_linked = 0;
6392 player->textsink_linked = 0;
6393 player->is_external_subtitle_present = FALSE;
6394 player->is_external_subtitle_added_now = FALSE;
6395 player->not_supported_codec = MISSING_PLUGIN_NONE;
6396 player->can_support_codec = FOUND_PLUGIN_NONE;
6397 player->pending_seek.is_pending = FALSE;
6398 player->pending_seek.pos = 0;
6399 player->msg_posted = FALSE;
6400 player->has_many_types = FALSE;
6401 player->no_more_pad = FALSE;
6402 player->not_found_demuxer = 0;
6403 player->seek_state = MMPLAYER_SEEK_NONE;
6404 player->is_subtitle_force_drop = FALSE;
6405 player->play_subtitle = FALSE;
6406 player->adjust_subtitle_pos = 0;
6408 player->total_bitrate = 0;
6409 player->total_maximum_bitrate = 0;
6411 __mmplayer_track_initialize(player);
6412 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6414 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6415 player->bitrate[i] = 0;
6416 player->maximum_bitrate[i] = 0;
6419 if (player->v_stream_caps) {
6420 gst_caps_unref(player->v_stream_caps);
6421 player->v_stream_caps = NULL;
6424 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6426 /* clean found parsers */
6427 if (player->parsers) {
6428 GList *parsers = player->parsers;
6429 for (; parsers; parsers = g_list_next(parsers)) {
6430 gchar *name = parsers->data;
6431 MMPLAYER_FREEIF(name);
6433 g_list_free(player->parsers);
6434 player->parsers = NULL;
6437 /* clean found audio decoders */
6438 if (player->audio_decoders) {
6439 GList *a_dec = player->audio_decoders;
6440 for (; a_dec; a_dec = g_list_next(a_dec)) {
6441 gchar *name = a_dec->data;
6442 MMPLAYER_FREEIF(name);
6444 g_list_free(player->audio_decoders);
6445 player->audio_decoders = NULL;
6452 __mmplayer_activate_next_source(mm_player_t *player, GstState target)
6454 MMPlayerGstElement *mainbin = NULL;
6455 MMMessageParamType msg_param = {0,};
6456 GstElement *element = NULL;
6457 MMHandleType attrs = 0;
6459 enum MainElementID elem_idx = MMPLAYER_M_NUM;
6463 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6464 LOGE("player is not initialized");
6468 mainbin = player->pipeline->mainbin;
6469 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6471 attrs = MMPLAYER_GET_ATTRS(player);
6473 LOGE("fail to get attributes");
6477 /* Initialize Player values */
6478 __mmplayer_initialize_gapless_play(player);
6480 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6482 if (__mmplayer_parse_profile((const char*)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6483 LOGE("failed to parse profile");
6484 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6488 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6489 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6490 LOGE("dash or hls is not supportable");
6491 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6495 element = __mmplayer_gst_create_source(player);
6497 LOGE("no source element was created");
6501 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6502 LOGE("failed to add source element to pipeline");
6503 gst_object_unref(GST_OBJECT(element));
6508 /* take source element */
6509 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6510 mainbin[MMPLAYER_M_SRC].gst = element;
6514 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6515 if (player->streamer == NULL) {
6516 player->streamer = __mm_player_streaming_create();
6517 __mm_player_streaming_initialize(player->streamer);
6520 elem_idx = MMPLAYER_M_TYPEFIND;
6521 element = gst_element_factory_make("typefind", "typefinder");
6522 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6523 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6525 elem_idx = MMPLAYER_M_AUTOPLUG;
6526 element = __mmplayer_gst_make_decodebin(player);
6529 /* check autoplug element is OK */
6531 LOGE("can not create element(%d)", elem_idx);
6535 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6536 LOGE("failed to add sinkbin to pipeline");
6537 gst_object_unref(GST_OBJECT(element));
6542 mainbin[elem_idx].id = elem_idx;
6543 mainbin[elem_idx].gst = element;
6545 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6546 LOGE("Failed to link src - autoplug(or typefind)");
6550 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6551 LOGE("Failed to change state of src element");
6555 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6556 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6557 LOGE("Failed to change state of decodebin");
6561 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6562 LOGE("Failed to change state of src element");
6567 player->gapless.stream_changed = TRUE;
6568 player->gapless.running = TRUE;
6574 MMPLAYER_PLAYBACK_UNLOCK(player);
6576 if (!player->msg_posted) {
6577 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6578 player->msg_posted = TRUE;
6585 __mmplayer_deactivate_selector(mm_player_t *player, MMPlayerTrackType type)
6587 mm_player_selector_t *selector = &player->selector[type];
6588 MMPlayerGstElement *sinkbin = NULL;
6589 enum MainElementID selectorId = MMPLAYER_M_NUM;
6590 enum MainElementID sinkId = MMPLAYER_M_NUM;
6591 GstPad *srcpad = NULL;
6592 GstPad *sinkpad = NULL;
6593 gboolean send_notice = FALSE;
6596 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6598 LOGD("type %d", type);
6601 case MM_PLAYER_TRACK_TYPE_AUDIO:
6602 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6603 sinkId = MMPLAYER_A_BIN;
6604 sinkbin = player->pipeline->audiobin;
6606 case MM_PLAYER_TRACK_TYPE_VIDEO:
6607 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6608 sinkId = MMPLAYER_V_BIN;
6609 sinkbin = player->pipeline->videobin;
6612 case MM_PLAYER_TRACK_TYPE_TEXT:
6613 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6614 sinkId = MMPLAYER_T_BIN;
6615 sinkbin = player->pipeline->textbin;
6618 LOGE("requested type is not supportable");
6623 if (player->pipeline->mainbin[selectorId].gst) {
6626 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6628 if (selector->event_probe_id != 0)
6629 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6630 selector->event_probe_id = 0;
6632 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6633 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6635 if (srcpad && sinkpad) {
6636 /* after getting drained signal there is no data flows, so no need to do pad_block */
6637 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6638 gst_pad_unlink(srcpad, sinkpad);
6640 /* send custom event to sink pad to handle it at video sink */
6642 LOGD("send custom event to sinkpad");
6643 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6644 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6645 gst_pad_send_event(sinkpad, event);
6649 gst_object_unref(sinkpad);
6652 gst_object_unref(srcpad);
6655 LOGD("selector release");
6657 /* release and unref requests pad from the selector */
6658 for (n = 0; n < selector->channels->len; n++) {
6659 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6660 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6662 g_ptr_array_set_size(selector->channels, 0);
6664 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6665 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6667 player->pipeline->mainbin[selectorId].gst = NULL;
6675 __mmplayer_deactivate_old_path(mm_player_t *player)
6678 MMPLAYER_RETURN_IF_FAIL(player);
6680 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6681 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6682 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6683 LOGE("deactivate selector error");
6687 __mmplayer_track_destroy(player);
6688 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6690 if (player->streamer) {
6691 __mm_player_streaming_deinitialize(player->streamer);
6692 __mm_player_streaming_destroy(player->streamer);
6693 player->streamer = NULL;
6696 MMPLAYER_PLAYBACK_LOCK(player);
6697 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6704 if (!player->msg_posted) {
6705 MMMessageParamType msg = {0,};
6708 msg.code = MM_ERROR_PLAYER_INTERNAL;
6709 LOGE("gapless_uri_play> deactivate error");
6711 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6712 player->msg_posted = TRUE;
6717 int _mmplayer_set_file_buffering_path(MMHandleType hplayer, const char* file_path)
6719 int result = MM_ERROR_NONE;
6720 mm_player_t* player = (mm_player_t*) hplayer;
6723 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6726 player->http_file_buffering_path = (gchar*)file_path;
6727 LOGD("temp file path: %s\n", player->http_file_buffering_path);
6733 int _mmplayer_set_uri(MMHandleType hplayer, const char* uri)
6735 int result = MM_ERROR_NONE;
6736 mm_player_t* player = (mm_player_t*) hplayer;
6739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6741 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6742 if (mm_attrs_commit_all(player->attrs)) {
6743 LOGE("failed to commit the original uri.\n");
6744 result = MM_ERROR_PLAYER_INTERNAL;
6746 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6747 LOGE("failed to add the original uri in the uri list.\n");
6754 int _mmplayer_set_next_uri(MMHandleType hplayer, const char* uri, bool is_first_path)
6756 mm_player_t* player = (mm_player_t*) hplayer;
6757 guint num_of_list = 0;
6761 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6762 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6764 if (player->pipeline && player->pipeline->textbin) {
6765 LOGE("subtitle path is enabled.\n");
6766 return MM_ERROR_PLAYER_INVALID_STATE;
6769 num_of_list = g_list_length(player->uri_info.uri_list);
6771 if (is_first_path == TRUE) {
6772 if (num_of_list == 0) {
6773 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6774 LOGD("add original path : %s", uri);
6776 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6777 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6779 LOGD("change original path : %s", uri);
6782 MMHandleType attrs = 0;
6783 attrs = MMPLAYER_GET_ATTRS(player);
6785 if (num_of_list == 0) {
6786 char *original_uri = NULL;
6789 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6791 if (!original_uri) {
6792 LOGE("there is no original uri.");
6793 return MM_ERROR_PLAYER_INVALID_STATE;
6796 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6797 player->uri_info.uri_idx = 0;
6799 LOGD("add original path at first : %s(%d)", original_uri);
6803 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6804 LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6808 return MM_ERROR_NONE;
6811 int _mmplayer_get_next_uri(MMHandleType hplayer, char** uri)
6813 mm_player_t* player = (mm_player_t*) hplayer;
6814 char *next_uri = NULL;
6815 guint num_of_list = 0;
6818 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6820 num_of_list = g_list_length(player->uri_info.uri_list);
6822 if (num_of_list > 0) {
6823 gint uri_idx = player->uri_info.uri_idx;
6825 if (uri_idx < num_of_list-1)
6830 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6831 LOGE("next uri idx : %d, uri = %s\n", uri_idx, next_uri);
6833 *uri = g_strdup(next_uri);
6837 return MM_ERROR_NONE;
6841 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad* pad,
6842 GstCaps *caps, gpointer data)
6844 mm_player_t* player = (mm_player_t*)data;
6845 const gchar* klass = NULL;
6846 const gchar* mime = NULL;
6847 gchar* caps_str = NULL;
6849 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6850 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6851 caps_str = gst_caps_to_string(caps);
6853 LOGW("unknown type of caps : %s from %s",
6854 caps_str, GST_ELEMENT_NAME(elem));
6856 MMPLAYER_FREEIF(caps_str);
6858 /* There is no available codec. */
6859 __mmplayer_check_not_supported_codec(player, klass, mime);
6863 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad* pad,
6864 GstCaps * caps, gpointer data)
6866 mm_player_t* player = (mm_player_t*)data;
6867 const char* mime = NULL;
6868 gboolean ret = TRUE;
6870 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6871 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6873 if (g_str_has_prefix(mime, "audio")) {
6874 GstStructure* caps_structure = NULL;
6875 gint samplerate = 0;
6877 gchar *caps_str = NULL;
6879 caps_structure = gst_caps_get_structure(caps, 0);
6880 gst_structure_get_int(caps_structure, "rate", &samplerate);
6881 gst_structure_get_int(caps_structure, "channels", &channels);
6883 if ((channels > 0 && samplerate == 0)) {
6884 LOGD("exclude audio...");
6888 caps_str = gst_caps_to_string(caps);
6889 /* set it directly because not sent by TAG */
6890 if (g_strrstr(caps_str, "mobile-xmf"))
6891 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6892 MMPLAYER_FREEIF(caps_str);
6893 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6894 MMMessageParamType msg_param;
6895 memset(&msg_param, 0, sizeof(MMMessageParamType));
6896 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6897 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6898 LOGD("video file is not supported on this device");
6900 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6901 LOGD("already video linked");
6904 LOGD("found new stream");
6911 __mmplayer_check_codec_info(mm_player_t* player, const char* klass, GstCaps* caps, char* factory_name)
6913 int ret = MM_ERROR_NONE;
6915 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6917 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6918 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6920 LOGD("audio codec type: %d", codec_type);
6921 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6922 /* sw codec will be skipped */
6923 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6924 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6925 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6926 ret = MM_ERROR_PLAYER_INTERNAL;
6930 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6931 /* hw codec will be skipped */
6932 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6933 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6934 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6935 ret = MM_ERROR_PLAYER_INTERNAL;
6940 /* set stream information */
6941 if (!player->audiodec_linked)
6942 __mmplayer_set_audio_attrs(player, caps);
6944 /* update codec info */
6945 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6946 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6947 player->audiodec_linked = 1;
6949 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6951 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6953 LOGD("video codec type: %d", codec_type);
6954 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6955 /* sw codec is skipped */
6956 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6957 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6958 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6959 ret = MM_ERROR_PLAYER_INTERNAL;
6963 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6964 /* hw codec is skipped */
6965 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
6966 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
6967 ret = MM_ERROR_PLAYER_INTERNAL;
6972 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
6973 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
6975 /* mark video decoder for acquire */
6976 if (player->video_decoder_resource == NULL) {
6977 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
6978 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
6979 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
6980 &player->video_decoder_resource)
6981 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6982 LOGE("could not mark video_decoder resource for acquire");
6983 ret = MM_ERROR_PLAYER_INTERNAL;
6987 LOGW("video decoder resource is already acquired, skip it.");
6988 ret = MM_ERROR_PLAYER_INTERNAL;
6992 player->interrupted_by_resource = FALSE;
6993 /* acquire resources for video playing */
6994 if (mm_resource_manager_commit(player->resource_manager)
6995 != MM_RESOURCE_MANAGER_ERROR_NONE) {
6996 LOGE("could not acquire resources for video decoding\n");
6997 ret = MM_ERROR_PLAYER_INTERNAL;
7002 /* update codec info */
7003 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7004 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7005 player->videodec_linked = 1;
7013 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad* pad,
7014 GstCaps* caps, GstElementFactory* factory, gpointer data)
7016 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
7017 We are defining our own and will be removed when it actually exposed */
7019 GST_AUTOPLUG_SELECT_TRY,
7020 GST_AUTOPLUG_SELECT_EXPOSE,
7021 GST_AUTOPLUG_SELECT_SKIP
7022 } GstAutoplugSelectResult;
7024 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7025 mm_player_t* player = (mm_player_t*)data;
7027 gchar* factory_name = NULL;
7028 gchar* caps_str = NULL;
7029 const gchar* klass = NULL;
7032 factory_name = GST_OBJECT_NAME(factory);
7033 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7034 caps_str = gst_caps_to_string(caps);
7036 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7038 /* store type string */
7039 if (player->type == NULL) {
7040 player->type = gst_caps_to_string(caps);
7041 __mmplayer_update_content_type_info(player);
7044 /* filtering exclude keyword */
7045 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7046 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7047 LOGW("skipping [%s] by exculde keyword [%s]",
7048 factory_name, player->ini.exclude_element_keyword[idx]);
7050 result = GST_AUTOPLUG_SELECT_SKIP;
7055 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7056 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7057 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7058 factory_name, player->ini.unsupported_codec_keyword[idx]);
7059 result = GST_AUTOPLUG_SELECT_SKIP;
7064 /* exclude webm format */
7065 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7066 * because webm format is not supportable.
7067 * If webm is disabled in "autoplug-continue", there is no state change
7068 * failure or error because the decodebin will expose the pad directly.
7069 * It make MSL invoke _prepare_async_callback.
7070 * So, we need to disable webm format in "autoplug-select" */
7071 if (caps_str && strstr(caps_str, "webm")) {
7072 LOGW("webm is not supported");
7073 result = GST_AUTOPLUG_SELECT_SKIP;
7077 /* check factory class for filtering */
7078 /* NOTE : msl don't need to use image plugins.
7079 * So, those plugins should be skipped for error handling.
7081 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7082 LOGD("skipping [%s] by not required\n", factory_name);
7083 result = GST_AUTOPLUG_SELECT_SKIP;
7087 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7088 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7089 // TO CHECK : subtitle if needed, add subparse exception.
7090 LOGD("skipping parser/demuxer [%s] in es player by not required\n", factory_name);
7091 result = GST_AUTOPLUG_SELECT_SKIP;
7095 if (g_strrstr(factory_name, "mpegpsdemux")) {
7096 LOGD("skipping PS container - not support\n");
7097 result = GST_AUTOPLUG_SELECT_SKIP;
7101 if (g_strrstr(factory_name, "mssdemux"))
7102 player->smooth_streaming = TRUE;
7104 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7105 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7108 GstStructure *str = NULL;
7109 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7111 /* don't make video because of not required */
7112 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7113 (!player->set_mode.media_packet_video_stream)) {
7114 LOGD("no need video decoding, expose pad");
7115 result = GST_AUTOPLUG_SELECT_EXPOSE;
7119 /* get w/h for omx state-tune */
7120 /* FIXME: deprecated? */
7121 str = gst_caps_get_structure(caps, 0);
7122 gst_structure_get_int(str, "width", &width);
7125 if (player->v_stream_caps) {
7126 gst_caps_unref(player->v_stream_caps);
7127 player->v_stream_caps = NULL;
7130 player->v_stream_caps = gst_caps_copy(caps);
7131 LOGD("take caps for video state tune");
7132 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7136 if (g_strrstr(klass, "Codec/Decoder")) {
7137 if (__mmplayer_check_codec_info(player, klass, caps, factory_name) != MM_ERROR_NONE) {
7138 LOGD("skipping %s codec", factory_name);
7139 result = GST_AUTOPLUG_SELECT_SKIP;
7145 MMPLAYER_FREEIF(caps_str);
7151 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad* new_pad,
7154 //mm_player_t* player = (mm_player_t*)data;
7155 GstCaps* caps = NULL;
7157 LOGD("[Decodebin2] pad-removed signal\n");
7159 caps = gst_pad_query_caps(new_pad, NULL);
7161 gchar* caps_str = NULL;
7162 caps_str = gst_caps_to_string(caps);
7164 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7166 MMPLAYER_FREEIF(caps_str);
7167 gst_caps_unref(caps);
7172 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7174 mm_player_t* player = (mm_player_t*)data;
7175 GstIterator *iter = NULL;
7176 GValue item = { 0, };
7178 gboolean done = FALSE;
7179 gboolean is_all_drained = TRUE;
7182 MMPLAYER_RETURN_IF_FAIL(player);
7184 LOGD("__mmplayer_gst_decode_drained");
7186 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7187 LOGW("Fail to get cmd lock");
7191 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7192 !__mmplayer_verify_gapless_play_path(player)) {
7193 LOGD("decoding is finished.");
7194 __mmplayer_reset_gapless_state(player);
7195 MMPLAYER_CMD_UNLOCK(player);
7199 player->gapless.reconfigure = TRUE;
7201 /* check decodebin src pads whether they received EOS or not */
7202 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7205 switch (gst_iterator_next(iter, &item)) {
7206 case GST_ITERATOR_OK:
7207 pad = g_value_get_object(&item);
7208 if (pad && !GST_PAD_IS_EOS(pad)) {
7209 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7210 is_all_drained = FALSE;
7213 g_value_reset(&item);
7215 case GST_ITERATOR_RESYNC:
7216 gst_iterator_resync(iter);
7218 case GST_ITERATOR_ERROR:
7219 case GST_ITERATOR_DONE:
7224 g_value_unset(&item);
7225 gst_iterator_free(iter);
7227 if (!is_all_drained) {
7228 LOGD("Wait util the all pads get EOS.");
7229 MMPLAYER_CMD_UNLOCK(player);
7234 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7235 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7237 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7238 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7239 __mmplayer_deactivate_old_path(player);
7240 MMPLAYER_CMD_UNLOCK(player);
7246 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7248 mm_player_t* player = (mm_player_t*)data;
7249 const gchar* klass = NULL;
7250 gchar* factory_name = NULL;
7252 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7253 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7255 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s\n", klass, factory_name, GST_ELEMENT_NAME(element));
7257 if (__mmplayer_add_dump_buffer_probe(player, element))
7258 LOGD("add buffer probe");
7261 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7262 gchar* selected = NULL;
7263 selected = g_strdup(GST_ELEMENT_NAME(element));
7264 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7268 if (g_strrstr(klass, "Parser")) {
7269 gchar* selected = NULL;
7271 selected = g_strdup(factory_name);
7272 player->parsers = g_list_append(player->parsers, selected);
7275 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7276 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7277 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7279 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7280 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7282 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7283 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7284 "max-video-width", player->adaptive_info.limit.width,
7285 "max-video-height", player->adaptive_info.limit.height, NULL);
7287 } else if (g_strrstr(klass, "Demuxer")) {
7288 //LOGD("plugged element is demuxer. take it");
7289 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7290 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7293 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7294 int surface_type = 0;
7296 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7299 // to support trust-zone only
7300 if (g_strrstr(factory_name, "asfdemux")) {
7301 LOGD("set file-location %s\n", player->profile.uri);
7302 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7303 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7304 LOGD("[%s] output-format to legacyh264parse\n", "mssdemux");
7305 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7306 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7307 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7308 (__mmplayer_is_only_mp3_type(player->type))) {
7309 LOGD("[mpegaudioparse] set streaming pull mode.");
7310 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7312 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7313 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7316 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7317 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7318 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7320 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7321 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7323 if (!MMPLAYER_IS_HTTP_PD(player) &&
7324 ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7325 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7326 (MMPLAYER_IS_DASH_STREAMING(player)))) {
7327 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7328 __mm_player_streaming_set_multiqueue(player->streamer, element, player->ini.http_buffering_time, 1.0, player->ini.http_buffering_limit);
7329 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7338 __mmplayer_release_misc(mm_player_t* player)
7341 bool cur_mode = player->set_mode.rich_audio;
7344 MMPLAYER_RETURN_IF_FAIL(player);
7346 player->video_stream_cb = NULL;
7347 player->video_stream_cb_user_param = NULL;
7348 player->video_stream_prerolled = FALSE;
7350 player->audio_stream_render_cb = NULL;
7351 player->audio_stream_cb_user_param = NULL;
7352 player->audio_stream_sink_sync = false;
7354 player->video_stream_changed_cb = NULL;
7355 player->video_stream_changed_cb_user_param = NULL;
7357 player->audio_stream_changed_cb = NULL;
7358 player->audio_stream_changed_cb_user_param = NULL;
7360 player->sent_bos = FALSE;
7361 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7363 player->seek_state = MMPLAYER_SEEK_NONE;
7365 player->total_bitrate = 0;
7366 player->total_maximum_bitrate = 0;
7368 player->not_found_demuxer = 0;
7370 player->last_position = 0;
7371 player->duration = 0;
7372 player->http_content_size = 0;
7373 player->not_supported_codec = MISSING_PLUGIN_NONE;
7374 player->can_support_codec = FOUND_PLUGIN_NONE;
7375 player->pending_seek.is_pending = FALSE;
7376 player->pending_seek.pos = 0;
7377 player->msg_posted = FALSE;
7378 player->has_many_types = FALSE;
7379 player->is_subtitle_force_drop = FALSE;
7380 player->play_subtitle = FALSE;
7381 player->adjust_subtitle_pos = 0;
7382 player->last_multiwin_status = FALSE;
7383 player->has_closed_caption = FALSE;
7384 player->set_mode.media_packet_video_stream = false;
7385 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7386 memset(&player->set_mode, 0, sizeof(MMPlayerSetMode));
7388 player->set_mode.rich_audio = cur_mode;
7390 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7391 player->bitrate[i] = 0;
7392 player->maximum_bitrate[i] = 0;
7395 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7397 /* remove media stream cb(appsrc cb) */
7398 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7399 player->media_stream_buffer_status_cb[i] = NULL;
7400 player->media_stream_seek_data_cb[i] = NULL;
7401 player->buffer_cb_user_param[i] = NULL;
7402 player->seek_cb_user_param[i] = NULL;
7404 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7406 /* free memory related to audio effect */
7407 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7409 if (player->adaptive_info.var_list) {
7410 g_list_free_full(player->adaptive_info.var_list, g_free);
7411 player->adaptive_info.var_list = NULL;
7414 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7415 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7416 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7418 /* Reset video360 settings to their defaults in case if the pipeline is to be
7421 player->video360_metadata.is_spherical = -1;
7422 player->is_openal_plugin_used = FALSE;
7424 player->is_content_spherical = FALSE;
7425 player->is_video360_enabled = TRUE;
7426 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7427 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7428 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7429 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7430 player->video360_zoom = 1.0f;
7431 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7432 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7434 player->sound.rg_enable = false;
7436 __mmplayer_initialize_video_roi(player);
7441 __mmplayer_release_misc_post(mm_player_t* player)
7443 char *original_uri = NULL;
7446 /* player->pipeline is already released before. */
7448 MMPLAYER_RETURN_IF_FAIL(player);
7450 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7452 /* clean found parsers */
7453 if (player->parsers) {
7454 GList *parsers = player->parsers;
7455 for (; parsers; parsers = g_list_next(parsers)) {
7456 gchar *name = parsers->data;
7457 MMPLAYER_FREEIF(name);
7459 g_list_free(player->parsers);
7460 player->parsers = NULL;
7463 /* clean found audio decoders */
7464 if (player->audio_decoders) {
7465 GList *a_dec = player->audio_decoders;
7466 for (; a_dec; a_dec = g_list_next(a_dec)) {
7467 gchar *name = a_dec->data;
7468 MMPLAYER_FREEIF(name);
7470 g_list_free(player->audio_decoders);
7471 player->audio_decoders = NULL;
7474 /* clean the uri list except original uri */
7475 if (player->uri_info.uri_list) {
7476 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7478 if (player->attrs) {
7479 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7480 LOGD("restore original uri = %s\n", original_uri);
7482 if (mm_attrs_commit_all(player->attrs))
7483 LOGE("failed to commit the original uri.\n");
7486 GList *uri_list = player->uri_info.uri_list;
7487 for (; uri_list; uri_list = g_list_next(uri_list)) {
7488 gchar *uri = uri_list->data;
7489 MMPLAYER_FREEIF(uri);
7491 g_list_free(player->uri_info.uri_list);
7492 player->uri_info.uri_list = NULL;
7495 /* clear the audio stream buffer list */
7496 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7498 /* clear the video stream bo list */
7499 __mmplayer_video_stream_destroy_bo_list(player);
7500 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7502 if (player->profile.input_mem.buf) {
7503 free(player->profile.input_mem.buf);
7504 player->profile.input_mem.buf = NULL;
7506 player->profile.input_mem.len = 0;
7507 player->profile.input_mem.offset = 0;
7509 player->uri_info.uri_idx = 0;
7514 __mmplayer_check_subtitle(mm_player_t* player)
7516 MMHandleType attrs = 0;
7517 char *subtitle_uri = NULL;
7521 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7523 /* get subtitle attribute */
7524 attrs = MMPLAYER_GET_ATTRS(player);
7528 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7529 if (!subtitle_uri || !strlen(subtitle_uri))
7532 SECURE_LOGD("subtitle uri is %s[%d]", subtitle_uri, strlen(subtitle_uri));
7533 player->is_external_subtitle_present = TRUE;
7541 __mmplayer_cancel_eos_timer(mm_player_t* player)
7543 MMPLAYER_RETURN_IF_FAIL(player);
7545 if (player->eos_timer) {
7546 LOGD("cancel eos timer");
7547 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7548 player->eos_timer = 0;
7555 __mmplayer_add_sink(mm_player_t* player, GstElement* sink)
7559 MMPLAYER_RETURN_IF_FAIL(player);
7560 MMPLAYER_RETURN_IF_FAIL(sink);
7562 player->sink_elements =
7563 g_list_append(player->sink_elements, sink);
7569 __mmplayer_del_sink(mm_player_t* player, GstElement* sink)
7573 MMPLAYER_RETURN_IF_FAIL(player);
7574 MMPLAYER_RETURN_IF_FAIL(sink);
7576 player->sink_elements =
7577 g_list_remove(player->sink_elements, sink);
7583 __mmplayer_add_signal_connection(mm_player_t* player, GObject* object,
7584 MMPlayerSignalType type, const gchar* signal, GCallback cb_funct, gpointer u_data)
7586 MMPlayerSignalItem* item = NULL;
7589 MMPLAYER_RETURN_IF_FAIL(player);
7591 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7592 LOGE("invalid signal type [%d]", type);
7596 item = (MMPlayerSignalItem*)g_malloc(sizeof(MMPlayerSignalItem));
7598 LOGE("cannot connect signal [%s]", signal);
7603 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7604 player->signals[type] = g_list_append(player->signals[type], item);
7610 /* NOTE : be careful with calling this api. please refer to below glib comment
7611 * glib comment : Note that there is a bug in GObject that makes this function much
7612 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7613 * will no longer be called, but, the signal handler is not currently disconnected.
7614 * If the instance is itself being freed at the same time than this doesn't matter,
7615 * since the signal will automatically be removed, but if instance persists,
7616 * then the signal handler will leak. You should not remove the signal yourself
7617 * because in a future versions of GObject, the handler will automatically be
7620 * It's possible to work around this problem in a way that will continue to work
7621 * with future versions of GObject by checking that the signal handler is still
7622 * connected before disconnected it:
7624 * if (g_signal_handler_is_connected(instance, id))
7625 * g_signal_handler_disconnect(instance, id);
7628 __mmplayer_release_signal_connection(mm_player_t* player, MMPlayerSignalType type)
7630 GList* sig_list = NULL;
7631 MMPlayerSignalItem* item = NULL;
7635 MMPLAYER_RETURN_IF_FAIL(player);
7637 LOGD("release signals type : %d", type);
7639 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7640 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7641 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7642 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7643 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7644 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7648 sig_list = player->signals[type];
7650 for (; sig_list; sig_list = sig_list->next) {
7651 item = sig_list->data;
7653 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7654 if (g_signal_handler_is_connected(item->obj, item->sig))
7655 g_signal_handler_disconnect(item->obj, item->sig);
7658 MMPLAYER_FREEIF(item);
7661 g_list_free(player->signals[type]);
7662 player->signals[type] = NULL;
7669 int _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7671 mm_player_t* player = 0;
7672 int prev_display_surface_type = 0;
7673 void *prev_display_overlay = NULL;
7677 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7678 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7680 player = MM_PLAYER_CAST(handle);
7682 /* check video sinkbin is created */
7683 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7684 LOGE("Videosink is already created");
7685 return MM_ERROR_NONE;
7688 LOGD("videosink element is not yet ready");
7690 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7691 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7693 return MM_ERROR_INVALID_ARGUMENT;
7696 /* load previous attributes */
7697 if (player->attrs) {
7698 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7699 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7700 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7701 if (prev_display_surface_type == surface_type) {
7702 LOGD("incoming display surface type is same as previous one, do nothing..");
7704 return MM_ERROR_NONE;
7707 LOGE("failed to load attributes");
7709 return MM_ERROR_PLAYER_INTERNAL;
7712 /* videobin is not created yet, so we just set attributes related to display surface */
7713 LOGD("store display attribute for given surface type(%d)", surface_type);
7714 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7715 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7716 if (mm_attrs_commit_all(player->attrs)) {
7717 LOGE("failed to commit attribute");
7719 return MM_ERROR_PLAYER_INTERNAL;
7723 return MM_ERROR_NONE;
7726 /* Note : if silent is true, then subtitle would not be displayed. :*/
7727 int _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7729 mm_player_t* player = (mm_player_t*) hplayer;
7733 /* check player handle */
7734 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7736 player->set_mode.subtitle_off = silent;
7738 LOGD("subtitle is %s.\n", player->set_mode.subtitle_off ? "ON" : "OFF");
7742 return MM_ERROR_NONE;
7745 int _mmplayer_sync_subtitle_pipeline(mm_player_t* player)
7747 MMPlayerGstElement* mainbin = NULL;
7748 MMPlayerGstElement* textbin = NULL;
7749 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7750 GstState current_state = GST_STATE_VOID_PENDING;
7751 GstState element_state = GST_STATE_VOID_PENDING;
7752 GstState element_pending_state = GST_STATE_VOID_PENDING;
7754 GstEvent *event = NULL;
7755 int result = MM_ERROR_NONE;
7757 GstClock *curr_clock = NULL;
7758 GstClockTime base_time, start_time, curr_time;
7763 /* check player handle */
7764 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7766 player->pipeline->mainbin &&
7767 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7769 mainbin = player->pipeline->mainbin;
7770 textbin = player->pipeline->textbin;
7772 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7774 // sync clock with current pipeline
7775 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7776 curr_time = gst_clock_get_time(curr_clock);
7778 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7779 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7781 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7782 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7784 if (current_state > GST_STATE_READY) {
7785 // sync state with current pipeline
7786 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7787 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7788 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7790 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7791 if (GST_STATE_CHANGE_FAILURE == ret) {
7792 LOGE("fail to state change.\n");
7793 result = MM_ERROR_PLAYER_INTERNAL;
7798 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7799 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7802 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7803 gst_object_unref(curr_clock);
7806 // seek to current position
7807 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7808 result = MM_ERROR_PLAYER_INVALID_STATE;
7809 LOGE("gst_element_query_position failed, invalid state\n");
7813 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7814 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);
7816 __mmplayer_gst_send_event_to_sink(player, event);
7818 result = MM_ERROR_PLAYER_INTERNAL;
7819 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7823 /* sync state with current pipeline */
7824 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7825 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7826 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7828 return MM_ERROR_NONE;
7831 /* release text pipeline resource */
7832 player->textsink_linked = 0;
7834 /* release signal */
7835 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7837 /* release textbin with it's childs */
7838 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7839 MMPLAYER_FREEIF(player->pipeline->textbin);
7840 player->pipeline->textbin = NULL;
7842 /* release subtitle elem */
7843 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7844 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7850 __mmplayer_change_external_subtitle_language(mm_player_t* player, const char* filepath)
7852 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7853 GstState current_state = GST_STATE_VOID_PENDING;
7855 MMHandleType attrs = 0;
7856 MMPlayerGstElement* mainbin = NULL;
7857 MMPlayerGstElement* textbin = NULL;
7859 gchar* subtitle_uri = NULL;
7860 int result = MM_ERROR_NONE;
7861 const gchar *charset = NULL;
7865 /* check player handle */
7866 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7868 player->pipeline->mainbin &&
7869 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7870 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7872 mainbin = player->pipeline->mainbin;
7873 textbin = player->pipeline->textbin;
7875 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7876 if (current_state < GST_STATE_READY) {
7877 result = MM_ERROR_PLAYER_INVALID_STATE;
7878 LOGE("Pipeline is not in proper state\n");
7882 attrs = MMPLAYER_GET_ATTRS(player);
7884 LOGE("cannot get content attribute\n");
7885 result = MM_ERROR_PLAYER_INTERNAL;
7889 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7890 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7891 LOGE("subtitle uri is not proper filepath\n");
7892 result = MM_ERROR_PLAYER_INVALID_URI;
7896 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7897 LOGE("failed to get storage info of subtitle path");
7898 result = MM_ERROR_PLAYER_INVALID_URI;
7902 LOGD("old subtitle file path is [%s]\n", subtitle_uri);
7903 LOGD("new subtitle file path is [%s]\n", filepath);
7905 if (!strcmp(filepath, subtitle_uri)) {
7906 LOGD("No need to swtich subtitle, as input filepath is same as current filepath\n");
7909 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7910 if (mm_attrs_commit_all(player->attrs)) {
7911 LOGE("failed to commit.\n");
7916 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7917 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7918 player->subtitle_language_list = NULL;
7919 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7921 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7922 if (ret != GST_STATE_CHANGE_SUCCESS) {
7923 LOGE("failed to change state of textbin to READY");
7924 result = MM_ERROR_PLAYER_INTERNAL;
7928 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7929 if (ret != GST_STATE_CHANGE_SUCCESS) {
7930 LOGE("failed to change state of subparse to READY");
7931 result = MM_ERROR_PLAYER_INTERNAL;
7935 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7936 if (ret != GST_STATE_CHANGE_SUCCESS) {
7937 LOGE("failed to change state of filesrc to READY");
7938 result = MM_ERROR_PLAYER_INTERNAL;
7942 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7944 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7946 charset = util_get_charset(filepath);
7948 LOGD("detected charset is %s\n", charset);
7949 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7952 result = _mmplayer_sync_subtitle_pipeline(player);
7959 /* API to switch between external subtitles */
7960 int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filepath)
7962 int result = MM_ERROR_NONE;
7963 mm_player_t* player = (mm_player_t*)hplayer;
7968 /* check player handle */
7969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7971 /* filepath can be null in idle state */
7973 /* check file path */
7974 if ((path = strstr(filepath, "file://")))
7975 result = util_exist_file_path(path + 7);
7977 result = util_exist_file_path(filepath);
7979 if (result != MM_ERROR_NONE) {
7980 LOGE("invalid subtitle path 0x%X", result);
7981 return result; /* file not found or permission denied */
7985 if (!player->pipeline) {
7987 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7988 if (mm_attrs_commit_all(player->attrs)) {
7989 LOGE("failed to commit"); /* subtitle path will not be created */
7990 return MM_ERROR_PLAYER_INTERNAL;
7993 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7994 /* check filepath */
7995 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7997 if (!__mmplayer_check_subtitle(player)) {
7998 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7999 if (mm_attrs_commit_all(player->attrs)) {
8000 LOGE("failed to commit");
8001 return MM_ERROR_PLAYER_INTERNAL;
8004 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8005 LOGE("fail to create text pipeline");
8006 return MM_ERROR_PLAYER_INTERNAL;
8009 result = _mmplayer_sync_subtitle_pipeline(player);
8011 result = __mmplayer_change_external_subtitle_language(player, filepath);
8014 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8015 player->is_external_subtitle_added_now = TRUE;
8017 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8018 if (!player->subtitle_language_list) {
8019 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8020 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8021 LOGW("subtitle language list is not updated yet");
8023 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8031 __mmplayer_change_selector_pad(mm_player_t* player, MMPlayerTrackType type, int index)
8033 int result = MM_ERROR_NONE;
8034 gchar* change_pad_name = NULL;
8035 GstPad* sinkpad = NULL;
8036 MMPlayerGstElement* mainbin = NULL;
8037 enum MainElementID elem_idx = MMPLAYER_M_NUM;
8038 GstCaps* caps = NULL;
8039 gint total_track_num = 0;
8043 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8044 MM_ERROR_PLAYER_NOT_INITIALIZED);
8046 LOGD("Change Track(%d) to %d\n", type, index);
8048 mainbin = player->pipeline->mainbin;
8050 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8051 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8052 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8053 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8055 /* Changing Video Track is not supported. */
8056 LOGE("Track Type Error\n");
8060 if (mainbin[elem_idx].gst == NULL) {
8061 result = MM_ERROR_PLAYER_NO_OP;
8062 LOGD("Req track doesn't exist\n");
8066 total_track_num = player->selector[type].total_track_num;
8067 if (total_track_num <= 0) {
8068 result = MM_ERROR_PLAYER_NO_OP;
8069 LOGD("Language list is not available \n");
8073 if ((index < 0) || (index >= total_track_num)) {
8074 result = MM_ERROR_INVALID_ARGUMENT;
8075 LOGD("Not a proper index : %d \n", index);
8079 /*To get the new pad from the selector*/
8080 change_pad_name = g_strdup_printf("sink_%u", index);
8081 if (change_pad_name == NULL) {
8082 result = MM_ERROR_PLAYER_INTERNAL;
8083 LOGD("Pad does not exists\n");
8087 LOGD("new active pad name: %s\n", change_pad_name);
8089 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8090 if (sinkpad == NULL) {
8091 LOGD("sinkpad is NULL");
8092 result = MM_ERROR_PLAYER_INTERNAL;
8096 LOGD("Set Active Pad - %s:%s\n", GST_DEBUG_PAD_NAME(sinkpad));
8097 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8099 caps = gst_pad_get_current_caps(sinkpad);
8100 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8103 gst_object_unref(sinkpad);
8105 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8106 __mmplayer_set_audio_attrs(player, caps);
8110 MMPLAYER_FREEIF(change_pad_name);
8114 int _mmplayer_change_track_language(MMHandleType hplayer, MMPlayerTrackType type, int index)
8116 int result = MM_ERROR_NONE;
8117 mm_player_t* player = NULL;
8118 MMPlayerGstElement* mainbin = NULL;
8120 gint current_active_index = 0;
8122 GstState current_state = GST_STATE_VOID_PENDING;
8123 GstEvent* event = NULL;
8128 player = (mm_player_t*)hplayer;
8129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8131 if (!player->pipeline) {
8132 LOGE("Track %d pre setting -> %d\n", type, index);
8134 player->selector[type].active_pad_index = index;
8138 mainbin = player->pipeline->mainbin;
8140 current_active_index = player->selector[type].active_pad_index;
8142 /*If index is same as running index no need to change the pad*/
8143 if (current_active_index == index)
8146 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8147 result = MM_ERROR_PLAYER_INVALID_STATE;
8151 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8152 if (current_state < GST_STATE_PAUSED) {
8153 result = MM_ERROR_PLAYER_INVALID_STATE;
8154 LOGW("Pipeline not in porper state\n");
8158 result = __mmplayer_change_selector_pad(player, type, index);
8159 if (result != MM_ERROR_NONE) {
8160 LOGE("change selector pad error\n");
8164 player->selector[type].active_pad_index = index;
8166 if (current_state == GST_STATE_PLAYING) {
8167 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);
8169 __mmplayer_gst_send_event_to_sink(player, event);
8171 result = MM_ERROR_PLAYER_INTERNAL;
8180 int _mmplayer_get_subtitle_silent(MMHandleType hplayer, int* silent)
8182 mm_player_t* player = (mm_player_t*) hplayer;
8186 /* check player handle */
8187 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8189 *silent = player->set_mode.subtitle_off;
8191 LOGD("subtitle is %s.\n", silent ? "ON" : "OFF");
8195 return MM_ERROR_NONE;
8199 __mmplayer_add_dump_buffer_probe(mm_player_t *player, GstElement *element)
8201 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8202 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8204 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8205 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8209 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8210 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8211 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8212 mm_player_dump_t *dump_s;
8213 dump_s = g_malloc(sizeof(mm_player_dump_t));
8215 if (dump_s == NULL) {
8216 LOGE("malloc fail");
8220 dump_s->dump_element_file = NULL;
8221 dump_s->dump_pad = NULL;
8222 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8224 if (dump_s->dump_pad) {
8225 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN*2);
8226 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]);
8227 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8228 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);
8229 /* add list for removed buffer probe and close FILE */
8230 player->dump_list = g_list_append(player->dump_list, dump_s);
8231 LOGD("%s sink pad added buffer probe for dump", factory_name);
8236 LOGE("failed to get %s sink pad added", factory_name);
8243 static GstPadProbeReturn
8244 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8246 FILE *dump_data = (FILE *) u_data;
8248 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8249 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8251 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, FALSE);
8253 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8255 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8257 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8259 return GST_PAD_PROBE_OK;
8263 __mmplayer_release_dump_list(GList *dump_list)
8266 GList *d_list = dump_list;
8267 for (; d_list; d_list = g_list_next(d_list)) {
8268 mm_player_dump_t *dump_s = d_list->data;
8269 if (dump_s->dump_pad) {
8270 if (dump_s->probe_handle_id)
8271 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8273 if (dump_s->dump_element_file) {
8274 fclose(dump_s->dump_element_file);
8275 dump_s->dump_element_file = NULL;
8277 MMPLAYER_FREEIF(dump_s);
8279 g_list_free(dump_list);
8285 _mmplayer_has_closed_caption(MMHandleType hplayer, bool* exist)
8287 mm_player_t* player = (mm_player_t*) hplayer;
8291 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8292 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8294 *exist = player->has_closed_caption;
8298 return MM_ERROR_NONE;
8301 void _mm_player_video_stream_internal_buffer_unref(void *buffer)
8305 // LOGD("unref internal gst buffer %p", buffer);
8306 gst_buffer_unref((GstBuffer *)buffer);
8312 int _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8314 mm_player_t* player = (mm_player_t*) hplayer;
8318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8319 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8321 if (MMPLAYER_IS_HTTP_PD(player))
8322 /* consider the timeout both download pipeline and playback pipeline */
8323 *timeout = player->ini.live_state_change_timeout + PLAYER_PD_STATE_CHANGE_TIME;
8324 else if (MMPLAYER_IS_STREAMING(player))
8325 *timeout = player->ini.live_state_change_timeout;
8327 *timeout = player->ini.localplayback_state_change_timeout;
8329 LOGD("timeout = %d\n", *timeout);
8332 return MM_ERROR_NONE;
8335 int _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8337 mm_player_t* player = (mm_player_t*) hplayer;
8341 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8342 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8344 *num = player->video_num_buffers;
8345 *extra_num = player->video_extra_num_buffers;
8347 LOGD("state %d, num %d(%d)\n", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8350 return MM_ERROR_NONE;
8354 __mmplayer_initialize_storage_info(mm_player_t* player, MMPlayerPathType path_type)
8358 MMPLAYER_RETURN_IF_FAIL(player);
8360 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8362 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8363 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8364 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8365 player->storage_info[i].id = -1;
8366 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8368 if (path_type != MMPLAYER_PATH_MAX)
8376 int _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8378 int ret = MM_ERROR_NONE;
8379 mm_player_t* player = (mm_player_t*)hplayer;
8380 MMMessageParamType msg_param = {0, };
8383 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8385 LOGW("state changed storage %d:%d", id, state);
8387 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8388 return MM_ERROR_NONE;
8390 /* FIXME: text path should be handled seperately. */
8391 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8392 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL) && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8393 LOGW("external storage is removed");
8395 if (player->msg_posted == FALSE) {
8396 memset(&msg_param, 0, sizeof(MMMessageParamType));
8397 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8398 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8399 player->msg_posted = TRUE;
8402 /* unrealize the player */
8403 ret = _mmplayer_unrealize(hplayer);
8404 if (ret != MM_ERROR_NONE)
8405 LOGE("failed to unrealize");
8412 int _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8414 int ret = MM_ERROR_NONE;
8415 mm_player_t* player = (mm_player_t*) hplayer;
8416 int idx = 0, total = 0;
8417 gchar *result = NULL, *tmp = NULL;
8420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8421 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8423 total = *num = g_list_length(player->adaptive_info.var_list);
8425 LOGW("There is no stream variant info.");
8429 result = g_strdup("");
8430 for (idx = 0 ; idx < total ; idx++) {
8431 VariantData *v_data = NULL;
8432 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8435 gchar data[64] = {0};
8436 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8438 tmp = g_strconcat(result, data, NULL);
8442 LOGW("There is no variant data in %d", idx);
8447 *var_info = (char *)result;
8449 LOGD("variant info %d:%s", *num, *var_info);
8454 int _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8456 int ret = MM_ERROR_NONE;
8457 mm_player_t* player = (mm_player_t*) hplayer;
8460 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8462 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8464 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8465 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8466 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8468 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8469 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8470 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8471 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8473 /* FIXME: seek to current position for applying new variant limitation */
8481 int _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8483 int ret = MM_ERROR_NONE;
8484 mm_player_t* player = (mm_player_t*) hplayer;
8487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8488 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8490 *bandwidth = player->adaptive_info.limit.bandwidth;
8491 *width = player->adaptive_info.limit.width;
8492 *height = player->adaptive_info.limit.height;
8494 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8500 int _mmplayer_set_streaming_buffering_time(MMHandleType hplayer, int buffer_ms, int rebuffer_ms)
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);
8508 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_NULL)
8509 LOGW("buffer_ms will not be applied.");
8512 LOGD("set buffering time %d ms / %d ms", buffer_ms, rebuffer_ms);
8514 if (player->streamer == NULL) {
8515 player->streamer = __mm_player_streaming_create();
8516 __mm_player_streaming_initialize(player->streamer);
8520 player->streamer->buffering_req.prebuffer_time = buffer_ms;
8522 if (rebuffer_ms >= 0)
8523 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
8530 int _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *buffer_ms, int *rebuffer_ms)
8532 int ret = MM_ERROR_NONE;
8533 mm_player_t* player = (mm_player_t*) hplayer;
8536 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8537 MMPLAYER_RETURN_VAL_IF_FAIL(buffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8539 if (player->streamer == NULL) {
8540 player->streamer = __mm_player_streaming_create();
8541 __mm_player_streaming_initialize(player->streamer);
8544 *buffer_ms = player->streamer->buffering_req.prebuffer_time;
8545 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8547 LOGD("buffering time %d ms / %d ms", *buffer_ms, *rebuffer_ms);
8553 int _mmplayer_set_codec_type(MMHandleType hplayer, MMPlayerStreamType stream_type, MMPlayerVideoCodecType codec_type)
8555 #define IDX_FIRST_SW_CODEC 0
8556 mm_player_t* player = (mm_player_t*) hplayer;
8557 const char* attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8558 MMHandleType attrs = 0;
8561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8563 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8564 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8565 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8567 switch (stream_type) {
8568 case MM_PLAYER_STREAM_TYPE_AUDIO:
8569 /* to support audio codec selection, codec info have to be added in ini file as below.
8570 audio codec element hw = xxxx
8571 audio codec element sw = avdec */
8572 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8573 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8574 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8575 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8576 LOGE("There is no audio codec info for codec_type %d", codec_type);
8577 return MM_ERROR_PLAYER_NO_OP;
8580 case MM_PLAYER_STREAM_TYPE_VIDEO:
8581 /* to support video codec selection, codec info have to be added in ini file as below.
8582 video codec element hw = omx
8583 video codec element sw = avdec */
8584 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8585 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8586 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8587 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8588 LOGE("There is no video codec info for codec_type %d", codec_type);
8589 return MM_ERROR_PLAYER_NO_OP;
8593 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8594 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8598 LOGD("update %s codec_type to %d", attr_name, codec_type);
8600 attrs = MMPLAYER_GET_ATTRS(player);
8601 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8603 if (mm_attrs_commit_all(player->attrs)) {
8604 LOGE("failed to commit codec_type attributes");
8605 return MM_ERROR_PLAYER_INTERNAL;
8609 return MM_ERROR_NONE;
8613 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8615 mm_player_t* player = (mm_player_t*) hplayer;
8616 GstElement* rg_vol_element = NULL;
8620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8622 player->sound.rg_enable = enabled;
8624 /* just hold rgvolume enable value if pipeline is not ready */
8625 if (!player->pipeline || !player->pipeline->audiobin) {
8626 LOGD("pipeline is not ready. holding rgvolume enable value\n");
8627 return MM_ERROR_NONE;
8630 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8632 if (!rg_vol_element) {
8633 LOGD("rgvolume element is not created");
8634 return MM_ERROR_PLAYER_INTERNAL;
8638 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8640 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8644 return MM_ERROR_NONE;
8648 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8650 mm_player_t* player = (mm_player_t*) hplayer;
8651 GstElement* rg_vol_element = NULL;
8652 gboolean enable = FALSE;
8656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8657 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8659 /* just hold enable_rg value if pipeline is not ready */
8660 if (!player->pipeline || !player->pipeline->audiobin) {
8661 LOGD("pipeline is not ready. holding rgvolume value (%d)\n", player->sound.rg_enable);
8662 *enabled = player->sound.rg_enable;
8663 return MM_ERROR_NONE;
8666 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8668 if (!rg_vol_element) {
8669 LOGD("rgvolume element is not created");
8670 return MM_ERROR_PLAYER_INTERNAL;
8673 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8678 return MM_ERROR_NONE;
8682 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8684 mm_player_t* player = (mm_player_t*) hplayer;
8685 MMHandleType attrs = 0;
8686 void *handle = NULL;
8687 int ret = MM_ERROR_NONE;
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8693 attrs = MMPLAYER_GET_ATTRS(player);
8694 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8696 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8698 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8699 return MM_ERROR_PLAYER_INTERNAL;
8702 player->video_roi.scale_x = scale_x;
8703 player->video_roi.scale_y = scale_y;
8704 player->video_roi.scale_width = scale_width;
8705 player->video_roi.scale_height = scale_height;
8707 /* check video sinkbin is created */
8708 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8709 return MM_ERROR_NONE;
8711 if (!gst_video_overlay_set_video_roi_area(
8712 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8713 scale_x, scale_y, scale_width, scale_height))
8714 ret = MM_ERROR_PLAYER_INTERNAL;
8716 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8717 scale_x, scale_y, scale_width, scale_height);
8725 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8727 mm_player_t* player = (mm_player_t*) hplayer;
8728 int ret = MM_ERROR_NONE;
8732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8735 *scale_x = player->video_roi.scale_x;
8736 *scale_y = player->video_roi.scale_y;
8737 *scale_width = player->video_roi.scale_width;
8738 *scale_height = player->video_roi.scale_height;
8740 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8741 *scale_x, *scale_y, *scale_width, *scale_height);
8747 __mmplayer_update_duration_attrs(mm_player_t *player, MMHandleType attrs)
8749 gboolean ret = FALSE;
8750 gint64 dur_nsec = 0;
8751 LOGD("try to update duration");
8753 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8754 player->duration = dur_nsec;
8755 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8759 if (player->duration < 0) {
8760 LOGW("duration is Non-Initialized !!!");
8761 player->duration = 0;
8764 /* update streaming service type */
8765 player->streaming_type = __mmplayer_get_stream_service_type(player);
8767 /* check duration is OK */
8768 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player)) {
8769 /* FIXIT : find another way to get duration here. */
8770 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8777 __mmplayer_update_audio_attrs(mm_player_t *player, MMHandleType attrs)
8779 /* update audio params
8780 NOTE : We need original audio params and it can be only obtained from src pad of audio
8781 decoder. Below code only valid when we are not using 'resampler' just before
8782 'audioconverter'. */
8783 GstCaps *caps_a = NULL;
8785 gint samplerate = 0, channels = 0;
8786 GstStructure* p = NULL;
8788 LOGD("try to update audio attrs");
8790 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8791 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8793 pad = gst_element_get_static_pad(
8794 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8797 LOGW("failed to get pad from audiosink");
8801 caps_a = gst_pad_get_current_caps(pad);
8804 LOGW("not ready to get audio caps");
8805 gst_object_unref(pad);
8809 p = gst_caps_get_structure(caps_a, 0);
8811 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8813 gst_structure_get_int(p, "rate", &samplerate);
8814 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8816 gst_structure_get_int(p, "channels", &channels);
8817 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8819 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8821 gst_caps_unref(caps_a);
8822 gst_object_unref(pad);
8828 __mmplayer_update_video_attrs(mm_player_t *player, MMHandleType attrs)
8830 LOGD("try to update video attrs");
8832 GstCaps *caps_v = NULL;
8836 GstStructure* p = NULL;
8838 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8839 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8841 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8843 LOGD("no videosink sink pad");
8847 caps_v = gst_pad_get_current_caps(pad);
8848 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8849 if (!caps_v && player->v_stream_caps) {
8850 caps_v = player->v_stream_caps;
8851 gst_caps_ref(caps_v);
8855 LOGD("no negitiated caps from videosink");
8856 gst_object_unref(pad);
8860 p = gst_caps_get_structure(caps_v, 0);
8861 gst_structure_get_int(p, "width", &width);
8862 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8864 gst_structure_get_int(p, "height", &height);
8865 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8867 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8869 SECURE_LOGD("width : %d height : %d", width, height);
8871 gst_caps_unref(caps_v);
8872 gst_object_unref(pad);
8875 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8876 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8883 __mmplayer_update_bitrate_attrs(mm_player_t *player, MMHandleType attrs)
8885 gboolean ret = FALSE;
8886 guint64 data_size = 0;
8890 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8891 if (!player->duration)
8894 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8895 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8896 if (stat(path, &sb) == 0)
8897 data_size = (guint64)sb.st_size;
8899 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8900 data_size = player->http_content_size;
8903 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8906 guint64 bitrate = 0;
8907 guint64 msec_dur = 0;
8909 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8911 bitrate = data_size * 8 * 1000 / msec_dur;
8912 SECURE_LOGD("file size : %u, video bitrate = %llu", data_size, bitrate);
8913 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
8917 LOGD("player duration is less than 0");
8921 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8922 if (player->total_bitrate) {
8923 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
8931 __mmplayer_copy_uri_and_set_type(MMPlayerParseProfile* data, const char *uri, int uri_type)
8933 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8934 data->uri_type = uri_type;
8937 __mmplayer_set_mem_uri(MMPlayerParseProfile* data, char *path, void *param)
8939 int ret = MM_ERROR_PLAYER_INVALID_URI;
8941 char *buffer = NULL;
8942 char *seperator = strchr(path, ',');
8943 char ext[100] = {0,}, size[100] = {0,};
8946 if ((buffer = strstr(path, "ext="))) {
8947 buffer += strlen("ext=");
8949 if (strlen(buffer)) {
8950 strncpy(ext, buffer, 99);
8952 if ((seperator = strchr(ext, ','))
8953 || (seperator = strchr(ext, ' '))
8954 || (seperator = strchr(ext, '\0'))) {
8955 seperator[0] = '\0';
8960 if ((buffer = strstr(path, "size="))) {
8961 buffer += strlen("size=");
8963 if (strlen(buffer) > 0) {
8964 strncpy(size, buffer, 99);
8966 if ((seperator = strchr(size, ','))
8967 || (seperator = strchr(size, ' '))
8968 || (seperator = strchr(size, '\0'))) {
8969 seperator[0] = '\0';
8972 mem_size = atoi(size);
8977 LOGD("ext: %s, mem_size: %d, mmap(param): %p\n", ext, mem_size, param);
8979 if (mem_size && param) {
8980 if (data->input_mem.buf)
8981 free(data->input_mem.buf);
8982 data->input_mem.buf = malloc(mem_size);
8984 if (data->input_mem.buf) {
8985 memcpy(data->input_mem.buf, param, mem_size);
8986 data->input_mem.len = mem_size;
8987 ret = MM_ERROR_NONE;
8989 LOGE("failed to alloc mem %d", mem_size);
8990 ret = MM_ERROR_PLAYER_INTERNAL;
8993 data->input_mem.offset = 0;
8994 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9001 __mmplayer_set_file_uri(MMPlayerParseProfile* data, const char *uri)
9003 gchar *location = NULL;
9006 int ret = MM_ERROR_NONE;
9008 if ((path = strstr(uri, "file://"))) {
9009 location = g_filename_from_uri(uri, NULL, &err);
9010 if (!location || (err != NULL)) {
9011 LOGE("Invalid URI '%s' for filesrc: %s", path,
9012 (err != NULL) ? err->message : "unknown error");
9018 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9019 return MM_ERROR_PLAYER_INVALID_URI;
9021 LOGD("path from uri: %s", location);
9024 path = (location != NULL) ? (location) : ((char *)uri);
9027 ret = util_exist_file_path(path);
9029 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9030 if (ret == MM_ERROR_NONE) {
9031 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9032 if (util_is_sdp_file(path)) {
9033 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc\n");
9034 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9036 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9038 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9039 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9041 LOGE("invalid uri, could not play..\n");
9042 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9051 static MMPlayerVideoStreamDataType*
9052 __mmplayer_create_stream_from_pad(GstPad *pad)
9054 GstCaps *caps = NULL;
9055 GstStructure *structure = NULL;
9056 unsigned int fourcc = 0;
9057 const gchar *string_format = NULL;
9058 MMPlayerVideoStreamDataType *stream = NULL;
9060 MMPixelFormatType format;
9062 caps = gst_pad_get_current_caps(pad);
9064 LOGE("Caps is NULL.");
9068 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9069 structure = gst_caps_get_structure(caps, 0);
9070 gst_structure_get_int(structure, "width", &width);
9071 gst_structure_get_int(structure, "height", &height);
9072 string_format = gst_structure_get_string(structure, "format");
9074 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9075 format = util_get_pixtype(fourcc);
9076 gst_caps_unref(caps);
9079 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9080 LOGE("Wrong condition!!");
9084 stream = (MMPlayerVideoStreamDataType *)g_malloc0(sizeof(MMPlayerVideoStreamDataType));
9086 LOGE("failed to alloc mem for video data");
9090 stream->width = width;
9091 stream->height = height;
9092 stream->format = format;
9098 __mmplayer_zerocopy_set_stride_elevation_bo(MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9100 unsigned int pitch = 0;
9102 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9104 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9105 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9106 stream->bo[index] = tbm_bo_ref(gst_tizen_memory_get_bos(mem, index));
9107 stream->stride[index] = pitch;
9108 stream->elevation[index] = stream->height;
9113 __mmplayer_swcodec_set_stride_elevation(MMPlayerVideoStreamDataType *stream)
9115 if (stream->format == MM_PIXEL_FORMAT_I420) {
9116 int ret = TBM_SURFACE_ERROR_NONE;
9117 tbm_surface_h surface;
9118 tbm_surface_info_s info;
9120 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9122 ret = tbm_surface_get_info(surface, &info);
9123 if (ret != TBM_SURFACE_ERROR_NONE) {
9124 tbm_surface_destroy(surface);
9128 tbm_surface_destroy(surface);
9129 stream->stride[0] = info.planes[0].stride;
9130 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9131 stream->stride[1] = info.planes[1].stride;
9132 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9133 stream->stride[2] = info.planes[2].stride;
9134 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9135 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9136 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9137 stream->stride[0] = stream->width * 4;
9138 stream->elevation[0] = stream->height;
9139 stream->bo_size = stream->stride[0] * stream->height;
9141 LOGE("Not support format %d", stream->format);
9149 __mmplayer_swcodec_set_bo(mm_player_t *player, MMPlayerVideoStreamDataType *stream, GstMemory *mem)
9151 tbm_bo_handle thandle;
9153 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9154 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9155 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9159 unsigned char *src = NULL;
9160 unsigned char *dest = NULL;
9161 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9163 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9165 LOGE("fail to gst_memory_map");
9169 if (!mapinfo.data) {
9170 LOGE("data pointer is wrong");
9174 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9175 if (!stream->bo[0]) {
9176 LOGE("Fail to tbm_bo_alloc!!");
9180 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9182 LOGE("thandle pointer is wrong");
9186 if (stream->format == MM_PIXEL_FORMAT_I420) {
9187 src_stride[0] = GST_ROUND_UP_4(stream->width);
9188 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9189 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9190 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9193 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9194 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9196 for (i = 0; i < 3; i++) {
9197 src = mapinfo.data + src_offset[i];
9198 dest = thandle.ptr + dest_offset[i];
9203 for (j = 0; j < stream->height >> k; j++) {
9204 memcpy(dest, src, stream->width>>k);
9205 src += src_stride[i];
9206 dest += stream->stride[i];
9209 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9210 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9212 LOGE("Not support format %d", stream->format);
9216 tbm_bo_unmap(stream->bo[0]);
9217 gst_memory_unmap(mem, &mapinfo);
9223 tbm_bo_unmap(stream->bo[0]);
9226 gst_memory_unmap(mem, &mapinfo);
9232 __mmplayer_set_pause_state(mm_player_t *player)
9234 if (player->sent_bos)
9237 /* rtsp case, get content attrs by GstMessage */
9238 if (MMPLAYER_IS_RTSP_STREAMING(player))
9241 /* it's first time to update all content attrs. */
9242 __mmplayer_update_content_attrs(player, ATTR_ALL);
9246 __mmplayer_set_playing_state(mm_player_t *player)
9248 gchar *audio_codec = NULL;
9250 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9251 /* initialize because auto resume is done well. */
9252 player->resumed_by_rewind = FALSE;
9253 player->playback_rate = 1.0;
9256 if (player->sent_bos)
9259 /* try to get content metadata */
9261 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9262 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9263 * legacy mmfw-player api
9265 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9267 if ((player->cmd == MMPLAYER_COMMAND_START)
9268 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9269 __mmplayer_handle_missed_plugin(player);
9272 /* check audio codec field is set or not
9273 * we can get it from typefinder or codec's caps.
9275 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9277 /* The codec format can't be sent for audio only case like amr, mid etc.
9278 * Because, parser don't make related TAG.
9279 * So, if it's not set yet, fill it with found data.
9282 if (g_strrstr(player->type, "audio/midi"))
9283 audio_codec = "MIDI";
9284 else if (g_strrstr(player->type, "audio/x-amr"))
9285 audio_codec = "AMR";
9286 else if (g_strrstr(player->type, "audio/mpeg")
9287 && !g_strrstr(player->type, "mpegversion= (int)1"))
9288 audio_codec = "AAC";
9290 audio_codec = "unknown";
9292 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9294 if (mm_attrs_commit_all(player->attrs))
9295 LOGE("failed to update attributes\n");
9297 LOGD("set audio codec type with caps\n");