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>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define DEFAULT_NUM_OF_V_OUT_BUFFER 3
94 #define PLAYER_DISPLAY_MODE_DST_ROI 5
96 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
98 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
99 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
100 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
101 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
103 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
104 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
106 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
108 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
109 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
110 #define DEFAULT_PCM_OUT_CHANNEL 2
112 /*---------------------------------------------------------------------------
113 | LOCAL CONSTANT DEFINITIONS: |
114 ---------------------------------------------------------------------------*/
116 /*---------------------------------------------------------------------------
117 | LOCAL DATA TYPE DEFINITIONS: |
118 ---------------------------------------------------------------------------*/
119 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
120 We are defining our own and will be removed when it actually exposed */
122 GST_AUTOPLUG_SELECT_TRY,
123 GST_AUTOPLUG_SELECT_EXPOSE,
124 GST_AUTOPLUG_SELECT_SKIP
125 } GstAutoplugSelectResult;
127 /*---------------------------------------------------------------------------
128 | GLOBAL VARIABLE DEFINITIONS: |
129 ---------------------------------------------------------------------------*/
131 /*---------------------------------------------------------------------------
132 | LOCAL VARIABLE DEFINITIONS: |
133 ---------------------------------------------------------------------------*/
134 static sound_stream_info_h stream_info;
136 /*---------------------------------------------------------------------------
137 | LOCAL FUNCTION PROTOTYPES: |
138 ---------------------------------------------------------------------------*/
139 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
142 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
143 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
144 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
146 static GstPadProbeReturn __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data);
147 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
148 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
149 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
150 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
151 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
152 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
153 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
154 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
155 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
156 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
158 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
159 static void __mmplayer_release_misc(mmplayer_t *player);
160 static void __mmplayer_release_misc_post(mmplayer_t *player);
161 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
162 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
163 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
164 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
167 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
168 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
169 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
170 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
171 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
172 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
173 static gpointer __mmplayer_gapless_play_thread(gpointer data);
174 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
175 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
176 static void __mmplayer_release_dump_list(GList *dump_list);
177 static int __mmplayer_gst_realize(mmplayer_t *player);
178 static int __mmplayer_gst_unrealize(mmplayer_t *player);
179 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
180 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
183 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
184 static void __mmplayer_activate_next_source(mmplayer_t *player, GstState target);
185 static void __mmplayer_check_pipeline(mmplayer_t *player);
186 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
187 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
188 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
189 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
190 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
191 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
192 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
193 static int __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res, void *user_data);
194 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
195 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
196 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
197 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
199 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
200 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
201 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
203 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
204 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
205 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
206 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
208 static void __mmplayer_set_pause_state(mmplayer_t *player);
209 static void __mmplayer_set_playing_state(mmplayer_t *player);
210 /*===========================================================================================
212 | FUNCTION DEFINITIONS |
214 ========================================================================================== */
218 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
222 count = gst_tag_list_get_tag_size(list, tag);
224 LOGD("count = %d", count);
226 for (i = 0; i < count; i++) {
229 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
230 if (!gst_tag_list_get_string_index(list, tag, i, &str))
231 g_assert_not_reached();
233 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
237 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
239 g_print(" : %s", str);
246 /* This function should be called after the pipeline goes PAUSED or higher
249 __mmplayer_update_content_attrs(mmplayer_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_value(player);
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");
323 __mmplayer_get_stream_service_type(mmplayer_t *player)
325 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
329 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
331 player->pipeline->mainbin &&
332 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
333 STREAMING_SERVICE_NONE);
335 /* streaming service type if streaming */
336 if (!MMPLAYER_IS_STREAMING(player))
337 return STREAMING_SERVICE_NONE;
339 streaming_type = (player->duration == 0) ?
340 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
342 switch (streaming_type) {
343 case STREAMING_SERVICE_LIVE:
344 LOGD("it's live streaming");
346 case STREAMING_SERVICE_VOD:
347 LOGD("it's vod streaming");
350 LOGE("should not get here");
356 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(mmplayer_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)", 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.");
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.");
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(mmplayer_t *player, mmplayer_command_state_e command)
435 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
436 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
440 //LOGD("incomming command : %d ", 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");
514 case MMPLAYER_COMMAND_STOP:
516 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
518 if (current_state == MM_PLAYER_STATE_READY)
521 /* need playing/paused state to stop */
522 if (current_state != MM_PLAYER_STATE_PLAYING &&
523 current_state != MM_PLAYER_STATE_PAUSED)
528 case MMPLAYER_COMMAND_PAUSE:
530 if (MMPLAYER_IS_LIVE_STREAMING(player))
533 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
534 goto NOT_COMPLETED_SEEK;
536 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
538 if (pending_state == MM_PLAYER_STATE_NONE) {
539 if (current_state == MM_PLAYER_STATE_PAUSED)
541 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
543 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
545 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
546 if (current_state == MM_PLAYER_STATE_PAUSED)
547 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
554 case MMPLAYER_COMMAND_RESUME:
556 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
557 goto NOT_COMPLETED_SEEK;
559 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
561 if (pending_state == MM_PLAYER_STATE_NONE) {
562 if (current_state == MM_PLAYER_STATE_PLAYING)
564 else if (current_state != MM_PLAYER_STATE_PAUSED)
566 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
568 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
569 LOGD("player is going to paused state, just change the pending state as playing");
579 player->cmd = command;
581 return MM_ERROR_NONE;
584 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
585 MMPLAYER_STATE_GET_NAME(current_state), command);
586 return MM_ERROR_PLAYER_INVALID_STATE;
589 LOGW("not completed seek");
590 return MM_ERROR_PLAYER_DOING_SEEK;
593 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
594 return MM_ERROR_PLAYER_NO_OP;
597 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
598 return MM_ERROR_PLAYER_NO_OP;
602 __mmplayer_gapless_play_thread(gpointer data)
604 mmplayer_t *player = (mmplayer_t *)data;
605 mmplayer_gst_element_t *mainbin = NULL;
607 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
609 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
610 while (!player->gapless_play_thread_exit) {
611 LOGD("gapless play thread started. waiting for signal.");
612 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
614 LOGD("reconfigure pipeline for gapless play.");
616 if (player->gapless_play_thread_exit) {
617 if (player->gapless.reconfigure) {
618 player->gapless.reconfigure = false;
619 MMPLAYER_PLAYBACK_UNLOCK(player);
621 LOGD("exiting gapless play thread");
625 mainbin = player->pipeline->mainbin;
627 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
628 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
629 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
630 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
631 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
633 __mmplayer_activate_next_source(player, GST_STATE_PLAYING);
635 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
641 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
643 GSource *source = NULL;
647 source = g_main_context_find_source_by_id(context, source_id);
648 if (source != NULL) {
649 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
650 g_source_destroy(source);
657 __mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
659 mmplayer_t *player = (mmplayer_t *)hplayer;
660 GstMessage *msg = NULL;
661 GQueue *queue = NULL;
664 MMPLAYER_RETURN_IF_FAIL(player);
666 /* disconnecting bus watch */
667 if (player->bus_watcher)
668 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
669 player->bus_watcher = 0;
671 /* destroy the gst bus msg thread */
672 if (player->bus_msg_thread) {
673 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
674 player->bus_msg_thread_exit = TRUE;
675 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
676 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
678 LOGD("gst bus msg thread exit.");
679 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
680 player->bus_msg_thread = NULL;
682 g_mutex_clear(&player->bus_msg_thread_mutex);
683 g_cond_clear(&player->bus_msg_thread_cond);
686 g_mutex_lock(&player->bus_msg_q_lock);
687 queue = player->bus_msg_q;
688 while (!g_queue_is_empty(queue)) {
689 msg = (GstMessage *)g_queue_pop_head(queue);
694 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
695 gst_message_unref(msg);
697 g_mutex_unlock(&player->bus_msg_q_lock);
703 __mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
705 GstElement *parent = NULL;
707 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
709 /* if we have no fakesink. this meas we are using decodebin which doesn'
710 t need to add extra fakesink */
711 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink, TRUE);
714 MMPLAYER_FSINK_LOCK(player);
719 /* get parent of fakesink */
720 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
722 LOGD("fakesink already removed");
726 gst_element_set_locked_state(fakesink->gst, TRUE);
728 /* setting the state to NULL never returns async
729 * so no need to wait for completion of state transiton
731 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
732 LOGE("fakesink state change failure!");
733 /* FIXIT : should I return here? or try to proceed to next? */
736 /* remove fakesink from it's parent */
737 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
738 LOGE("failed to remove fakesink");
740 gst_object_unref(parent);
745 gst_object_unref(parent);
747 LOGD("state-holder removed");
749 gst_element_set_locked_state(fakesink->gst, FALSE);
751 MMPLAYER_FSINK_UNLOCK(player);
756 gst_element_set_locked_state(fakesink->gst, FALSE);
758 MMPLAYER_FSINK_UNLOCK(player);
762 static GstPadProbeReturn
763 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
765 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
766 return GST_PAD_PROBE_OK;
770 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
772 gint64 stop_running_time = 0;
773 gint64 position_running_time = 0;
777 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
778 if ((player->gapless.update_segment[idx] == TRUE) ||
779 !(player->selector[idx].event_probe_id)) {
780 /* LOGW("[%d] skip", idx); */
784 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
786 gst_segment_to_running_time(&player->gapless.segment[idx],
787 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
788 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
790 gst_segment_to_running_time(&player->gapless.segment[idx],
791 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
793 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
795 gst_segment_to_running_time(&player->gapless.segment[idx],
796 GST_FORMAT_TIME, player->duration);
799 position_running_time =
800 gst_segment_to_running_time(&player->gapless.segment[idx],
801 GST_FORMAT_TIME, player->gapless.segment[idx].position);
803 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
804 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
806 GST_TIME_ARGS(stop_running_time),
807 GST_TIME_ARGS(position_running_time),
808 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
809 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
811 position_running_time = MAX(position_running_time, stop_running_time);
812 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
813 GST_FORMAT_TIME, player->gapless.segment[idx].start);
814 position_running_time = MAX(0, position_running_time);
815 position = MAX(position, position_running_time);
819 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
820 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
821 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
823 player->gapless.start_time[stream_type] += position;
829 static GstPadProbeReturn
830 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
832 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
833 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
834 mmplayer_t *player = (mmplayer_t *)data;
835 GstCaps *caps = NULL;
836 GstStructure *str = NULL;
837 const gchar *name = NULL;
838 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
839 gboolean caps_ret = TRUE;
841 if (GST_EVENT_IS_DOWNSTREAM(event) &&
842 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
843 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
844 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
845 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
847 } else if (GST_EVENT_IS_UPSTREAM(event) &&
848 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
852 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
856 if (strstr(name, "audio")) {
857 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
858 } else if (strstr(name, "video")) {
859 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
861 /* text track is not supportable */
862 LOGE("invalid name %s", name);
866 switch (GST_EVENT_TYPE(event)) {
869 /* in case of gapless, drop eos event not to send it to sink */
870 if (player->gapless.reconfigure && !player->msg_posted) {
871 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
872 ret = GST_PAD_PROBE_DROP;
876 case GST_EVENT_STREAM_START:
878 __mmplayer_gst_selector_update_start_time(player, stream_type);
881 case GST_EVENT_FLUSH_STOP:
883 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
884 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
885 player->gapless.start_time[stream_type] = 0;
888 case GST_EVENT_SEGMENT:
893 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
894 gst_event_copy_segment(event, &segment);
896 if (segment.format != GST_FORMAT_TIME)
899 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
900 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
901 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
902 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
903 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
904 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
906 /* keep the all the segment ev to cover the seeking */
907 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
908 player->gapless.update_segment[stream_type] = TRUE;
910 if (!player->gapless.running)
913 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
915 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
917 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
918 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
919 gst_event_unref(event);
920 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
926 gdouble proportion = 0.0;
927 GstClockTimeDiff diff = 0;
928 GstClockTime timestamp = 0;
929 gint64 running_time_diff = -1;
931 GstEvent *tmpev = NULL;
933 running_time_diff = player->gapless.segment[stream_type].base;
935 if (running_time_diff <= 0) /* don't need to adjust */
938 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
939 gst_event_unref(event);
941 if (timestamp < running_time_diff) {
942 LOGW("QOS event from previous group");
943 ret = GST_PAD_PROBE_DROP;
947 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
948 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
949 stream_type, GST_TIME_ARGS(timestamp),
950 GST_TIME_ARGS(running_time_diff),
951 GST_TIME_ARGS(timestamp - running_time_diff));
953 timestamp -= running_time_diff;
955 /* That case is invalid for QoS events */
956 if (diff < 0 && -diff > timestamp) {
957 LOGW("QOS event from previous group");
958 ret = GST_PAD_PROBE_DROP;
962 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
963 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
973 gst_caps_unref(caps);
977 /* create fakesink for audio or video path witout audiobin or videobin */
979 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
981 GstElement *pipeline = NULL;
982 GstElement *fakesink = NULL;
983 GstPad *sinkpad = NULL;
986 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
988 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
991 fakesink = gst_element_factory_make("fakesink", NULL);
992 if (fakesink == NULL) {
993 LOGE("failed to create fakesink");
997 /* store it as it's sink element */
998 __mmplayer_add_sink(player, fakesink);
1000 gst_bin_add(GST_BIN(pipeline), fakesink);
1003 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1005 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1007 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1008 LOGE("failed to link fakesink");
1009 gst_object_unref(GST_OBJECT(fakesink));
1013 if (strstr(name, "video")) {
1014 if (player->v_stream_caps) {
1015 gst_caps_unref(player->v_stream_caps);
1016 player->v_stream_caps = NULL;
1018 if (player->ini.set_dump_element_flag)
1019 __mmplayer_add_dump_buffer_probe(player, fakesink);
1022 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1023 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1027 gst_object_unref(GST_OBJECT(sinkpad));
1034 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1036 GstElement *pipeline = NULL;
1037 GstElement *selector = NULL;
1038 GstPad *srcpad = NULL;
1041 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1043 selector = gst_element_factory_make("input-selector", NULL);
1045 LOGE("failed to create input-selector");
1048 g_object_set(selector, "sync-streams", TRUE, NULL);
1050 player->pipeline->mainbin[elem_idx].id = elem_idx;
1051 player->pipeline->mainbin[elem_idx].gst = selector;
1053 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1055 srcpad = gst_element_get_static_pad(selector, "src");
1057 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1058 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1059 __mmplayer_gst_selector_blocked, NULL, NULL);
1060 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1061 __mmplayer_gst_selector_event_probe, player, NULL);
1063 gst_element_set_state(selector, GST_STATE_PAUSED);
1065 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1066 gst_bin_add(GST_BIN(pipeline), selector);
1068 gst_object_unref(GST_OBJECT(srcpad));
1075 __mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1077 mmplayer_t *player = (mmplayer_t *)data;
1078 GstElement *selector = NULL;
1079 GstCaps *caps = NULL;
1080 GstStructure *str = NULL;
1081 const gchar *name = NULL;
1082 GstPad *sinkpad = NULL;
1083 gboolean first_track = FALSE;
1084 gboolean caps_ret = TRUE;
1086 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1087 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1090 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1091 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1093 LOGD("pad-added signal handling");
1095 /* get mimetype from caps */
1096 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1100 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1101 /* LOGD("detected mimetype : %s", name); */
1103 if (strstr(name, "video")) {
1105 gchar *caps_str = NULL;
1107 caps_str = gst_caps_to_string(caps);
1108 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1109 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1110 player->set_mode.video_zc = true;
1112 MMPLAYER_FREEIF(caps_str);
1114 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1115 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1117 LOGD("surface type : %d", stype);
1119 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1120 __mmplayer_gst_create_sinkbin(elem, pad, player);
1124 /* in case of exporting video frame, it requires the 360 video filter.
1125 * it will be handled in _no_more_pads(). */
1126 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1127 __mmplayer_gst_make_fakesink(player, pad, name);
1131 LOGD("video selector is required");
1132 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1133 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1134 } else if (strstr(name, "audio")) {
1135 gint samplerate = 0;
1138 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1139 if (player->build_audio_offload)
1140 player->no_more_pad = TRUE; /* remove state holder */
1141 __mmplayer_gst_create_sinkbin(elem, pad, player);
1145 gst_structure_get_int(str, "rate", &samplerate);
1146 gst_structure_get_int(str, "channels", &channels);
1148 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1149 __mmplayer_gst_make_fakesink(player, pad, name);
1153 LOGD("audio selector is required");
1154 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1155 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1157 } else if (strstr(name, "text")) {
1158 LOGD("text selector is required");
1159 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1160 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1162 LOGE("invalid caps info");
1166 /* check selector and create it */
1167 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1168 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1173 LOGD("input-selector is already created.");
1177 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1179 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1181 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1182 LOGE("failed to link selector");
1183 gst_object_unref(GST_OBJECT(selector));
1188 LOGD("this track will be activated");
1189 g_object_set(selector, "active-pad", sinkpad, NULL);
1192 __mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1198 gst_caps_unref(caps);
1201 gst_object_unref(GST_OBJECT(sinkpad));
1209 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1211 GstPad *srcpad = NULL;
1214 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1216 LOGD("type %d", type);
1219 LOGD("there is no %d track", type);
1223 srcpad = gst_element_get_static_pad(selector, "src");
1225 LOGE("failed to get srcpad from selector");
1229 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1231 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1233 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1234 if (player->selector[type].block_id) {
1235 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1236 player->selector[type].block_id = 0;
1240 gst_object_unref(GST_OBJECT(srcpad));
1249 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1251 MMHandleType attrs = 0;
1252 gint active_index = 0;
1255 MMPLAYER_RETURN_IF_FAIL(player);
1257 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1259 /* change track to active pad */
1260 active_index = player->selector[type].active_pad_index;
1261 if ((active_index != DEFAULT_TRACK) &&
1262 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1263 LOGW("failed to change %d type track to %d", type, active_index);
1264 player->selector[type].active_pad_index = DEFAULT_TRACK;
1268 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1269 attrs = MMPLAYER_GET_ATTRS(player);
1271 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1272 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1274 if (mm_attrs_commit_all(attrs))
1275 LOGW("failed to commit attrs.");
1277 LOGW("cannot get content attribute");
1286 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1289 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1291 if (!audio_selector) {
1292 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1294 /* in case the source is changed, output can be changed. */
1295 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1296 LOGD("remove previous audiobin if it exist");
1298 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1299 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1301 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1302 MMPLAYER_FREEIF(player->pipeline->audiobin);
1305 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1306 __mmplayer_pipeline_complete(NULL, player);
1311 /* apply the audio track information */
1312 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1314 /* create audio sink path */
1315 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1316 LOGE("failed to create audio sink path");
1325 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1328 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1330 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1331 LOGD("text path is not supproted");
1335 /* apply the text track information */
1336 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1338 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1339 player->has_closed_caption = TRUE;
1341 /* create text decode path */
1342 player->no_more_pad = TRUE;
1344 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1345 LOGE("failed to create text sink path");
1354 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1356 gint64 dur_bytes = 0L;
1359 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1360 player->pipeline->mainbin && player->streamer, FALSE);
1362 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1363 LOGE("fail to get duration.");
1365 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1366 * use file information was already set on Q2 when it was created. */
1367 __mm_player_streaming_set_queue2(player->streamer,
1368 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1369 TRUE, /* use_buffering */
1370 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1371 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1378 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1380 mmplayer_t *player = NULL;
1381 GstElement *video_selector = NULL;
1382 GstElement *audio_selector = NULL;
1383 GstElement *text_selector = NULL;
1386 player = (mmplayer_t *)data;
1388 LOGD("no-more-pad signal handling");
1390 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1391 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1392 LOGW("player is shutting down");
1396 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1397 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1398 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1399 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1400 LOGE("failed to set queue2 buffering");
1405 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1406 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1407 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1409 if (!video_selector && !audio_selector && !text_selector) {
1410 LOGW("there is no selector");
1411 player->no_more_pad = TRUE;
1415 /* create video path followed by video-select */
1416 if (video_selector && !audio_selector && !text_selector)
1417 player->no_more_pad = TRUE;
1419 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1422 /* create audio path followed by audio-select */
1423 if (audio_selector && !text_selector)
1424 player->no_more_pad = TRUE;
1426 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1429 /* create text path followed by text-select */
1430 __mmplayer_create_text_sink_path(player, text_selector);
1433 if (player->gapless.reconfigure) {
1434 player->gapless.reconfigure = FALSE;
1435 MMPLAYER_PLAYBACK_UNLOCK(player);
1442 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1444 gboolean ret = FALSE;
1445 GstElement *pipeline = NULL;
1446 GstPad *sinkpad = NULL;
1449 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1450 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1452 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1454 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1456 LOGE("failed to get pad from sinkbin");
1462 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1463 LOGE("failed to link sinkbin for reusing");
1464 goto EXIT; /* exit either pass or fail */
1468 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1469 LOGE("failed to set state(READY) to sinkbin");
1474 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1475 LOGE("failed to add sinkbin to pipeline");
1480 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1481 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1486 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1487 LOGE("failed to set state(PAUSED) to sinkbin");
1496 gst_object_unref(GST_OBJECT(sinkpad));
1504 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1506 mmplayer_t *player = NULL;
1507 GstCaps *caps = NULL;
1508 gchar *caps_str = NULL;
1509 GstStructure *str = NULL;
1510 const gchar *name = NULL;
1511 GstElement *sinkbin = NULL;
1512 gboolean reusing = FALSE;
1513 gboolean caps_ret = TRUE;
1514 gchar *sink_pad_name = "sink";
1517 player = (mmplayer_t *)data;
1520 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1521 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1523 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1527 caps_str = gst_caps_to_string(caps);
1529 /* LOGD("detected mimetype : %s", name); */
1530 if (strstr(name, "audio")) {
1531 if (player->pipeline->audiobin == NULL) {
1532 const gchar *audio_format = gst_structure_get_string(str, "format");
1534 LOGD("original audio format %s", audio_format);
1535 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1538 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1539 LOGE("failed to create audiobin. continuing without audio");
1543 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1544 LOGD("creating audiobin success");
1547 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1548 LOGD("reusing audiobin");
1549 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
1551 } else if (strstr(name, "video")) {
1552 /* 1. zero copy is updated at _decode_pad_added()
1553 * 2. NULL surface type is handled in _decode_pad_added() */
1554 LOGD("zero copy %d", player->set_mode.video_zc);
1555 if (player->pipeline->videobin == NULL) {
1556 int surface_type = 0;
1557 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1558 LOGD("display_surface_type (%d)", surface_type);
1560 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY && player->video_overlay_resource == NULL) {
1561 LOGD("mark video overlay for acquire");
1562 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
1563 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
1564 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
1565 &player->video_overlay_resource)
1566 != MM_RESOURCE_MANAGER_ERROR_NONE) {
1567 LOGE("could not mark video_overlay resource for acquire");
1572 player->interrupted_by_resource = FALSE;
1574 if (mm_resource_manager_commit(player->resource_manager) !=
1575 MM_RESOURCE_MANAGER_ERROR_NONE) {
1576 LOGE("could not acquire resources for video playing");
1580 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1581 LOGE("failed to create videobin. continuing without video");
1585 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1586 LOGD("creating videosink bin success");
1589 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1590 LOGD("re-using videobin");
1591 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
1593 } else if (strstr(name, "text")) {
1594 if (player->pipeline->textbin == NULL) {
1595 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1596 LOGE("failed to create text sink bin. continuing without text");
1600 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1601 player->textsink_linked = 1;
1602 LOGD("creating textsink bin success");
1604 if (!player->textsink_linked) {
1605 LOGD("re-using textbin");
1607 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1608 player->textsink_linked = 1;
1610 /* linked textbin exist which means that the external subtitle path exist already */
1611 LOGW("ignoring internal subtutle since external subtitle is available");
1614 sink_pad_name = "text_sink";
1616 LOGW("unknown mime type %s, ignoring it", name);
1620 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1623 LOGD("[handle: %p] success to create and link sink bin", player);
1625 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1626 * streaming task. if the task blocked, then buffer will not flow to the next element
1627 *(autoplugging element). so this is special hack for streaming. please try to remove it
1629 /* dec stream count. we can remove fakesink if it's zero */
1630 if (player->num_dynamic_pad)
1631 player->num_dynamic_pad--;
1633 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1635 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1636 __mmplayer_pipeline_complete(NULL, player);
1640 MMPLAYER_FREEIF(caps_str);
1643 gst_caps_unref(caps);
1649 __mmplayer_get_property_value_for_rotation(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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(mmplayer_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);
1836 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1838 MMHandleType attrs = 0;
1839 void *handle = NULL;
1842 /* check video sinkbin is created */
1843 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1844 LOGW("There is no video sink");
1848 attrs = MMPLAYER_GET_ATTRS(player);
1849 MMPLAYER_RETURN_IF_FAIL(attrs);
1850 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1852 gst_video_overlay_set_video_roi_area(
1853 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1854 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1855 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1856 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1861 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1863 MMHandleType attrs = 0;
1864 void *handle = NULL;
1868 int win_roi_width = 0;
1869 int win_roi_height = 0;
1872 /* check video sinkbin is created */
1873 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1874 LOGW("There is no video sink");
1878 attrs = MMPLAYER_GET_ATTRS(player);
1879 MMPLAYER_RETURN_IF_FAIL(attrs);
1881 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1884 /* It should be set after setting window */
1885 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1886 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1887 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1888 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1890 /* After setting window handle, set display roi area */
1891 gst_video_overlay_set_display_roi_area(
1892 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1893 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1894 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1895 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1900 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1902 MMHandleType attrs = 0;
1903 void *handle = NULL;
1905 /* check video sinkbin is created */
1906 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1909 attrs = MMPLAYER_GET_ATTRS(player);
1910 MMPLAYER_RETURN_IF_FAIL(attrs);
1912 /* common case if using overlay surface */
1913 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1916 /* default is using wl_surface_id */
1917 unsigned int wl_surface_id = 0;
1918 wl_surface_id = *(int *)handle;
1919 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1920 gst_video_overlay_set_wl_window_wl_surface_id(
1921 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1924 /* FIXIT : is it error case? */
1925 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1930 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
1932 gboolean update_all_param = FALSE;
1935 /* check video sinkbin is created */
1936 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1937 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1939 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1940 LOGE("can not find tizenwlsink");
1941 return MM_ERROR_PLAYER_INTERNAL;
1944 LOGD("param_name : %s", param_name);
1945 if (!g_strcmp0(param_name, "update_all_param"))
1946 update_all_param = TRUE;
1948 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1949 __mmplayer_video_param_set_display_overlay(player);
1950 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1951 __mmplayer_video_param_set_display_method(player);
1952 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1953 __mmplayer_video_param_set_display_visible(player);
1954 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1955 __mmplayer_video_param_set_display_rotation(player);
1956 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1957 __mmplayer_video_param_set_roi_area(player);
1958 if (update_all_param)
1959 __mmplayer_video_param_set_video_roi_area(player);
1961 return MM_ERROR_NONE;
1965 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
1967 MMHandleType attrs = 0;
1968 int surface_type = 0;
1969 int ret = MM_ERROR_NONE;
1973 /* check video sinkbin is created */
1974 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1975 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1977 attrs = MMPLAYER_GET_ATTRS(player);
1979 LOGE("cannot get content attribute");
1980 return MM_ERROR_PLAYER_INTERNAL;
1982 LOGD("param_name : %s", param_name);
1984 /* update display surface */
1985 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
1986 LOGD("check display surface type attribute: %d", surface_type);
1988 /* configuring display */
1989 switch (surface_type) {
1990 case MM_DISPLAY_SURFACE_OVERLAY:
1992 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
1993 if (ret != MM_ERROR_NONE)
2001 return MM_ERROR_NONE;
2005 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2007 gboolean disable_overlay = FALSE;
2008 mmplayer_t *player = (mmplayer_t *)hplayer;
2009 int ret = MM_ERROR_NONE;
2012 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2013 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2014 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2015 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2017 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2018 LOGW("Display control is not supported");
2019 return MM_ERROR_PLAYER_INTERNAL;
2022 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2024 if (audio_only == (bool)disable_overlay) {
2025 LOGE("It's the same with current setting: (%d)", audio_only);
2026 return MM_ERROR_NONE;
2030 LOGE("disable overlay");
2031 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2033 /* release overlay resource */
2034 if (player->video_overlay_resource != NULL) {
2035 ret = mm_resource_manager_mark_for_release(player->resource_manager,
2036 player->video_overlay_resource);
2037 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2038 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
2041 player->video_overlay_resource = NULL;
2044 ret = mm_resource_manager_commit(player->resource_manager);
2045 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2046 LOGE("failed to commit acquiring of overlay resource, ret(0x%x)", ret);
2050 /* mark video overlay for acquire */
2051 if (player->video_overlay_resource == NULL) {
2052 ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
2053 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY,
2054 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
2055 &player->video_overlay_resource);
2056 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2057 LOGE("could not prepare for video_overlay resource");
2062 player->interrupted_by_resource = FALSE;
2063 /* acquire resources for video overlay */
2064 ret = mm_resource_manager_commit(player->resource_manager);
2065 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
2066 LOGE("could not acquire resources for video playing");
2070 LOGD("enable overlay");
2071 __mmplayer_video_param_set_display_overlay(player);
2072 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2077 return MM_ERROR_NONE;
2081 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2083 mmplayer_t *player = (mmplayer_t *)hplayer;
2084 gboolean disable_overlay = FALSE;
2088 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2089 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2090 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2091 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2092 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2094 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2095 LOGW("Display control is not supported");
2096 return MM_ERROR_PLAYER_INTERNAL;
2099 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2101 *paudio_only = (bool)disable_overlay;
2103 LOGD("audio_only : %d", *paudio_only);
2107 return MM_ERROR_NONE;
2111 __mmplayer_gst_element_link_bucket(GList *element_bucket)
2113 GList *bucket = element_bucket;
2114 mmplayer_gst_element_t *element = NULL;
2115 mmplayer_gst_element_t *prv_element = NULL;
2116 gint successful_link_count = 0;
2120 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2122 prv_element = (mmplayer_gst_element_t *)bucket->data;
2123 bucket = bucket->next;
2125 for (; bucket; bucket = bucket->next) {
2126 element = (mmplayer_gst_element_t *)bucket->data;
2128 if (element && element->gst) {
2129 if (prv_element && prv_element->gst) {
2130 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2131 LOGD("linking [%s] to [%s] success",
2132 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2133 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2134 successful_link_count++;
2136 LOGD("linking [%s] to [%s] failed",
2137 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2138 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2144 prv_element = element;
2149 return successful_link_count;
2153 __mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2155 GList *bucket = element_bucket;
2156 mmplayer_gst_element_t *element = NULL;
2157 int successful_add_count = 0;
2161 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2162 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2164 for (; bucket; bucket = bucket->next) {
2165 element = (mmplayer_gst_element_t *)bucket->data;
2167 if (element && element->gst) {
2168 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2169 LOGD("__mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2170 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2171 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2174 successful_add_count++;
2180 return successful_add_count;
2184 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2186 mmplayer_t *player = (mmplayer_t *)data;
2187 GstCaps *caps = NULL;
2188 GstStructure *str = NULL;
2190 gboolean caps_ret = TRUE;
2194 MMPLAYER_RETURN_IF_FAIL(pad);
2195 MMPLAYER_RETURN_IF_FAIL(unused);
2196 MMPLAYER_RETURN_IF_FAIL(data);
2198 caps = gst_pad_get_current_caps(pad);
2202 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2206 LOGD("name = %s", name);
2208 if (strstr(name, "audio")) {
2209 __mmplayer_update_content_attrs(player, ATTR_AUDIO);
2211 if (player->audio_stream_changed_cb) {
2212 LOGE("call the audio stream changed cb");
2213 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2215 } else if (strstr(name, "video")) {
2216 if ((name = gst_structure_get_string(str, "format")))
2217 player->set_mode.video_zc = name[0] == 'S';
2219 __mmplayer_update_content_attrs(player, ATTR_VIDEO);
2221 if (player->video_stream_changed_cb) {
2222 LOGE("call the video stream changed cb");
2223 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2226 LOGW("invalid caps info");
2231 gst_caps_unref(caps);
2239 * This function is to create audio pipeline for playing.
2241 * @param player [in] handle of player
2243 * @return This function returns zero on success.
2245 * @see __mmplayer_gst_create_midi_pipeline, __mmplayer_gst_create_video_sink_bin
2247 /* macro for code readability. just for sinkbin-creation functions */
2248 #define MMPLAYER_CREATE_ELEMENT(x_bin, x_id, x_factory, x_name, x_add_bucket, x_player) \
2250 x_bin[x_id].id = x_id;\
2251 x_bin[x_id].gst = gst_element_factory_make(x_factory, x_name);\
2252 if (!x_bin[x_id].gst) {\
2253 LOGE("failed to create %s", x_factory);\
2256 if (x_player->ini.set_dump_element_flag)\
2257 __mmplayer_add_dump_buffer_probe(x_player, x_bin[x_id].gst);\
2260 element_bucket = g_list_append(element_bucket, &x_bin[x_id]);\
2264 __mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2269 MMPLAYER_RETURN_IF_FAIL(player);
2271 if (player->audio_stream_buff_list) {
2272 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2273 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2276 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2277 __mmplayer_audio_stream_send_data(player, tmp);
2279 MMPLAYER_FREEIF(tmp->pcm_data);
2280 MMPLAYER_FREEIF(tmp);
2283 g_list_free(player->audio_stream_buff_list);
2284 player->audio_stream_buff_list = NULL;
2291 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2293 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2296 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_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_decoded_cb_user_param); */
2307 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2313 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2315 mmplayer_t *player = (mmplayer_t *)data;
2316 const gchar *pcm_format = NULL;
2320 gint endianness = 0;
2321 guint64 channel_mask = 0;
2322 void *a_data = NULL;
2324 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2325 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2329 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_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 pcm_format = gst_structure_get_string(structure, "format");
2340 gst_structure_get_int(structure, "rate", &rate);
2341 gst_structure_get_int(structure, "channels", &channel);
2342 gst_structure_get_int(structure, "depth", &depth);
2343 gst_structure_get_int(structure, "endianness", &endianness);
2344 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2345 gst_caps_unref(GST_CAPS(caps));
2347 /* In case of the sync is false, use buffer list. *
2348 * The num of buffer list depends on the num of audio channels */
2349 if (player->audio_stream_buff_list) {
2350 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2351 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2353 if (channel_mask == tmp->channel_mask) {
2354 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2355 if (tmp->data_size + a_size < tmp->buff_size) {
2356 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2357 tmp->data_size += a_size;
2359 /* send data to client */
2360 __mmplayer_audio_stream_send_data(player, tmp);
2362 if (a_size > tmp->buff_size) {
2363 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2364 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2365 if (tmp->pcm_data == NULL) {
2366 LOGE("failed to realloc data.");
2369 tmp->buff_size = a_size;
2371 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2372 memcpy(tmp->pcm_data, a_data, a_size);
2373 tmp->data_size = a_size;
2378 LOGE("data is empty in list.");
2384 /* create new audio stream data */
2385 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2386 if (a_buffer == NULL) {
2387 LOGE("failed to alloc data.");
2390 a_buffer->bitrate = rate;
2391 a_buffer->channel = channel;
2392 a_buffer->depth = depth;
2393 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2394 a_buffer->channel_mask = channel_mask;
2395 a_buffer->data_size = a_size;
2396 a_buffer->pcm_format = util_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2398 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2399 /* If sync is FALSE, use buffer list to reduce the IPC. */
2400 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2401 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2402 if (a_buffer->pcm_data == NULL) {
2403 LOGE("failed to alloc data.");
2404 MMPLAYER_FREEIF(a_buffer);
2407 memcpy(a_buffer->pcm_data, a_data, a_size);
2408 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2409 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2411 /* If sync is TRUE, send data directly. */
2412 a_buffer->pcm_data = a_data;
2413 __mmplayer_audio_stream_send_data(player, a_buffer);
2414 MMPLAYER_FREEIF(a_buffer);
2418 gst_buffer_unmap(buffer, &mapinfo);
2423 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2425 mmplayer_t *player = (mmplayer_t *)data;
2426 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2427 GstPad *sinkpad = NULL;
2428 GstElement *queue = NULL, *sink = NULL;
2431 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2433 queue = gst_element_factory_make("queue", NULL);
2434 if (queue == NULL) {
2435 LOGD("fail make queue");
2439 sink = gst_element_factory_make("fakesink", NULL);
2441 LOGD("fail make fakesink");
2445 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2447 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2448 LOGW("failed to link queue & sink");
2452 sinkpad = gst_element_get_static_pad(queue, "sink");
2454 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2455 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2459 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2461 gst_object_unref(sinkpad);
2462 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2463 g_object_set(sink, "sync", TRUE, NULL);
2464 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2466 gst_element_set_state(sink, GST_STATE_PAUSED);
2467 gst_element_set_state(queue, GST_STATE_PAUSED);
2469 __mmplayer_add_signal_connection(player,
2471 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2473 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2480 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2482 gst_object_unref(GST_OBJECT(queue));
2486 gst_object_unref(GST_OBJECT(sink));
2490 gst_object_unref(GST_OBJECT(sinkpad));
2498 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player, MMHandleType attrs)
2500 #define MAX_PROPS_LEN 128
2501 gint latency_mode = 0;
2502 gchar *stream_type = NULL;
2503 gchar *latency = NULL;
2505 gchar stream_props[MAX_PROPS_LEN] = {0,};
2506 GstStructure *props = NULL;
2509 * It should be set after player creation through attribute.
2510 * But, it can not be changed during playing.
2513 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2515 mm_attrs_get_int_by_name(attrs, "sound_stream_index", &stream_id);
2516 mm_attrs_get_string_by_name(attrs, "sound_stream_type", &stream_type);
2519 LOGE("stream_type is null.");
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], result[%s].", stream_type, stream_id, stream_props);
2526 gst_structure_free(props);
2529 mm_attrs_get_int_by_name(attrs, "sound_latency_mode", &latency_mode);
2531 switch (latency_mode) {
2532 case AUDIO_LATENCY_MODE_LOW:
2533 latency = g_strndup("low", 3);
2535 case AUDIO_LATENCY_MODE_MID:
2536 latency = g_strndup("mid", 3);
2538 case AUDIO_LATENCY_MODE_HIGH:
2539 latency = g_strndup("high", 4);
2543 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2547 LOGD("audiosink property - latency=%s", latency);
2549 MMPLAYER_FREEIF(latency);
2555 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2557 mmplayer_gst_element_t *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(mmplayer_t *player, GList **bucket)
2587 mmplayer_gst_element_t *audiobin = NULL;
2588 MMHandleType attrs = 0;
2589 GList *element_bucket = NULL;
2590 GstCaps *acaps = NULL;
2591 GstPad *sink_pad = NULL;
2592 int pitch_control = 0;
2593 double pitch_value = 1.0;
2596 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2597 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2599 audiobin = player->pipeline->audiobin;
2600 attrs = MMPLAYER_GET_ATTRS(player);
2602 if (player->build_audio_offload) { /* skip all the audio filters */
2603 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2604 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", TRUE, player);
2605 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2606 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2611 mm_attrs_multiple_get(player->attrs, NULL,
2612 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2613 MM_PLAYER_PITCH_VALUE, &pitch_value,
2616 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2617 if (pitch_control && (player->videodec_linked == 0)) {
2618 GstElementFactory *factory;
2620 factory = gst_element_factory_find("pitch");
2622 gst_object_unref(factory);
2625 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", TRUE, player);
2628 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", TRUE, player);
2629 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2631 LOGW("there is no pitch element");
2636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", TRUE, player);
2638 /* replaygain volume */
2639 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", TRUE, player);
2640 if (player->sound.rg_enable)
2641 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2643 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2646 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", TRUE, player);
2648 if (player->audio_decoded_cb) { /* pcm extraction only, no sound output */
2649 gchar *dst_format = NULL;
2651 int dst_samplerate = 0;
2652 int dst_channels = 0;
2653 GstCaps *caps = NULL;
2654 char *caps_str = NULL;
2656 /* get conf. values */
2657 mm_attrs_multiple_get(player->attrs, NULL,
2658 "pcm_audioformat", &dst_format, &dst_len,
2659 "pcm_extraction_samplerate", &dst_samplerate,
2660 "pcm_extraction_channels", &dst_channels,
2663 LOGD("required pcm format - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2664 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2665 mm_attrs_multiple_get(player->attrs, NULL,
2666 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2667 "content_audio_samplerate", &dst_samplerate,
2668 "content_audio_channels", &dst_channels,
2671 LOGD("decoded pcm format - format: %s(%d), samplerate : %d, channel: %d", dst_format, dst_len, dst_samplerate, dst_channels);
2673 /* If there is no enough information, set it to platform default value. */
2674 if (dst_format == NULL || util_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2675 LOGD("set platform default format");
2676 dst_format = DEFAULT_PCM_OUT_FORMAT;
2678 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2679 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2683 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_DEFAULT, "capsfilter", "audio capsfilter", TRUE, player);
2684 caps = gst_caps_new_simple("audio/x-raw",
2685 "format", G_TYPE_STRING, dst_format,
2686 "rate", G_TYPE_INT, dst_samplerate,
2687 "channels", G_TYPE_INT, dst_channels,
2690 caps_str = gst_caps_to_string(caps);
2691 LOGD("new caps : %s", caps_str);
2693 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_CAPS_DEFAULT].gst), "caps", caps, NULL);
2696 gst_caps_unref(caps);
2697 MMPLAYER_FREEIF(caps_str);
2699 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_DEINTERLEAVE, "deinterleave", "deinterleave", TRUE, player);
2702 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2704 /* raw pad handling signal, audiosink will be added after getting signal */
2705 __mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_DEINTERLEAVE].gst),
2706 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "fakesink", "audiosink", TRUE, player);
2709 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE, NULL);
2711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "signal-handoffs", TRUE, NULL);
2713 __mmplayer_add_signal_connection(player,
2714 G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2715 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2717 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2721 /* normal playback */
2724 /* for logical volume control */
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", TRUE, player);
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2728 if (player->sound.mute) {
2729 LOGD("mute enabled");
2730 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2733 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2735 /* audio effect element. if audio effect is enabled */
2736 if ((strcmp(player->ini.audioeffect_element, ""))
2738 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2739 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", TRUE, player);
2741 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2743 if ((!player->bypass_audio_effect)
2744 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2745 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2746 if (!_mmplayer_audio_effect_custom_apply(player))
2747 LOGI("apply audio effect(custom) setting success");
2751 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2752 && (player->set_mode.rich_audio))
2753 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", TRUE, player);
2756 /* create audio sink */
2757 LOGD("360 spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2758 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2759 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2761 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2762 if (player->is_360_feature_enabled &&
2763 player->is_content_spherical &&
2765 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2766 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2767 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2769 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2771 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", TRUE, player);
2773 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", TRUE, player);
2774 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2775 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2776 gst_caps_unref(acaps);
2778 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", TRUE, player);
2780 player->is_openal_plugin_used = TRUE;
2782 if (player->is_360_feature_enabled && player->is_content_spherical)
2783 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2784 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", TRUE, player);
2787 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2788 (player->videodec_linked && player->ini.use_system_clock)) {
2789 LOGD("system clock will be used.");
2790 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2793 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2794 __mmplayer_gst_set_pulsesink_property(player, attrs);
2795 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2796 __mmplayer_gst_set_openalsink_property(player);
2799 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2800 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2802 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2803 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2804 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2805 gst_object_unref(GST_OBJECT(sink_pad));
2807 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2811 *bucket = element_bucket;
2814 return MM_ERROR_NONE;
2817 g_list_free(element_bucket);
2821 return MM_ERROR_PLAYER_INTERNAL;
2825 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2827 mmplayer_gst_element_t *first_element = NULL;
2828 mmplayer_gst_element_t *audiobin = NULL;
2830 GstPad *ghostpad = NULL;
2831 GList *element_bucket = NULL;
2835 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2838 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2840 LOGE("failed to allocate memory for audiobin");
2841 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2845 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2846 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2847 if (!audiobin[MMPLAYER_A_BIN].gst) {
2848 LOGE("failed to create audiobin");
2853 player->pipeline->audiobin = audiobin;
2855 /* create audio filters and audiosink */
2856 if (__mmplayer_gst_fill_audio_bucket(player, &element_bucket) != MM_ERROR_NONE)
2859 /* adding created elements to bin */
2860 LOGD("adding created elements to bin");
2861 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2864 /* linking elements in the bucket by added order. */
2865 LOGD("Linking elements in the bucket by added order.");
2866 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1)
2869 /* get first element's sinkpad for creating ghostpad */
2870 first_element = (mmplayer_gst_element_t *)element_bucket->data;
2871 if (!first_element) {
2872 LOGE("failed to get first elem");
2876 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2878 LOGE("failed to get pad from first element of audiobin");
2882 ghostpad = gst_ghost_pad_new("sink", pad);
2884 LOGE("failed to create ghostpad");
2888 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
2889 LOGE("failed to add ghostpad to audiobin");
2893 gst_object_unref(pad);
2895 g_list_free(element_bucket);
2898 return MM_ERROR_NONE;
2901 LOGD("ERROR : releasing audiobin");
2904 gst_object_unref(GST_OBJECT(pad));
2907 gst_object_unref(GST_OBJECT(ghostpad));
2910 g_list_free(element_bucket);
2912 /* release element which are not added to bin */
2913 for (i = 1; i < MMPLAYER_A_NUM; i++) {
2914 /* NOTE : skip bin */
2915 if (audiobin[i].gst) {
2916 GstObject *parent = NULL;
2917 parent = gst_element_get_parent(audiobin[i].gst);
2920 gst_object_unref(GST_OBJECT(audiobin[i].gst));
2921 audiobin[i].gst = NULL;
2923 gst_object_unref(GST_OBJECT(parent));
2927 /* release audiobin with it's childs */
2928 if (audiobin[MMPLAYER_A_BIN].gst)
2929 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
2931 MMPLAYER_FREEIF(audiobin);
2933 player->pipeline->audiobin = NULL;
2935 return MM_ERROR_PLAYER_INTERNAL;
2939 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
2941 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
2945 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
2947 int ret = MM_ERROR_NONE;
2949 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
2950 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
2952 MMPLAYER_VIDEO_BO_LOCK(player);
2954 if (player->video_bo_list) {
2955 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2956 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
2957 if (tmp && tmp->bo == bo) {
2959 LOGD("release bo %p", bo);
2960 tbm_bo_unref(tmp->bo);
2961 MMPLAYER_VIDEO_BO_UNLOCK(player);
2962 MMPLAYER_VIDEO_BO_SIGNAL(player);
2967 /* hw codec is running or the list was reset for DRC. */
2968 LOGW("there is no bo list.");
2970 MMPLAYER_VIDEO_BO_UNLOCK(player);
2972 LOGW("failed to find bo %p", bo);
2977 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
2982 MMPLAYER_RETURN_IF_FAIL(player);
2984 MMPLAYER_VIDEO_BO_LOCK(player);
2985 if (player->video_bo_list) {
2986 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
2987 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
2988 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
2991 tbm_bo_unref(tmp->bo);
2995 g_list_free(player->video_bo_list);
2996 player->video_bo_list = NULL;
2998 player->video_bo_size = 0;
2999 MMPLAYER_VIDEO_BO_UNLOCK(player);
3006 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3009 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3010 gboolean ret = TRUE;
3012 /* check DRC, if it is, destroy the prev bo list to create again */
3013 if (player->video_bo_size != size) {
3014 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3015 __mmplayer_video_stream_destroy_bo_list(player);
3016 player->video_bo_size = size;
3019 MMPLAYER_VIDEO_BO_LOCK(player);
3021 if ((!player->video_bo_list) ||
3022 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3024 /* create bo list */
3026 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3028 if (player->video_bo_list) {
3029 /* if bo list did not created all, try it again. */
3030 idx = g_list_length(player->video_bo_list);
3031 LOGD("bo list exist(len: %d)", idx);
3034 for (; idx < player->ini.num_of_video_bo; idx++) {
3035 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3037 LOGE("Fail to alloc bo_info.");
3040 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3042 LOGE("Fail to tbm_bo_alloc.");
3043 MMPLAYER_FREEIF(bo_info);
3046 bo_info->used = FALSE;
3047 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3050 /* update video num buffers */
3051 player->video_num_buffers = idx;
3052 if (idx == player->ini.num_of_video_bo)
3053 player->video_extra_num_buffers = player->ini.num_of_video_bo/2;
3056 MMPLAYER_VIDEO_BO_UNLOCK(player);
3060 LOGD("Num of video buffers(%d/%d)", player->video_num_buffers, player->video_extra_num_buffers);
3064 /* get bo from list*/
3065 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3066 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3067 if (tmp && (tmp->used == FALSE)) {
3068 LOGD("found bo %p to use", tmp->bo);
3070 MMPLAYER_VIDEO_BO_UNLOCK(player);
3071 return tbm_bo_ref(tmp->bo);
3075 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3076 MMPLAYER_VIDEO_BO_UNLOCK(player);
3080 if (player->ini.video_bo_timeout <= 0) {
3081 MMPLAYER_VIDEO_BO_WAIT(player);
3083 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3084 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3091 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3093 mmplayer_t *player = (mmplayer_t *)data;
3095 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3097 /* send prerolled pkt */
3098 player->video_stream_prerolled = false;
3100 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3102 /* not to send prerolled pkt again */
3103 player->video_stream_prerolled = true;
3107 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3109 mmplayer_t *player = (mmplayer_t *)data;
3110 mmplayer_video_decoded_data_info_t *stream = NULL;
3111 GstMemory *mem = NULL;
3114 MMPLAYER_RETURN_IF_FAIL(player);
3115 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3117 if (player->video_stream_prerolled) {
3118 player->video_stream_prerolled = false;
3119 LOGD("skip the prerolled pkt not to send it again");
3123 /* clear stream data structure */
3124 stream = __mmplayer_create_stream_from_pad(pad);
3126 LOGE("failed to alloc stream");
3130 __mmplayer_get_video_angle(player, NULL, &stream->orientation);
3132 /* set size and timestamp */
3133 mem = gst_buffer_peek_memory(buffer, 0);
3134 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3135 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3137 /* check zero-copy */
3138 if (player->set_mode.video_zc &&
3139 player->set_mode.video_export &&
3140 gst_is_tizen_memory(mem)) {
3141 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3142 stream->internal_buffer = gst_buffer_ref(buffer);
3143 } else { /* sw codec */
3144 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3147 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3151 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3152 LOGE("failed to send video decoded data.");
3159 LOGE("release video stream resource.");
3160 if (gst_is_tizen_memory(mem)) {
3162 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3164 tbm_bo_unref(stream->bo[i]);
3167 /* unref gst buffer */
3168 if (stream->internal_buffer)
3169 gst_buffer_unref(stream->internal_buffer);
3172 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3174 MMPLAYER_FREEIF(stream);
3179 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3181 mmplayer_gst_element_t *videobin = NULL;
3184 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3186 videobin = player->pipeline->videobin;
3188 /* Set spatial media metadata and/or user settings to the element.
3190 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3191 "projection-type", player->video360_metadata.projection_type, NULL);
3193 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3194 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3196 if (player->video360_metadata.full_pano_width_pixels &&
3197 player->video360_metadata.full_pano_height_pixels &&
3198 player->video360_metadata.cropped_area_image_width &&
3199 player->video360_metadata.cropped_area_image_height) {
3200 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3201 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3202 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3203 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3204 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3205 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3206 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3210 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3211 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3212 "horizontal-fov", player->video360_horizontal_fov,
3213 "vertical-fov", player->video360_vertical_fov, NULL);
3216 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3217 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3218 "zoom", 1.0f / player->video360_zoom, NULL);
3221 if (player->video360_yaw_radians <= M_PI &&
3222 player->video360_yaw_radians >= -M_PI &&
3223 player->video360_pitch_radians <= M_PI_2 &&
3224 player->video360_pitch_radians >= -M_PI_2) {
3225 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3226 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3227 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3228 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3229 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3230 "pose-yaw", player->video360_metadata.init_view_heading,
3231 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3234 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3235 "passthrough", !player->is_video360_enabled, NULL);
3242 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3244 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3245 GList *element_bucket = NULL;
3248 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3250 /* create video360 filter */
3251 if (player->is_360_feature_enabled && player->is_content_spherical) {
3252 LOGD("create video360 element");
3253 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", TRUE, player);
3254 __mmplayer_gst_set_video360_property(player);
3258 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3259 LOGD("skip creating the videoconv and rotator");
3260 return MM_ERROR_NONE;
3263 /* in case of sw codec & overlay surface type, except 360 playback.
3264 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3265 LOGD("create video converter: %s", video_csc);
3266 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", TRUE, player);
3269 *bucket = element_bucket;
3271 return MM_ERROR_NONE;
3273 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3274 g_list_free(element_bucket);
3278 return MM_ERROR_PLAYER_INTERNAL;
3282 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3284 gchar *factory_name = NULL;
3286 switch (surface_type) {
3287 case MM_DISPLAY_SURFACE_OVERLAY:
3288 if (strlen(player->ini.videosink_element_overlay) > 0)
3289 factory_name = player->ini.videosink_element_overlay;
3291 case MM_DISPLAY_SURFACE_REMOTE:
3292 case MM_DISPLAY_SURFACE_NULL:
3293 if (strlen(player->ini.videosink_element_fake) > 0)
3294 factory_name = player->ini.videosink_element_fake;
3297 LOGE("unidentified surface type");
3301 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3302 return factory_name;
3306 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3308 gchar *factory_name = NULL;
3309 mmplayer_gst_element_t *videobin = NULL;
3314 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3316 videobin = player->pipeline->videobin;
3317 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3319 attrs = MMPLAYER_GET_ATTRS(player);
3321 LOGE("cannot get content attribute");
3322 return MM_ERROR_PLAYER_INTERNAL;
3325 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3326 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3327 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3329 /* support shard memory with S/W codec on HawkP */
3330 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3331 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3332 "use-tbm", use_tbm, NULL);
3336 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3337 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3340 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3342 LOGD("disable last-sample");
3343 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3346 if (player->set_mode.video_export) {
3348 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3349 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3350 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3352 __mmplayer_add_signal_connection(player,
3353 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3354 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3356 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3359 __mmplayer_add_signal_connection(player,
3360 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3361 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3363 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3367 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3368 return MM_ERROR_PLAYER_INTERNAL;
3370 if (videobin[MMPLAYER_V_SINK].gst) {
3371 GstPad *sink_pad = NULL;
3372 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3374 __mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3375 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3376 gst_object_unref(GST_OBJECT(sink_pad));
3378 LOGE("failed to get sink pad from videosink");
3382 return MM_ERROR_NONE;
3387 * - video overlay surface(arm/x86) : tizenwlsink
3390 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3393 GList *element_bucket = NULL;
3394 mmplayer_gst_element_t *first_element = NULL;
3395 mmplayer_gst_element_t *videobin = NULL;
3396 gchar *videosink_factory_name = NULL;
3399 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3402 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3404 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3406 player->pipeline->videobin = videobin;
3409 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3410 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3411 if (!videobin[MMPLAYER_V_BIN].gst) {
3412 LOGE("failed to create videobin");
3416 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3419 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3420 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", TRUE, player);
3422 /* additional setting for sink plug-in */
3423 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3424 LOGE("failed to set video property");
3428 /* store it as it's sink element */
3429 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3431 /* adding created elements to bin */
3432 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3433 LOGE("failed to add elements");
3437 /* Linking elements in the bucket by added order */
3438 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3439 LOGE("failed to link elements");
3443 /* get first element's sinkpad for creating ghostpad */
3444 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3445 if (!first_element) {
3446 LOGE("failed to get first element from bucket");
3450 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3452 LOGE("failed to get pad from first element");
3456 /* create ghostpad */
3457 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3458 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3459 LOGE("failed to add ghostpad to videobin");
3462 gst_object_unref(pad);
3464 /* done. free allocated variables */
3465 g_list_free(element_bucket);
3469 return MM_ERROR_NONE;
3472 LOGE("ERROR : releasing videobin");
3473 g_list_free(element_bucket);
3476 gst_object_unref(GST_OBJECT(pad));
3478 /* release videobin with it's childs */
3479 if (videobin[MMPLAYER_V_BIN].gst)
3480 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3482 MMPLAYER_FREEIF(videobin);
3483 player->pipeline->videobin = NULL;
3485 return MM_ERROR_PLAYER_INTERNAL;
3489 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3491 GList *element_bucket = NULL;
3492 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3494 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", TRUE, player);
3495 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", TRUE, player);
3496 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3497 "signal-handoffs", FALSE,
3500 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", TRUE, player);
3501 __mmplayer_add_signal_connection(player,
3502 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3503 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3505 G_CALLBACK(__mmplayer_update_subtitle),
3508 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3509 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3511 if (!player->play_subtitle) {
3512 LOGD("add textbin sink as sink element of whole pipeline.");
3513 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3516 /* adding created elements to bin */
3517 LOGD("adding created elements to bin");
3518 if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3519 LOGE("failed to add elements");
3523 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3524 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3525 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3527 /* linking elements in the bucket by added order. */
3528 LOGD("Linking elements in the bucket by added order.");
3529 if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3530 LOGE("failed to link elements");
3534 /* done. free allocated variables */
3535 g_list_free(element_bucket);
3537 if (textbin[MMPLAYER_T_QUEUE].gst) {
3539 GstPad *ghostpad = NULL;
3541 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3543 LOGE("failed to get sink pad of text queue");
3547 ghostpad = gst_ghost_pad_new("text_sink", pad);
3548 gst_object_unref(pad);
3551 LOGE("failed to create ghostpad of textbin");
3555 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3556 LOGE("failed to add ghostpad to textbin");
3557 gst_object_unref(ghostpad);
3562 return MM_ERROR_NONE;
3565 g_list_free(element_bucket);
3567 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3568 LOGE("remove textbin sink from sink list");
3569 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3572 /* release element at __mmplayer_gst_create_text_sink_bin */
3573 return MM_ERROR_PLAYER_INTERNAL;
3577 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3579 mmplayer_gst_element_t *textbin = NULL;
3580 GList *element_bucket = NULL;
3581 int surface_type = 0;
3586 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3589 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3591 LOGE("failed to allocate memory for textbin");
3592 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3596 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3597 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3598 if (!textbin[MMPLAYER_T_BIN].gst) {
3599 LOGE("failed to create textbin");
3604 player->pipeline->textbin = textbin;
3607 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3608 LOGD("surface type for subtitle : %d", surface_type);
3609 switch (surface_type) {
3610 case MM_DISPLAY_SURFACE_OVERLAY:
3611 case MM_DISPLAY_SURFACE_NULL:
3612 case MM_DISPLAY_SURFACE_REMOTE:
3613 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3614 LOGE("failed to make plain text elements");
3625 return MM_ERROR_NONE;
3629 LOGD("ERROR : releasing textbin");
3631 g_list_free(element_bucket);
3633 /* release signal */
3634 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3636 /* release element which are not added to bin */
3637 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3638 /* NOTE : skip bin */
3639 if (textbin[i].gst) {
3640 GstObject *parent = NULL;
3641 parent = gst_element_get_parent(textbin[i].gst);
3644 gst_object_unref(GST_OBJECT(textbin[i].gst));
3645 textbin[i].gst = NULL;
3647 gst_object_unref(GST_OBJECT(parent));
3652 /* release textbin with it's childs */
3653 if (textbin[MMPLAYER_T_BIN].gst)
3654 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3656 MMPLAYER_FREEIF(player->pipeline->textbin);
3657 player->pipeline->textbin = NULL;
3660 return MM_ERROR_PLAYER_INTERNAL;
3664 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3666 mmplayer_gst_element_t *mainbin = NULL;
3667 mmplayer_gst_element_t *textbin = NULL;
3668 MMHandleType attrs = 0;
3669 GstElement *subsrc = NULL;
3670 GstElement *subparse = NULL;
3671 gchar *subtitle_uri = NULL;
3672 const gchar *charset = NULL;
3678 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3680 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3682 mainbin = player->pipeline->mainbin;
3684 attrs = MMPLAYER_GET_ATTRS(player);
3686 LOGE("cannot get content attribute");
3687 return MM_ERROR_PLAYER_INTERNAL;
3690 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3691 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3692 LOGE("subtitle uri is not proper filepath.");
3693 return MM_ERROR_PLAYER_INVALID_URI;
3696 if (!util_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3697 LOGE("failed to get storage info of subtitle path");
3698 return MM_ERROR_PLAYER_INVALID_URI;
3701 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3703 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3704 player->subtitle_language_list = NULL;
3705 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3707 /* create the subtitle source */
3708 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3710 LOGE("failed to create filesrc element");
3713 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3715 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3716 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3718 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3719 LOGW("failed to add queue");
3720 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3721 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3722 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3727 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3729 LOGE("failed to create subparse element");
3733 charset = util_get_charset(subtitle_uri);
3735 LOGD("detected charset is %s", charset);
3736 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3739 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3740 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3742 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3743 LOGW("failed to add subparse");
3744 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3745 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3746 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3750 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3751 LOGW("failed to link subsrc and subparse");
3755 player->play_subtitle = TRUE;
3756 player->adjust_subtitle_pos = 0;
3758 LOGD("play subtitle using subtitle file");
3760 if (player->pipeline->textbin == NULL) {
3761 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3762 LOGE("failed to create text sink bin. continuing without text");
3766 textbin = player->pipeline->textbin;
3768 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3769 LOGW("failed to add textbin");
3771 /* release signal */
3772 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3774 /* release textbin with it's childs */
3775 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3776 MMPLAYER_FREEIF(player->pipeline->textbin);
3777 player->pipeline->textbin = textbin = NULL;
3781 LOGD("link text input selector and textbin ghost pad");
3783 player->textsink_linked = 1;
3784 player->external_text_idx = 0;
3785 LOGI("textsink is linked");
3787 textbin = player->pipeline->textbin;
3788 LOGD("text bin has been created. reuse it.");
3789 player->external_text_idx = 1;
3792 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3793 LOGW("failed to link subparse and textbin");
3797 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3799 LOGE("failed to get sink pad from textsink to probe data");
3803 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3804 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3806 gst_object_unref(pad);
3809 /* create dot. for debugging */
3810 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3813 return MM_ERROR_NONE;
3816 /* release text pipeline resource */
3817 player->textsink_linked = 0;
3819 /* release signal */
3820 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3822 if (player->pipeline->textbin) {
3823 LOGE("remove textbin");
3825 /* release textbin with it's childs */
3826 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3827 MMPLAYER_FREEIF(player->pipeline->textbin);
3828 player->pipeline->textbin = NULL;
3832 /* release subtitle elem */
3833 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3834 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3836 return MM_ERROR_PLAYER_INTERNAL;
3840 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3842 mmplayer_t *player = (mmplayer_t *)data;
3843 MMMessageParamType msg = {0, };
3844 GstClockTime duration = 0;
3845 gpointer text = NULL;
3846 guint text_size = 0;
3847 gboolean ret = TRUE;
3848 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3852 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3853 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3855 if (player->is_subtitle_force_drop) {
3856 LOGW("subtitle is dropped forcedly.");
3860 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3861 text = mapinfo.data;
3862 text_size = mapinfo.size;
3864 if (player->set_mode.subtitle_off) {
3865 LOGD("subtitle is OFF.");
3869 if (!text || (text_size == 0)) {
3870 LOGD("There is no subtitle to be displayed.");
3874 msg.data = (void *)text;
3876 duration = GST_BUFFER_DURATION(buffer);
3878 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
3879 if (player->duration > GST_BUFFER_PTS(buffer))
3880 duration = player->duration - GST_BUFFER_PTS(buffer);
3883 LOGI("subtitle duration is invalid, subtitle duration change "
3884 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
3886 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
3888 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
3890 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
3891 gst_buffer_unmap(buffer, &mapinfo);
3898 static GstPadProbeReturn
3899 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
3901 mmplayer_t *player = (mmplayer_t *)u_data;
3902 GstClockTime cur_timestamp = 0;
3903 gint64 adjusted_timestamp = 0;
3904 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
3906 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3908 if (player->set_mode.subtitle_off) {
3909 LOGD("subtitle is OFF.");
3913 if (player->adjust_subtitle_pos == 0) {
3914 LOGD("nothing to do");
3918 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
3919 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
3921 if (adjusted_timestamp < 0) {
3922 LOGD("adjusted_timestamp under zero");
3927 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
3928 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
3929 GST_TIME_ARGS(cur_timestamp),
3930 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
3932 return GST_PAD_PROBE_OK;
3936 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
3940 /* check player and subtitlebin are created */
3941 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3942 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
3944 if (position == 0) {
3945 LOGD("nothing to do");
3947 return MM_ERROR_NONE;
3950 /* check current postion */
3951 player->adjust_subtitle_pos = position;
3953 LOGD("save adjust_subtitle_pos in player");
3957 return MM_ERROR_NONE;
3961 * This function is to create audio or video pipeline for playing.
3963 * @param player [in] handle of player
3965 * @return This function returns zero on success.
3970 __mmplayer_gst_create_pipeline(mmplayer_t *player)
3972 int ret = MM_ERROR_NONE;
3973 mmplayer_gst_element_t *mainbin = NULL;
3974 MMHandleType attrs = 0;
3977 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3979 /* get profile attribute */
3980 attrs = MMPLAYER_GET_ATTRS(player);
3982 LOGE("failed to get content attribute");
3986 /* create pipeline handles */
3987 if (player->pipeline) {
3988 LOGE("pipeline should be released before create new one");
3992 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
3993 if (player->pipeline == NULL)
3996 /* create mainbin */
3997 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
3998 if (mainbin == NULL)
4001 /* create pipeline */
4002 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4003 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4004 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4005 LOGE("failed to create pipeline");
4010 player->pipeline->mainbin = mainbin;
4012 /* create the source and decoder elements */
4013 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4014 ret = __mmplayer_gst_build_es_pipeline(player);
4016 ret = __mmplayer_gst_build_pipeline(player);
4018 if (ret != MM_ERROR_NONE) {
4019 LOGE("failed to create some elements");
4023 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4024 if (__mmplayer_check_subtitle(player)
4025 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4026 LOGE("failed to create text pipeline");
4029 ret = __mmplayer_gst_add_bus_watch(player);
4030 if (ret != MM_ERROR_NONE) {
4031 LOGE("failed to add bus watch");
4036 return MM_ERROR_NONE;
4039 __mmplayer_gst_destroy_pipeline(player);
4040 return MM_ERROR_PLAYER_INTERNAL;
4044 __mmplayer_reset_gapless_state(mmplayer_t *player)
4047 MMPLAYER_RETURN_IF_FAIL(player
4049 && player->pipeline->audiobin
4050 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4052 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4059 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4062 int ret = MM_ERROR_NONE;
4066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4068 /* cleanup stuffs */
4069 MMPLAYER_FREEIF(player->type);
4070 player->no_more_pad = FALSE;
4071 player->num_dynamic_pad = 0;
4072 player->demux_pad_index = 0;
4074 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4075 player->subtitle_language_list = NULL;
4076 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4078 __mmplayer_reset_gapless_state(player);
4080 if (player->streamer) {
4081 __mm_player_streaming_initialize(player->streamer, FALSE);
4082 __mm_player_streaming_destroy(player->streamer);
4083 player->streamer = NULL;
4086 /* cleanup unlinked mime type */
4087 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4088 MMPLAYER_FREEIF(player->unlinked_video_mime);
4089 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4091 /* cleanup running stuffs */
4092 __mmplayer_cancel_eos_timer(player);
4094 /* cleanup gst stuffs */
4095 if (player->pipeline) {
4096 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4097 GstTagList *tag_list = player->pipeline->tag_list;
4099 /* first we need to disconnect all signal hander */
4100 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4103 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4104 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4105 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4106 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4107 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4108 gst_object_unref(bus);
4110 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4111 ret = __mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4112 if (ret != MM_ERROR_NONE) {
4113 LOGE("fail to change state to NULL");
4114 return MM_ERROR_PLAYER_INTERNAL;
4117 LOGW("succeeded in changing state to NULL");
4119 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4122 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4123 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4125 /* free avsysaudiosink
4126 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4127 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4129 MMPLAYER_FREEIF(audiobin);
4130 MMPLAYER_FREEIF(videobin);
4131 MMPLAYER_FREEIF(textbin);
4132 MMPLAYER_FREEIF(mainbin);
4136 gst_tag_list_unref(tag_list);
4138 MMPLAYER_FREEIF(player->pipeline);
4140 MMPLAYER_FREEIF(player->album_art);
4142 if (player->v_stream_caps) {
4143 gst_caps_unref(player->v_stream_caps);
4144 player->v_stream_caps = NULL;
4147 if (player->a_stream_caps) {
4148 gst_caps_unref(player->a_stream_caps);
4149 player->a_stream_caps = NULL;
4152 if (player->s_stream_caps) {
4153 gst_caps_unref(player->s_stream_caps);
4154 player->s_stream_caps = NULL;
4156 __mmplayer_track_destroy(player);
4158 if (player->sink_elements)
4159 g_list_free(player->sink_elements);
4160 player->sink_elements = NULL;
4162 if (player->bufmgr) {
4163 tbm_bufmgr_deinit(player->bufmgr);
4164 player->bufmgr = NULL;
4167 LOGW("finished destroy pipeline");
4175 __mmplayer_gst_realize(mmplayer_t *player)
4178 int ret = MM_ERROR_NONE;
4182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4184 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4186 ret = __mmplayer_gst_create_pipeline(player);
4188 LOGE("failed to create pipeline");
4192 /* set pipeline state to READY */
4193 /* NOTE : state change to READY must be performed sync. */
4194 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4195 ret = __mmplayer_gst_set_state(player,
4196 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4198 if (ret != MM_ERROR_NONE) {
4199 /* return error if failed to set state */
4200 LOGE("failed to set READY state");
4204 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4206 /* create dot before error-return. for debugging */
4207 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4215 __mmplayer_gst_unrealize(mmplayer_t *player)
4217 int ret = MM_ERROR_NONE;
4221 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4223 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4224 MMPLAYER_PRINT_STATE(player);
4226 /* release miscellaneous information */
4227 __mmplayer_release_misc(player);
4229 /* destroy pipeline */
4230 ret = __mmplayer_gst_destroy_pipeline(player);
4231 if (ret != MM_ERROR_NONE) {
4232 LOGE("failed to destory pipeline");
4236 /* release miscellaneous information.
4237 these info needs to be released after pipeline is destroyed. */
4238 __mmplayer_release_misc_post(player);
4240 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4248 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4253 LOGW("set_message_callback is called with invalid player handle");
4254 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4257 player->msg_cb = callback;
4258 player->msg_cb_param = user_param;
4260 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4264 return MM_ERROR_NONE;
4268 __mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4270 int ret = MM_ERROR_NONE;
4275 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4276 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4277 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4279 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4281 if (strstr(uri, "es_buff://")) {
4282 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4283 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4284 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4285 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4287 tmp = g_ascii_strdown(uri, strlen(uri));
4288 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4289 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4291 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4293 } else if (strstr(uri, "mms://")) {
4294 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4295 } else if ((path = strstr(uri, "mem://"))) {
4296 ret = __mmplayer_set_mem_uri(data, path, param);
4298 ret = __mmplayer_set_file_uri(data, uri);
4301 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4302 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4303 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4304 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4306 /* dump parse result */
4307 SECURE_LOGW("incoming uri : %s", uri);
4308 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4309 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4317 __mmplayer_can_do_interrupt(mmplayer_t *player)
4319 if (!player || !player->pipeline || !player->attrs) {
4320 LOGW("not initialized");
4324 if (player->audio_decoded_cb) {
4325 LOGW("not support in pcm extraction mode");
4329 /* check if seeking */
4330 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4331 MMMessageParamType msg_param;
4332 memset(&msg_param, 0, sizeof(MMMessageParamType));
4333 msg_param.code = MM_ERROR_PLAYER_SEEK;
4334 player->seek_state = MMPLAYER_SEEK_NONE;
4335 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4339 /* check other thread */
4340 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4341 LOGW("locked already, cmd state : %d", player->cmd);
4343 /* check application command */
4344 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4345 LOGW("playing.. should wait cmd lock then, will be interrupted");
4347 /* lock will be released at mrp_resource_release_cb() */
4348 MMPLAYER_CMD_LOCK(player);
4351 LOGW("nothing to do");
4354 LOGW("can interrupt immediately");
4358 FAILED: /* with CMD UNLOCKED */
4361 INTERRUPT: /* with CMD LOCKED, released at mrp_resource_release_cb() */
4366 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4369 mmplayer_t *player = NULL;
4373 if (user_data == NULL) {
4374 LOGE("- user_data is null");
4377 player = (mmplayer_t *)user_data;
4379 /* do something to release resource here.
4380 * player stop and interrupt forwarding */
4381 if (!__mmplayer_can_do_interrupt(player)) {
4382 LOGW("no need to interrupt, so leave");
4384 MMMessageParamType msg = {0, };
4387 player->interrupted_by_resource = TRUE;
4389 /* get last play position */
4390 if (_mmplayer_get_position((MMHandleType)player, &pos) != MM_ERROR_NONE) {
4391 LOGW("failed to get play position.");
4393 msg.union_type = MM_MSG_UNION_TIME;
4394 msg.time.elapsed = pos;
4395 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4397 LOGD("video resource conflict so, resource will be freed by unrealizing");
4398 if (_mmplayer_unrealize((MMHandleType)player))
4399 LOGW("failed to unrealize");
4401 /* lock is called in __mmplayer_can_do_interrupt() */
4402 MMPLAYER_CMD_UNLOCK(player);
4405 if (res == player->video_overlay_resource)
4406 player->video_overlay_resource = FALSE;
4408 player->video_decoder_resource = FALSE;
4416 __mmplayer_initialize_video_roi(mmplayer_t *player)
4418 player->video_roi.scale_x = 0.0;
4419 player->video_roi.scale_y = 0.0;
4420 player->video_roi.scale_width = 1.0;
4421 player->video_roi.scale_height = 1.0;
4425 _mmplayer_create_player(MMHandleType handle)
4427 int ret = MM_ERROR_PLAYER_INTERNAL;
4428 bool enabled = false;
4430 mmplayer_t *player = MM_PLAYER_CAST(handle);
4434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4436 /* initialize player state */
4437 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4438 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4439 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4442 /* check current state */
4443 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4445 /* construct attributes */
4446 player->attrs = _mmplayer_construct_attribute(handle);
4448 if (!player->attrs) {
4449 LOGE("Failed to construct attributes");
4453 /* initialize gstreamer with configured parameter */
4454 if (!__mmplayer_init_gstreamer(player)) {
4455 LOGE("Initializing gstreamer failed");
4456 _mmplayer_deconstruct_attribute(handle);
4460 /* create lock. note that g_tread_init() has already called in gst_init() */
4461 g_mutex_init(&player->fsink_lock);
4463 /* create update tag lock */
4464 g_mutex_init(&player->update_tag_lock);
4466 /* create gapless play mutex */
4467 g_mutex_init(&player->gapless_play_thread_mutex);
4469 /* create gapless play cond */
4470 g_cond_init(&player->gapless_play_thread_cond);
4472 /* create gapless play thread */
4473 player->gapless_play_thread =
4474 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4475 if (!player->gapless_play_thread) {
4476 LOGE("failed to create gapless play thread");
4477 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4478 g_mutex_clear(&player->gapless_play_thread_mutex);
4479 g_cond_clear(&player->gapless_play_thread_cond);
4483 player->bus_msg_q = g_queue_new();
4484 if (!player->bus_msg_q) {
4485 LOGE("failed to create queue for bus_msg");
4486 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4490 ret = _mmplayer_initialize_video_capture(player);
4491 if (ret != MM_ERROR_NONE) {
4492 LOGE("failed to initialize video capture");
4496 /* initialize resource manager */
4497 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4498 __resource_release_cb, player, &player->resource_manager)
4499 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4500 LOGE("failed to initialize resource manager");
4501 ret = MM_ERROR_PLAYER_INTERNAL;
4505 /* create video bo lock and cond */
4506 g_mutex_init(&player->video_bo_mutex);
4507 g_cond_init(&player->video_bo_cond);
4509 /* create media stream callback mutex */
4510 g_mutex_init(&player->media_stream_cb_lock);
4512 /* create subtitle info lock and cond */
4513 g_mutex_init(&player->subtitle_info_mutex);
4514 g_cond_init(&player->subtitle_info_cond);
4516 player->streaming_type = STREAMING_SERVICE_NONE;
4518 /* give default value of audio effect setting */
4519 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4520 player->sound.rg_enable = false;
4521 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4523 player->play_subtitle = FALSE;
4524 player->has_closed_caption = FALSE;
4525 player->video_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4526 player->video_extra_num_buffers = DEFAULT_NUM_OF_V_OUT_BUFFER;
4527 player->pending_resume = FALSE;
4528 if (player->ini.dump_element_keyword[0][0] == '\0')
4529 player->ini.set_dump_element_flag = FALSE;
4531 player->ini.set_dump_element_flag = TRUE;
4533 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4534 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4535 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4537 /* Set video360 settings to their defaults for just-created player.
4540 player->is_360_feature_enabled = FALSE;
4541 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4542 LOGI("spherical feature info: %d", enabled);
4544 player->is_360_feature_enabled = TRUE;
4546 LOGE("failed to get spherical feature info");
4549 player->is_content_spherical = FALSE;
4550 player->is_video360_enabled = TRUE;
4551 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4552 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4553 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4554 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4555 player->video360_zoom = 1.0f;
4556 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4557 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4559 __mmplayer_initialize_video_roi(player);
4561 /* set player state to null */
4562 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4563 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4567 return MM_ERROR_NONE;
4571 g_mutex_clear(&player->fsink_lock);
4572 /* free update tag lock */
4573 g_mutex_clear(&player->update_tag_lock);
4574 g_queue_free(player->bus_msg_q);
4575 /* free gapless play thread */
4576 if (player->gapless_play_thread) {
4577 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4578 player->gapless_play_thread_exit = TRUE;
4579 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4580 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4582 g_thread_join(player->gapless_play_thread);
4583 player->gapless_play_thread = NULL;
4585 g_mutex_clear(&player->gapless_play_thread_mutex);
4586 g_cond_clear(&player->gapless_play_thread_cond);
4589 /* release attributes */
4590 _mmplayer_deconstruct_attribute(handle);
4598 __mmplayer_init_gstreamer(mmplayer_t *player)
4600 static gboolean initialized = FALSE;
4601 static const int max_argc = 50;
4603 gchar **argv = NULL;
4604 gchar **argv2 = NULL;
4610 LOGD("gstreamer already initialized.");
4615 argc = malloc(sizeof(int));
4616 argv = malloc(sizeof(gchar *) * max_argc);
4617 argv2 = malloc(sizeof(gchar *) * max_argc);
4619 if (!argc || !argv || !argv2)
4622 memset(argv, 0, sizeof(gchar *) * max_argc);
4623 memset(argv2, 0, sizeof(gchar *) * max_argc);
4627 argv[0] = g_strdup("mmplayer");
4630 for (i = 0; i < 5; i++) {
4631 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4632 if (strlen(player->ini.gst_param[i]) > 0) {
4633 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4638 /* we would not do fork for scanning plugins */
4639 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4642 /* check disable registry scan */
4643 if (player->ini.skip_rescan) {
4644 argv[*argc] = g_strdup("--gst-disable-registry-update");
4648 /* check disable segtrap */
4649 if (player->ini.disable_segtrap) {
4650 argv[*argc] = g_strdup("--gst-disable-segtrap");
4654 LOGD("initializing gstreamer with following parameter");
4655 LOGD("argc : %d", *argc);
4658 for (i = 0; i < arg_count; i++) {
4660 LOGD("argv[%d] : %s", i, argv2[i]);
4663 /* initializing gstreamer */
4664 if (!gst_init_check(argc, &argv, &err)) {
4665 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4672 for (i = 0; i < arg_count; i++) {
4673 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4674 MMPLAYER_FREEIF(argv2[i]);
4677 MMPLAYER_FREEIF(argv);
4678 MMPLAYER_FREEIF(argv2);
4679 MMPLAYER_FREEIF(argc);
4689 for (i = 0; i < arg_count; i++) {
4690 LOGD("free[%d] : %s", i, argv2[i]);
4691 MMPLAYER_FREEIF(argv2[i]);
4694 MMPLAYER_FREEIF(argv);
4695 MMPLAYER_FREEIF(argv2);
4696 MMPLAYER_FREEIF(argc);
4702 __mmplayer_check_async_state_transition(mmplayer_t *player)
4704 GstState element_state = GST_STATE_VOID_PENDING;
4705 GstState element_pending_state = GST_STATE_VOID_PENDING;
4706 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4707 GstElement *element = NULL;
4708 gboolean async = FALSE;
4710 /* check player handle */
4711 MMPLAYER_RETURN_IF_FAIL(player &&
4713 player->pipeline->mainbin &&
4714 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4717 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4719 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4720 LOGD("don't need to check the pipeline state");
4724 MMPLAYER_PRINT_STATE(player);
4726 /* wait for state transition */
4727 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4728 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4730 if (ret == GST_STATE_CHANGE_FAILURE) {
4731 LOGE(" [%s] state : %s pending : %s",
4732 GST_ELEMENT_NAME(element),
4733 gst_element_state_get_name(element_state),
4734 gst_element_state_get_name(element_pending_state));
4736 /* dump state of all element */
4737 __mmplayer_dump_pipeline_state(player);
4742 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4747 _mmplayer_destroy(MMHandleType handle)
4749 mmplayer_t *player = MM_PLAYER_CAST(handle);
4753 /* check player handle */
4754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4756 /* destroy can called at anytime */
4757 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4759 /* check async state transition */
4760 __mmplayer_check_async_state_transition(player);
4762 /* release gapless play thread */
4763 if (player->gapless_play_thread) {
4764 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4765 player->gapless_play_thread_exit = TRUE;
4766 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4767 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4769 LOGD("waitting for gapless play thread exit");
4770 g_thread_join(player->gapless_play_thread);
4771 g_mutex_clear(&player->gapless_play_thread_mutex);
4772 g_cond_clear(&player->gapless_play_thread_cond);
4773 LOGD("gapless play thread released");
4776 _mmplayer_release_video_capture(player);
4778 /* de-initialize resource manager */
4779 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4780 player->resource_manager))
4781 LOGE("failed to deinitialize resource manager");
4783 /* release pipeline */
4784 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4785 LOGE("failed to destory pipeline");
4786 return MM_ERROR_PLAYER_INTERNAL;
4789 g_queue_free(player->bus_msg_q);
4791 /* release subtitle info lock and cond */
4792 g_mutex_clear(&player->subtitle_info_mutex);
4793 g_cond_clear(&player->subtitle_info_cond);
4795 __mmplayer_release_dump_list(player->dump_list);
4797 /* release miscellaneous information */
4798 __mmplayer_release_misc(player);
4800 /* release miscellaneous information.
4801 these info needs to be released after pipeline is destroyed. */
4802 __mmplayer_release_misc_post(player);
4804 /* release attributes */
4805 _mmplayer_deconstruct_attribute(handle);
4808 g_mutex_clear(&player->fsink_lock);
4811 g_mutex_clear(&player->update_tag_lock);
4813 /* release video bo lock and cond */
4814 g_mutex_clear(&player->video_bo_mutex);
4815 g_cond_clear(&player->video_bo_cond);
4817 /* release media stream callback lock */
4818 g_mutex_clear(&player->media_stream_cb_lock);
4822 return MM_ERROR_NONE;
4826 _mmplayer_realize(MMHandleType hplayer)
4828 mmplayer_t *player = (mmplayer_t *)hplayer;
4831 MMHandleType attrs = 0;
4832 int ret = MM_ERROR_NONE;
4836 /* check player handle */
4837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4839 /* check current state */
4840 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4842 attrs = MMPLAYER_GET_ATTRS(player);
4844 LOGE("fail to get attributes.");
4845 return MM_ERROR_PLAYER_INTERNAL;
4847 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4848 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4850 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4851 ret = __mmplayer_parse_profile((const char *)uri, param, &player->profile);
4853 if (ret != MM_ERROR_NONE) {
4854 LOGE("failed to parse profile");
4859 if (uri && (strstr(uri, "es_buff://"))) {
4860 if (strstr(uri, "es_buff://push_mode"))
4861 player->es_player_push_mode = TRUE;
4863 player->es_player_push_mode = FALSE;
4866 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4867 LOGW("mms protocol is not supported format.");
4868 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4871 if (MMPLAYER_IS_STREAMING(player))
4872 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4874 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4876 player->smooth_streaming = FALSE;
4877 player->videodec_linked = 0;
4878 player->audiodec_linked = 0;
4879 player->textsink_linked = 0;
4880 player->is_external_subtitle_present = FALSE;
4881 player->is_external_subtitle_added_now = FALSE;
4882 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
4883 player->video360_metadata.is_spherical = -1;
4884 player->is_openal_plugin_used = FALSE;
4885 player->demux_pad_index = 0;
4886 player->subtitle_language_list = NULL;
4887 player->is_subtitle_force_drop = FALSE;
4889 __mmplayer_track_initialize(player);
4890 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
4892 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
4893 gint prebuffer_ms = 0, rebuffer_ms = 0;
4895 player->streamer = __mm_player_streaming_create();
4896 __mm_player_streaming_initialize(player->streamer, TRUE);
4898 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
4899 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
4901 if (prebuffer_ms > 0) {
4902 prebuffer_ms = MAX(prebuffer_ms, 1000);
4903 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
4906 if (rebuffer_ms > 0) {
4907 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
4908 rebuffer_ms = MAX(rebuffer_ms, 1000);
4909 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
4912 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
4913 player->streamer->buffering_req.rebuffer_time);
4916 /* realize pipeline */
4917 ret = __mmplayer_gst_realize(player);
4918 if (ret != MM_ERROR_NONE)
4919 LOGE("fail to realize the player.");
4921 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
4929 _mmplayer_unrealize(MMHandleType hplayer)
4931 mmplayer_t *player = (mmplayer_t *)hplayer;
4932 int ret = MM_ERROR_NONE;
4936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4938 MMPLAYER_CMD_UNLOCK(player);
4939 /* destroy the gst bus msg thread which is created during realize.
4940 this funct have to be called before getting cmd lock. */
4941 __mmplayer_bus_msg_thread_destroy(player);
4942 MMPLAYER_CMD_LOCK(player);
4944 /* check current state */
4945 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
4947 /* check async state transition */
4948 __mmplayer_check_async_state_transition(player);
4950 /* unrealize pipeline */
4951 ret = __mmplayer_gst_unrealize(player);
4953 /* set asm stop if success */
4954 if (MM_ERROR_NONE == ret) {
4955 if (!player->interrupted_by_resource) {
4956 if (player->video_decoder_resource != NULL) {
4957 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4958 player->video_decoder_resource);
4959 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4960 LOGE("failed to mark decoder resource for release, ret(0x%x)", ret);
4962 player->video_decoder_resource = NULL;
4965 if (player->video_overlay_resource != NULL) {
4966 ret = mm_resource_manager_mark_for_release(player->resource_manager,
4967 player->video_overlay_resource);
4968 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4969 LOGE("failed to mark overlay resource for release, ret(0x%x)", ret);
4971 player->video_overlay_resource = NULL;
4974 ret = mm_resource_manager_commit(player->resource_manager);
4975 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
4976 LOGE("failed to commit resource releases, ret(0x%x)", ret);
4979 LOGE("failed and don't change asm state to stop");
4987 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
4989 mmplayer_t *player = (mmplayer_t *)hplayer;
4991 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4993 return __mmplayer_gst_set_message_callback(player, callback, user_param);
4997 _mmplayer_get_state(MMHandleType hplayer, int *state)
4999 mmplayer_t *player = (mmplayer_t *)hplayer;
5001 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5003 *state = MMPLAYER_CURRENT_STATE(player);
5005 return MM_ERROR_NONE;
5010 _mmplayer_set_volume(MMHandleType hplayer, mmplayer_volume_type_t volume)
5012 mmplayer_t *player = (mmplayer_t *)hplayer;
5013 GstElement *vol_element = NULL;
5018 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5020 LOGD("volume [L]=%f:[R]=%f",
5021 volume.level[MM_VOLUME_CHANNEL_LEFT], volume.level[MM_VOLUME_CHANNEL_RIGHT]);
5023 /* invalid factor range or not */
5024 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++) {
5025 if (volume.level[i] < MM_VOLUME_FACTOR_MIN || volume.level[i] > MM_VOLUME_FACTOR_MAX) {
5026 LOGE("Invalid factor!(valid factor:0~1.0)");
5027 return MM_ERROR_INVALID_ARGUMENT;
5031 /* not support to set other value into each channel */
5032 if ((volume.level[MM_VOLUME_CHANNEL_LEFT] != volume.level[MM_VOLUME_CHANNEL_RIGHT]))
5033 return MM_ERROR_INVALID_ARGUMENT;
5035 /* Save volume to handle. Currently the first array element will be saved. */
5036 player->sound.volume = volume.level[MM_VOLUME_CHANNEL_LEFT];
5038 /* check pipeline handle */
5039 if (!player->pipeline || !player->pipeline->audiobin) {
5040 LOGD("audiobin is not created yet");
5041 LOGD("but, current stored volume will be set when it's created.");
5043 /* NOTE : stored volume will be used in create_audiobin
5044 * returning MM_ERROR_NONE here makes application to able to
5045 * set volume at anytime.
5047 return MM_ERROR_NONE;
5050 /* setting volume to volume element */
5051 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5054 LOGD("volume is set [%f]", player->sound.volume);
5055 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5060 return MM_ERROR_NONE;
5064 _mmplayer_get_volume(MMHandleType hplayer, mmplayer_volume_type_t *volume)
5066 mmplayer_t *player = (mmplayer_t *)hplayer;
5071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5072 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5074 /* returning stored volume */
5075 for (i = 0; i < MM_VOLUME_CHANNEL_NUM; i++)
5076 volume->level[i] = player->sound.volume;
5080 return MM_ERROR_NONE;
5084 _mmplayer_set_mute(MMHandleType hplayer, int mute)
5086 mmplayer_t *player = (mmplayer_t *)hplayer;
5087 GstElement *vol_element = NULL;
5091 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5093 /* mute value shoud 0 or 1 */
5094 if (mute != 0 && mute != 1) {
5095 LOGE("bad mute value");
5097 /* FIXIT : definitly, we need _BAD_PARAM error code */
5098 return MM_ERROR_INVALID_ARGUMENT;
5101 player->sound.mute = mute;
5103 /* just hold mute value if pipeline is not ready */
5104 if (!player->pipeline || !player->pipeline->audiobin) {
5105 LOGD("pipeline is not ready. holding mute value");
5106 return MM_ERROR_NONE;
5109 vol_element = player->pipeline->audiobin[MMPLAYER_A_VOL].gst;
5111 /* NOTE : volume will only created when the bt is enabled */
5113 LOGD("mute : %d", mute);
5114 g_object_set(vol_element, "mute", mute, NULL);
5116 LOGD("volume elemnet is not created. using volume in audiosink");
5120 return MM_ERROR_NONE;
5124 _mmplayer_get_mute(MMHandleType hplayer, int *pmute)
5126 mmplayer_t *player = (mmplayer_t *)hplayer;
5130 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5131 MMPLAYER_RETURN_VAL_IF_FAIL(pmute, MM_ERROR_INVALID_ARGUMENT);
5133 /* just hold mute value if pipeline is not ready */
5134 if (!player->pipeline || !player->pipeline->audiobin) {
5135 LOGD("pipeline is not ready. returning stored value");
5136 *pmute = player->sound.mute;
5137 return MM_ERROR_NONE;
5140 *pmute = player->sound.mute;
5144 return MM_ERROR_NONE;
5148 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5150 mmplayer_t *player = (mmplayer_t *)hplayer;
5154 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5156 player->video_stream_changed_cb = callback;
5157 player->video_stream_changed_cb_user_param = user_param;
5158 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5162 return MM_ERROR_NONE;
5166 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5168 mmplayer_t *player = (mmplayer_t *)hplayer;
5172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5174 player->audio_stream_changed_cb = callback;
5175 player->audio_stream_changed_cb_user_param = user_param;
5176 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5180 return MM_ERROR_NONE;
5184 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5186 mmplayer_t *player = (mmplayer_t *)hplayer;
5190 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5192 player->audio_decoded_cb = callback;
5193 player->audio_decoded_cb_user_param = user_param;
5194 player->audio_extract_opt = opt;
5195 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5199 return MM_ERROR_NONE;
5203 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5205 mmplayer_t *player = (mmplayer_t *)hplayer;
5209 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5211 if (callback && !player->bufmgr)
5212 player->bufmgr = tbm_bufmgr_init(-1);
5214 player->set_mode.video_export = (callback) ? true : false;
5215 player->video_decoded_cb = callback;
5216 player->video_decoded_cb_user_param = user_param;
5218 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5222 return MM_ERROR_NONE;
5226 _mmplayer_start(MMHandleType hplayer)
5228 mmplayer_t *player = (mmplayer_t *)hplayer;
5229 gint ret = MM_ERROR_NONE;
5233 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235 /* check current state */
5236 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5238 /* start pipeline */
5239 ret = __mmplayer_gst_start(player);
5240 if (ret != MM_ERROR_NONE)
5241 LOGE("failed to start player.");
5243 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5244 LOGD("force playing start even during buffering");
5245 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5253 /* NOTE: post "not supported codec message" to application
5254 * when one codec is not found during AUTOPLUGGING in MSL.
5255 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5256 * And, if any codec is not found, don't send message here.
5257 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5260 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5262 MMMessageParamType msg_param;
5263 memset(&msg_param, 0, sizeof(MMMessageParamType));
5264 gboolean post_msg_direct = FALSE;
5268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5270 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5271 player->not_supported_codec, player->can_support_codec);
5273 if (player->not_found_demuxer) {
5274 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5275 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5277 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5278 MMPLAYER_FREEIF(msg_param.data);
5280 return MM_ERROR_NONE;
5283 if (player->not_supported_codec) {
5284 if (player->can_support_codec) {
5285 // There is one codec to play
5286 post_msg_direct = TRUE;
5288 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5289 post_msg_direct = TRUE;
5292 if (post_msg_direct) {
5293 MMMessageParamType msg_param;
5294 memset(&msg_param, 0, sizeof(MMMessageParamType));
5296 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5297 LOGW("not found AUDIO codec, posting error code to application.");
5299 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5300 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5301 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5302 LOGW("not found VIDEO codec, posting error code to application.");
5304 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5305 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5308 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5310 MMPLAYER_FREEIF(msg_param.data);
5312 return MM_ERROR_NONE;
5314 // no any supported codec case
5315 LOGW("not found any codec, posting error code to application.");
5317 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5318 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5319 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5321 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5322 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5325 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5327 MMPLAYER_FREEIF(msg_param.data);
5333 return MM_ERROR_NONE;
5337 __mmplayer_check_pipeline(mmplayer_t *player)
5339 GstState element_state = GST_STATE_VOID_PENDING;
5340 GstState element_pending_state = GST_STATE_VOID_PENDING;
5342 int ret = MM_ERROR_NONE;
5344 if (!player->gapless.reconfigure)
5347 LOGW("pipeline is under construction.");
5349 MMPLAYER_PLAYBACK_LOCK(player);
5350 MMPLAYER_PLAYBACK_UNLOCK(player);
5352 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5354 /* wait for state transition */
5355 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5356 if (ret == GST_STATE_CHANGE_FAILURE)
5357 LOGE("failed to change pipeline state within %d sec", timeout);
5360 /* NOTE : it should be able to call 'stop' anytime*/
5362 _mmplayer_stop(MMHandleType hplayer)
5364 mmplayer_t *player = (mmplayer_t *)hplayer;
5365 int ret = MM_ERROR_NONE;
5369 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5371 /* check current state */
5372 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5374 /* check pipline building state */
5375 __mmplayer_check_pipeline(player);
5376 __mmplayer_reset_gapless_state(player);
5378 /* NOTE : application should not wait for EOS after calling STOP */
5379 __mmplayer_cancel_eos_timer(player);
5382 player->seek_state = MMPLAYER_SEEK_NONE;
5385 ret = __mmplayer_gst_stop(player);
5387 if (ret != MM_ERROR_NONE)
5388 LOGE("failed to stop player.");
5396 _mmplayer_pause(MMHandleType hplayer)
5398 mmplayer_t *player = (mmplayer_t *)hplayer;
5399 gint64 pos_nsec = 0;
5400 gboolean async = FALSE;
5401 gint ret = MM_ERROR_NONE;
5405 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5407 /* check current state */
5408 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5410 /* check pipline building state */
5411 __mmplayer_check_pipeline(player);
5413 switch (MMPLAYER_CURRENT_STATE(player)) {
5414 case MM_PLAYER_STATE_READY:
5416 /* check prepare async or not.
5417 * In the case of streaming playback, it's recommned to avoid blocking wait.
5419 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5420 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5422 /* Changing back sync of rtspsrc to async */
5423 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5424 LOGD("async prepare working mode for rtsp");
5430 case MM_PLAYER_STATE_PLAYING:
5432 /* NOTE : store current point to overcome some bad operation
5433 *(returning zero when getting current position in paused state) of some
5436 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5437 LOGW("getting current position failed in paused");
5439 player->last_position = pos_nsec;
5441 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5442 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5443 This causes problem is position calculation during normal pause resume scenarios also.
5444 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5445 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5446 (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5447 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5453 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5454 LOGD("doing async pause in case of ms buff src");
5458 /* pause pipeline */
5459 ret = __mmplayer_gst_pause(player, async);
5461 if (ret != MM_ERROR_NONE)
5462 LOGE("failed to pause player. ret : 0x%x", ret);
5464 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5465 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5466 LOGE("failed to update display_rotation");
5474 /* in case of streaming, pause could take long time.*/
5476 _mmplayer_abort_pause(MMHandleType hplayer)
5478 mmplayer_t *player = (mmplayer_t *)hplayer;
5479 int ret = MM_ERROR_NONE;
5483 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5485 player->pipeline->mainbin,
5486 MM_ERROR_PLAYER_NOT_INITIALIZED);
5488 LOGD("set the pipeline state to READY");
5490 /* set state to READY */
5491 ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5492 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5493 if (ret != MM_ERROR_NONE) {
5494 LOGE("fail to change state to READY");
5495 return MM_ERROR_PLAYER_INTERNAL;
5498 LOGD("succeeded in changing state to READY");
5503 _mmplayer_resume(MMHandleType hplayer)
5505 mmplayer_t *player = (mmplayer_t *)hplayer;
5506 int ret = MM_ERROR_NONE;
5507 gboolean async = FALSE;
5511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5513 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5514 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5515 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5519 /* Changing back sync mode rtspsrc to async */
5520 LOGD("async resume for rtsp case");
5524 /* check current state */
5525 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5527 ret = __mmplayer_gst_resume(player, async);
5528 if (ret != MM_ERROR_NONE)
5529 LOGE("failed to resume player.");
5531 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5532 LOGD("force resume even during buffering");
5533 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5542 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5544 mmplayer_t *player = (mmplayer_t *)hplayer;
5545 gint64 pos_nsec = 0;
5546 int ret = MM_ERROR_NONE;
5548 signed long long start = 0, stop = 0;
5549 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5552 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5553 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5555 /* The sound of video is not supported under 0.0 and over 2.0. */
5556 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5557 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5560 _mmplayer_set_mute(hplayer, mute);
5562 if (player->playback_rate == rate)
5563 return MM_ERROR_NONE;
5565 /* If the position is reached at start potion during fast backward, EOS is posted.
5566 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5568 player->playback_rate = rate;
5570 current_state = MMPLAYER_CURRENT_STATE(player);
5572 if (current_state != MM_PLAYER_STATE_PAUSED)
5573 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5575 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5577 if ((current_state == MM_PLAYER_STATE_PAUSED)
5578 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5579 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5580 pos_nsec = player->last_position;
5585 stop = GST_CLOCK_TIME_NONE;
5587 start = GST_CLOCK_TIME_NONE;
5591 if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5592 player->playback_rate,
5594 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5595 GST_SEEK_TYPE_SET, start,
5596 GST_SEEK_TYPE_SET, stop)) {
5597 LOGE("failed to set speed playback");
5598 return MM_ERROR_PLAYER_SEEK;
5601 LOGD("succeeded to set speed playback as %0.1f", rate);
5605 return MM_ERROR_NONE;;
5609 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5611 mmplayer_t *player = (mmplayer_t *)hplayer;
5612 int ret = MM_ERROR_NONE;
5616 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5618 /* check pipline building state */
5619 __mmplayer_check_pipeline(player);
5621 ret = __mmplayer_gst_set_position(player, position, FALSE);
5629 _mmplayer_get_position(MMHandleType hplayer, gint64 *position)
5631 mmplayer_t *player = (mmplayer_t *)hplayer;
5632 int ret = MM_ERROR_NONE;
5634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5636 ret = __mmplayer_gst_get_position(player, position);
5642 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5644 mmplayer_t *player = (mmplayer_t *)hplayer;
5645 int ret = MM_ERROR_NONE;
5647 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5648 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5650 if (g_strrstr(player->type, "video/mpegts"))
5651 __mmplayer_update_duration_value(player);
5653 *duration = player->duration;
5658 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5660 mmplayer_t *player = (mmplayer_t *)hplayer;
5661 int ret = MM_ERROR_NONE;
5663 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5665 ret = __mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5671 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5673 mmplayer_t *player = (mmplayer_t *)hplayer;
5674 int ret = MM_ERROR_NONE;
5678 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5680 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5688 __mmplayer_is_midi_type(gchar *str_caps)
5690 if ((g_strrstr(str_caps, "audio/midi")) ||
5691 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5692 (g_strrstr(str_caps, "application/x-smaf")) ||
5693 (g_strrstr(str_caps, "audio/x-imelody")) ||
5694 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5695 (g_strrstr(str_caps, "audio/xmf")) ||
5696 (g_strrstr(str_caps, "audio/mxmf"))) {
5705 __mmplayer_is_only_mp3_type(gchar *str_caps)
5707 if (g_strrstr(str_caps, "application/x-id3") ||
5708 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5714 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5716 GstStructure *caps_structure = NULL;
5717 gint samplerate = 0;
5721 MMPLAYER_RETURN_IF_FAIL(player && caps);
5723 caps_structure = gst_caps_get_structure(caps, 0);
5725 /* set stream information */
5726 gst_structure_get_int(caps_structure, "rate", &samplerate);
5727 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5729 gst_structure_get_int(caps_structure, "channels", &channels);
5730 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5732 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5736 __mmplayer_update_content_type_info(mmplayer_t *player)
5739 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5741 if (__mmplayer_is_midi_type(player->type)) {
5742 player->bypass_audio_effect = TRUE;
5746 if (!player->streamer) {
5747 LOGD("no need to check streaming type");
5751 if (g_strrstr(player->type, "application/x-hls")) {
5752 /* If it can't know exact type when it parses uri because of redirection case,
5753 * it will be fixed by typefinder or when doing autoplugging.
5755 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5756 player->streamer->is_adaptive_streaming = TRUE;
5757 } else if (g_strrstr(player->type, "application/dash+xml")) {
5758 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5759 player->streamer->is_adaptive_streaming = TRUE;
5762 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5763 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5764 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5766 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5767 if (player->streamer->is_adaptive_streaming)
5768 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5770 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5774 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5779 __mmplayer_typefind_have_type(GstElement *tf, guint probability,
5780 GstCaps *caps, gpointer data)
5782 mmplayer_t *player = (mmplayer_t *)data;
5787 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5789 /* store type string */
5790 MMPLAYER_FREEIF(player->type);
5791 player->type = gst_caps_to_string(caps);
5793 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5794 player, player->type, probability, gst_caps_get_size(caps));
5796 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5797 (g_strrstr(player->type, "audio/x-raw-int"))) {
5798 LOGE("not support media format");
5800 if (player->msg_posted == FALSE) {
5801 MMMessageParamType msg_param;
5802 memset(&msg_param, 0, sizeof(MMMessageParamType));
5804 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5805 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5807 /* don't post more if one was sent already */
5808 player->msg_posted = TRUE;
5813 __mmplayer_update_content_type_info(player);
5815 pad = gst_element_get_static_pad(tf, "src");
5817 LOGE("fail to get typefind src pad.");
5821 if (!__mmplayer_gst_create_decoder(player, pad, caps)) {
5822 gboolean async = FALSE;
5823 LOGE("failed to autoplug %s", player->type);
5825 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5827 if (async && player->msg_posted == FALSE)
5828 __mmplayer_handle_missed_plugin(player);
5832 gst_object_unref(GST_OBJECT(pad));
5840 __mmplayer_gst_make_decodebin(mmplayer_t *player)
5842 GstElement *decodebin = NULL;
5846 /* create decodebin */
5847 decodebin = gst_element_factory_make("decodebin", NULL);
5850 LOGE("fail to create decodebin");
5854 /* raw pad handling signal */
5855 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5856 G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player);
5858 /* no-more-pad pad handling signal */
5859 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5860 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5862 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5863 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5865 /* This signal is emitted when a pad for which there is no further possible
5866 decoding is added to the decodebin.*/
5867 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5868 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5870 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5871 before looking for any elements that can handle that stream.*/
5872 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5873 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5875 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5876 before looking for any elements that can handle that stream.*/
5877 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5878 G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player);
5880 /* This signal is emitted once decodebin has finished decoding all the data.*/
5881 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5882 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5884 /* This signal is emitted when a element is added to the bin.*/
5885 __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5886 G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player);
5893 __mmplayer_gst_make_queue2(mmplayer_t *player)
5895 GstElement *queue2 = NULL;
5896 gint64 dur_bytes = 0L;
5897 mmplayer_gst_element_t *mainbin = NULL;
5898 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5901 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5903 mainbin = player->pipeline->mainbin;
5905 queue2 = gst_element_factory_make("queue2", "queue2");
5907 LOGE("failed to create buffering queue element");
5911 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5912 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5914 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5916 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5917 * skip the pull mode(file or ring buffering) setting. */
5918 if (dur_bytes > 0) {
5919 if (!g_strrstr(player->type, "video/mpegts")) {
5920 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5921 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5927 __mm_player_streaming_set_queue2(player->streamer,
5931 (guint64)dur_bytes); /* no meaning at the moment */
5937 __mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
5939 mmplayer_gst_element_t *mainbin = NULL;
5940 GstElement *decodebin = NULL;
5941 GstElement *queue2 = NULL;
5942 GstPad *sinkpad = NULL;
5943 GstPad *qsrcpad = NULL;
5946 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
5948 mainbin = player->pipeline->mainbin;
5950 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
5952 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
5953 LOGW("need to check: muxed buffer is not null");
5956 queue2 = __mmplayer_gst_make_queue2(player);
5958 LOGE("failed to make queue2");
5962 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
5963 LOGE("failed to add buffering queue");
5967 sinkpad = gst_element_get_static_pad(queue2, "sink");
5968 qsrcpad = gst_element_get_static_pad(queue2, "src");
5970 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
5971 LOGE("failed to link [%s:%s]-[%s:%s]",
5972 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
5976 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
5977 LOGE("failed to sync queue2 state with parent");
5981 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
5982 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
5986 gst_object_unref(GST_OBJECT(sinkpad));
5990 /* create decodebin */
5991 decodebin = __mmplayer_gst_make_decodebin(player);
5993 LOGE("failed to make decodebin");
5997 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
5998 LOGE("failed to add decodebin");
6002 /* to force caps on the decodebin element and avoid reparsing stuff by
6003 * typefind. It also avoids a deadlock in the way typefind activates pads in
6004 * the state change */
6005 g_object_set(decodebin, "sink-caps", caps, NULL);
6007 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6009 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6010 LOGE("failed to link [%s:%s]-[%s:%s]",
6011 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6015 gst_object_unref(GST_OBJECT(sinkpad));
6017 gst_object_unref(GST_OBJECT(qsrcpad));
6020 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6021 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6023 /* set decodebin property about buffer in streaming playback. *
6024 * in case of HLS/DASH, it does not need to have big buffer *
6025 * because it is kind of adaptive streaming. */
6026 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6027 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6028 gint high_percent = 0;
6030 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6031 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6033 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6035 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6037 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6038 "high-percent", high_percent,
6039 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6040 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6041 "max-size-buffers", 0, NULL); // disable or automatic
6044 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6045 LOGE("failed to sync decodebin state with parent");
6056 gst_object_unref(GST_OBJECT(sinkpad));
6059 gst_object_unref(GST_OBJECT(qsrcpad));
6062 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6063 * You need to explicitly set elements to the NULL state before
6064 * dropping the final reference, to allow them to clean up.
6066 gst_element_set_state(queue2, GST_STATE_NULL);
6068 /* And, it still has a parent "player".
6069 * You need to let the parent manage the object instead of unreffing the object directly.
6071 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6072 gst_object_unref(queue2);
6077 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6078 * You need to explicitly set elements to the NULL state before
6079 * dropping the final reference, to allow them to clean up.
6081 gst_element_set_state(decodebin, GST_STATE_NULL);
6083 /* And, it still has a parent "player".
6084 * You need to let the parent manage the object instead of unreffing the object directly.
6087 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6088 gst_object_unref(decodebin);
6096 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6100 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6101 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6103 LOGD("class : %s, mime : %s", factory_class, mime);
6105 /* add missing plugin */
6106 /* NOTE : msl should check missing plugin for image mime type.
6107 * Some motion jpeg clips can have playable audio track.
6108 * So, msl have to play audio after displaying popup written video format not supported.
6110 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6111 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6112 LOGD("not found demuxer");
6113 player->not_found_demuxer = TRUE;
6114 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6120 if (!g_strrstr(factory_class, "Demuxer")) {
6121 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6122 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6123 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6125 /* check that clip have multi tracks or not */
6126 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6127 LOGD("video plugin is already linked");
6129 LOGW("add VIDEO to missing plugin");
6130 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6131 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6133 } else if (g_str_has_prefix(mime, "audio")) {
6134 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6135 LOGD("audio plugin is already linked");
6137 LOGW("add AUDIO to missing plugin");
6138 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6139 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6147 return MM_ERROR_NONE;
6151 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6153 mmplayer_t *player = (mmplayer_t *)data;
6157 MMPLAYER_RETURN_IF_FAIL(player);
6159 /* remove fakesink. */
6160 if (!__mmplayer_gst_remove_fakesink(player,
6161 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6162 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6163 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6164 * source element are not same. To overcome this situation, this function will called
6165 * several places and several times. Therefore, this is not an error case.
6170 LOGD("[handle: %p] pipeline has completely constructed", player);
6172 if ((player->ini.async_start) &&
6173 (player->msg_posted == FALSE) &&
6174 (player->cmd >= MMPLAYER_COMMAND_START))
6175 __mmplayer_handle_missed_plugin(player);
6177 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6181 __mmplayer_check_profile(void)
6184 static int profile_tv = -1;
6186 if (__builtin_expect(profile_tv != -1, 1))
6189 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6190 switch (*profileName) {
6205 __mmplayer_get_next_uri(mmplayer_t *player)
6207 mmplayer_parse_profile_t profile;
6209 guint num_of_list = 0;
6212 num_of_list = g_list_length(player->uri_info.uri_list);
6213 uri_idx = player->uri_info.uri_idx;
6215 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6216 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6217 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6219 LOGW("next uri does not exist");
6223 if (__mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6224 LOGE("failed to parse profile");
6228 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6229 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6230 LOGW("uri type is not supported(%d)", profile.uri_type);
6234 LOGD("success to find next uri %d", uri_idx);
6238 if (uri_idx == num_of_list) {
6239 LOGE("failed to find next uri");
6243 player->uri_info.uri_idx = uri_idx;
6244 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6246 if (mm_attrs_commit_all(player->attrs)) {
6247 LOGE("failed to commit");
6251 SECURE_LOGD("next playback uri: %s", uri);
6256 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6258 #define REPEAT_COUNT_INFINITELY -1
6259 #define REPEAT_COUNT_MIN 2
6261 MMHandleType attrs = 0;
6265 guint num_of_list = 0;
6266 int profile_tv = -1;
6270 LOGD("checking for gapless play option");
6272 if (player->pipeline->textbin) {
6273 LOGE("subtitle path is enabled. gapless play is not supported.");
6277 attrs = MMPLAYER_GET_ATTRS(player);
6279 LOGE("fail to get attributes.");
6283 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6285 /* gapless playback is not supported in case of video at TV profile. */
6286 profile_tv = __mmplayer_check_profile();
6287 if (profile_tv && video) {
6288 LOGW("not support video gapless playback");
6292 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6293 LOGE("failed to get play count");
6295 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6296 LOGE("failed to get gapless mode");
6298 /* check repeat count in case of audio */
6300 (video || (count != REPEAT_COUNT_INFINITELY && count < REPEAT_COUNT_MIN))) {
6301 LOGW("gapless is disabled");
6305 num_of_list = g_list_length(player->uri_info.uri_list);
6307 LOGD("repeat count = %d, num_of_list = %d", count, num_of_list);
6309 if (num_of_list == 0) {
6310 /* audio looping path */
6311 if (count >= REPEAT_COUNT_MIN) {
6312 /* decrease play count */
6313 /* we succeeded to rewind. update play count and then wait for next EOS */
6315 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6316 /* commit attribute */
6317 if (mm_attrs_commit_all(attrs))
6318 LOGE("failed to commit attribute");
6320 } else if (count != REPEAT_COUNT_INFINITELY) {
6321 LOGD("there is no next uri and no repeat");
6324 LOGD("looping cnt %d", count);
6326 /* gapless playback path */
6327 if (!__mmplayer_get_next_uri(player)) {
6328 LOGE("failed to get next uri");
6335 LOGE("unable to play gapless path. EOS will be posted soon");
6340 __mmplayer_initialize_gapless_play(mmplayer_t *player)
6346 player->smooth_streaming = FALSE;
6347 player->videodec_linked = 0;
6348 player->audiodec_linked = 0;
6349 player->textsink_linked = 0;
6350 player->is_external_subtitle_present = FALSE;
6351 player->is_external_subtitle_added_now = FALSE;
6352 player->not_supported_codec = MISSING_PLUGIN_NONE;
6353 player->can_support_codec = FOUND_PLUGIN_NONE;
6354 player->pending_seek.is_pending = false;
6355 player->pending_seek.pos = 0;
6356 player->msg_posted = FALSE;
6357 player->has_many_types = FALSE;
6358 player->no_more_pad = FALSE;
6359 player->not_found_demuxer = 0;
6360 player->seek_state = MMPLAYER_SEEK_NONE;
6361 player->is_subtitle_force_drop = FALSE;
6362 player->play_subtitle = FALSE;
6363 player->adjust_subtitle_pos = 0;
6365 player->total_bitrate = 0;
6366 player->total_maximum_bitrate = 0;
6368 __mmplayer_track_initialize(player);
6369 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
6371 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
6372 player->bitrate[i] = 0;
6373 player->maximum_bitrate[i] = 0;
6376 if (player->v_stream_caps) {
6377 gst_caps_unref(player->v_stream_caps);
6378 player->v_stream_caps = NULL;
6381 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
6383 /* clean found audio decoders */
6384 if (player->audio_decoders) {
6385 GList *a_dec = player->audio_decoders;
6386 for (; a_dec; a_dec = g_list_next(a_dec)) {
6387 gchar *name = a_dec->data;
6388 MMPLAYER_FREEIF(name);
6390 g_list_free(player->audio_decoders);
6391 player->audio_decoders = NULL;
6398 __mmplayer_activate_next_source(mmplayer_t *player, GstState target)
6400 mmplayer_gst_element_t *mainbin = NULL;
6401 MMMessageParamType msg_param = {0,};
6402 GstElement *element = NULL;
6403 MMHandleType attrs = 0;
6405 main_element_id_e elem_idx = MMPLAYER_M_NUM;
6409 if (!player || !player->pipeline || !player->pipeline->mainbin) {
6410 LOGE("player is not initialized");
6414 mainbin = player->pipeline->mainbin;
6415 msg_param.code = MM_ERROR_PLAYER_INTERNAL;
6417 attrs = MMPLAYER_GET_ATTRS(player);
6419 LOGE("fail to get attributes");
6423 /* Initialize Player values */
6424 __mmplayer_initialize_gapless_play(player);
6426 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
6428 if (__mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) {
6429 LOGE("failed to parse profile");
6430 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6434 if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) ||
6435 (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) {
6436 LOGE("dash or hls is not supportable");
6437 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
6441 element = __mmplayer_gst_create_source(player);
6443 LOGE("no source element was created");
6447 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6448 LOGE("failed to add source element to pipeline");
6449 gst_object_unref(GST_OBJECT(element));
6454 /* take source element */
6455 mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC;
6456 mainbin[MMPLAYER_M_SRC].gst = element;
6460 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6461 if (player->streamer == NULL) {
6462 player->streamer = __mm_player_streaming_create();
6463 __mm_player_streaming_initialize(player->streamer, TRUE);
6466 elem_idx = MMPLAYER_M_TYPEFIND;
6467 element = gst_element_factory_make("typefind", "typefinder");
6468 __mmplayer_add_signal_connection(player, G_OBJECT(element),
6469 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player);
6471 elem_idx = MMPLAYER_M_AUTOPLUG;
6472 element = __mmplayer_gst_make_decodebin(player);
6475 /* check autoplug element is OK */
6477 LOGE("can not create element(%d)", elem_idx);
6481 if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) {
6482 LOGE("failed to add sinkbin to pipeline");
6483 gst_object_unref(GST_OBJECT(element));
6488 mainbin[elem_idx].id = elem_idx;
6489 mainbin[elem_idx].gst = element;
6491 if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) {
6492 LOGE("Failed to link src - autoplug(or typefind)");
6496 if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) {
6497 LOGE("Failed to change state of src element");
6501 if (!MMPLAYER_IS_HTTP_STREAMING(player)) {
6502 if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) {
6503 LOGE("Failed to change state of decodebin");
6507 if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) {
6508 LOGE("Failed to change state of src element");
6513 player->gapless.stream_changed = TRUE;
6514 player->gapless.running = TRUE;
6520 MMPLAYER_PLAYBACK_UNLOCK(player);
6522 if (!player->msg_posted) {
6523 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6524 player->msg_posted = TRUE;
6531 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6533 mmplayer_selector_t *selector = &player->selector[type];
6534 mmplayer_gst_element_t *sinkbin = NULL;
6535 main_element_id_e selectorId = MMPLAYER_M_NUM;
6536 main_element_id_e sinkId = MMPLAYER_M_NUM;
6537 GstPad *srcpad = NULL;
6538 GstPad *sinkpad = NULL;
6539 gboolean send_notice = FALSE;
6542 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6544 LOGD("type %d", type);
6547 case MM_PLAYER_TRACK_TYPE_AUDIO:
6548 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6549 sinkId = MMPLAYER_A_BIN;
6550 sinkbin = player->pipeline->audiobin;
6552 case MM_PLAYER_TRACK_TYPE_VIDEO:
6553 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6554 sinkId = MMPLAYER_V_BIN;
6555 sinkbin = player->pipeline->videobin;
6558 case MM_PLAYER_TRACK_TYPE_TEXT:
6559 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6560 sinkId = MMPLAYER_T_BIN;
6561 sinkbin = player->pipeline->textbin;
6564 LOGE("requested type is not supportable");
6569 if (player->pipeline->mainbin[selectorId].gst) {
6572 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6574 if (selector->event_probe_id != 0)
6575 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6576 selector->event_probe_id = 0;
6578 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6579 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6581 if (srcpad && sinkpad) {
6582 /* after getting drained signal there is no data flows, so no need to do pad_block */
6583 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6584 gst_pad_unlink(srcpad, sinkpad);
6586 /* send custom event to sink pad to handle it at video sink */
6588 LOGD("send custom event to sinkpad");
6589 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6590 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6591 gst_pad_send_event(sinkpad, event);
6595 gst_object_unref(sinkpad);
6598 gst_object_unref(srcpad);
6601 LOGD("selector release");
6603 /* release and unref requests pad from the selector */
6604 for (n = 0; n < selector->channels->len; n++) {
6605 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6606 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6608 g_ptr_array_set_size(selector->channels, 0);
6610 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6611 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6613 player->pipeline->mainbin[selectorId].gst = NULL;
6621 __mmplayer_deactivate_old_path(mmplayer_t *player)
6624 MMPLAYER_RETURN_IF_FAIL(player);
6626 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6627 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6628 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6629 LOGE("deactivate selector error");
6633 __mmplayer_track_destroy(player);
6634 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6636 if (player->streamer) {
6637 __mm_player_streaming_initialize(player->streamer, FALSE);
6638 __mm_player_streaming_destroy(player->streamer);
6639 player->streamer = NULL;
6642 MMPLAYER_PLAYBACK_LOCK(player);
6643 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6650 if (!player->msg_posted) {
6651 MMMessageParamType msg = {0,};
6654 msg.code = MM_ERROR_PLAYER_INTERNAL;
6655 LOGE("gapless_uri_play> deactivate error");
6657 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6658 player->msg_posted = TRUE;
6664 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6666 int result = MM_ERROR_NONE;
6667 mmplayer_t *player = (mmplayer_t *)hplayer;
6670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6672 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6673 if (mm_attrs_commit_all(player->attrs)) {
6674 LOGE("failed to commit the original uri.");
6675 result = MM_ERROR_PLAYER_INTERNAL;
6677 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6678 LOGE("failed to add the original uri in the uri list.");
6686 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6688 mmplayer_t *player = (mmplayer_t *)hplayer;
6689 guint num_of_list = 0;
6693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6694 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6696 if (player->pipeline && player->pipeline->textbin) {
6697 LOGE("subtitle path is enabled.");
6698 return MM_ERROR_PLAYER_INVALID_STATE;
6701 num_of_list = g_list_length(player->uri_info.uri_list);
6703 if (is_first_path) {
6704 if (num_of_list == 0) {
6705 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6706 SECURE_LOGD("add original path : %s", uri);
6708 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6709 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6711 SECURE_LOGD("change original path : %s", uri);
6714 MMHandleType attrs = 0;
6715 attrs = MMPLAYER_GET_ATTRS(player);
6717 if (num_of_list == 0) {
6718 char *original_uri = NULL;
6721 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6723 if (!original_uri) {
6724 LOGE("there is no original uri.");
6725 return MM_ERROR_PLAYER_INVALID_STATE;
6728 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6729 player->uri_info.uri_idx = 0;
6731 SECURE_LOGD("add original path at first : %s", original_uri);
6735 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6736 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6740 return MM_ERROR_NONE;
6744 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6746 mmplayer_t *player = (mmplayer_t *)hplayer;
6747 char *next_uri = NULL;
6748 guint num_of_list = 0;
6751 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6753 num_of_list = g_list_length(player->uri_info.uri_list);
6755 if (num_of_list > 0) {
6756 gint uri_idx = player->uri_info.uri_idx;
6758 if (uri_idx < num_of_list-1)
6763 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6764 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6766 *uri = g_strdup(next_uri);
6770 return MM_ERROR_NONE;
6774 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6775 GstCaps *caps, gpointer data)
6777 mmplayer_t *player = (mmplayer_t *)data;
6778 const gchar *klass = NULL;
6779 const gchar *mime = NULL;
6780 gchar *caps_str = NULL;
6782 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6783 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6784 caps_str = gst_caps_to_string(caps);
6786 LOGW("unknown type of caps : %s from %s",
6787 caps_str, GST_ELEMENT_NAME(elem));
6789 MMPLAYER_FREEIF(caps_str);
6791 /* There is no available codec. */
6792 __mmplayer_check_not_supported_codec(player, klass, mime);
6796 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6797 GstCaps *caps, gpointer data)
6799 mmplayer_t *player = (mmplayer_t *)data;
6800 const char *mime = NULL;
6801 gboolean ret = TRUE;
6803 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6804 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6806 if (g_str_has_prefix(mime, "audio")) {
6807 GstStructure *caps_structure = NULL;
6808 gint samplerate = 0;
6810 gchar *caps_str = NULL;
6812 caps_structure = gst_caps_get_structure(caps, 0);
6813 gst_structure_get_int(caps_structure, "rate", &samplerate);
6814 gst_structure_get_int(caps_structure, "channels", &channels);
6816 if ((channels > 0 && samplerate == 0)) {
6817 LOGD("exclude audio...");
6821 caps_str = gst_caps_to_string(caps);
6822 /* set it directly because not sent by TAG */
6823 if (g_strrstr(caps_str, "mobile-xmf"))
6824 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6825 MMPLAYER_FREEIF(caps_str);
6826 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6827 MMMessageParamType msg_param;
6828 memset(&msg_param, 0, sizeof(MMMessageParamType));
6829 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6830 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6831 LOGD("video file is not supported on this device");
6833 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6834 LOGD("already video linked");
6837 LOGD("found new stream");
6844 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6846 gboolean ret = TRUE;
6847 GDBusConnection *conn = NULL;
6849 GVariant *result = NULL;
6850 const gchar *dbus_device_type = NULL;
6851 const gchar *dbus_ret = NULL;
6854 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6856 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6862 result = g_dbus_connection_call_sync(conn,
6863 "org.pulseaudio.Server",
6864 "/org/pulseaudio/StreamManager",
6865 "org.pulseaudio.StreamManager",
6866 "GetCurrentMediaRoutingPath",
6867 g_variant_new("(s)", "out"),
6868 G_VARIANT_TYPE("(ss)"),
6869 G_DBUS_CALL_FLAGS_NONE,
6873 if (!result || err) {
6874 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6880 /* device type is listed in stream-map.json at mmfw-sysconf */
6881 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6883 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6884 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6889 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6890 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6891 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6892 LOGD("audio offload is supportable");
6898 LOGD("audio offload is not supportable");
6902 g_variant_unref(result);
6903 g_object_unref(conn);
6908 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6910 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6911 gint64 position = 0;
6913 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6914 player->pipeline && player->pipeline->mainbin);
6916 MMPLAYER_CMD_LOCK(player);
6917 current_state = MMPLAYER_CURRENT_STATE(player);
6919 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6920 LOGW("getting current position failed in paused");
6922 _mmplayer_unrealize((MMHandleType)player);
6923 _mmplayer_realize((MMHandleType)player);
6925 _mmplayer_set_position((MMHandleType)player, position);
6927 /* async not to be blocked in streaming case */
6928 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6929 if (mm_attrs_commit_all(player->attrs))
6930 LOGE("failed to commit");
6932 _mmplayer_pause((MMHandleType)player);
6934 if (current_state == MM_PLAYER_STATE_PLAYING)
6935 _mmplayer_start((MMHandleType)player);
6936 MMPLAYER_CMD_UNLOCK(player);
6938 LOGD("rebuilding audio pipeline is completed.");
6941 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6943 mmplayer_t *player = (mmplayer_t *)user_data;
6944 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6945 gboolean is_supportable = FALSE;
6947 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6948 LOGW("failed to get device type");
6950 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6952 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6953 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6954 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6955 LOGD("ignore this dev connected info");
6959 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6960 if (player->build_audio_offload == is_supportable) {
6961 LOGD("keep current pipeline without re-building");
6965 /* rebuild pipeline */
6966 LOGD("re-build pipeline - offload: %d", is_supportable);
6967 player->build_audio_offload = FALSE;
6968 __mmplayer_rebuild_audio_pipeline(player);
6974 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6976 unsigned int id = 0;
6978 if (player->audio_device_cb_id != 0) {
6979 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6983 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6984 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6985 LOGD("added device connected cb (%u)", id);
6986 player->audio_device_cb_id = id;
6988 LOGW("failed to add device connected cb");
6996 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6998 gboolean ret = FALSE;
6999 GstElementFactory *factory = NULL;
7002 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7004 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7005 if (!__mmplayer_is_only_mp3_type(player->type))
7008 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7009 LOGD("there is no audio offload sink");
7013 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7014 LOGW("there is no audio device type to support offload");
7018 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7020 LOGW("there is no installed audio offload sink element");
7023 gst_object_unref(factory);
7025 if (!__mmplayer_add_audio_device_connected_cb(player))
7028 if (!__mmplayer_is_audio_offload_device_type(player))
7031 LOGD("audio offload can be built");
7039 static GstAutoplugSelectResult
7040 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7042 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7044 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7045 int audio_offload = 0;
7047 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7048 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7050 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7051 LOGD("expose audio path to build offload output path");
7052 player->build_audio_offload = TRUE;
7053 /* update codec info */
7054 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7055 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7056 player->audiodec_linked = 1;
7058 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7062 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7064 LOGD("audio codec type: %d", codec_type);
7065 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7066 /* sw codec will be skipped */
7067 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7068 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7069 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7070 ret = GST_AUTOPLUG_SELECT_SKIP;
7074 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7075 /* hw codec will be skipped */
7076 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7077 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7078 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7079 ret = GST_AUTOPLUG_SELECT_SKIP;
7084 /* set stream information */
7085 if (!player->audiodec_linked)
7086 __mmplayer_set_audio_attrs(player, caps);
7088 /* update codec info */
7089 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7090 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7091 player->audiodec_linked = 1;
7093 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7095 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7097 LOGD("video codec type: %d", codec_type);
7098 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7099 /* sw codec is skipped */
7100 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7101 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7102 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7103 ret = GST_AUTOPLUG_SELECT_SKIP;
7107 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7108 /* hw codec is skipped */
7109 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7110 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7111 ret = GST_AUTOPLUG_SELECT_SKIP;
7116 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7117 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7119 /* mark video decoder for acquire */
7120 if (player->video_decoder_resource == NULL) {
7121 if (mm_resource_manager_mark_for_acquire(player->resource_manager,
7122 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
7123 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
7124 &player->video_decoder_resource)
7125 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7126 LOGE("could not mark video_decoder resource for acquire");
7127 ret = GST_AUTOPLUG_SELECT_SKIP;
7131 LOGW("video decoder resource is already acquired, skip it.");
7132 ret = GST_AUTOPLUG_SELECT_SKIP;
7136 player->interrupted_by_resource = FALSE;
7137 /* acquire resources for video playing */
7138 if (mm_resource_manager_commit(player->resource_manager)
7139 != MM_RESOURCE_MANAGER_ERROR_NONE) {
7140 LOGE("could not acquire resources for video decoding");
7141 ret = GST_AUTOPLUG_SELECT_SKIP;
7146 /* update codec info */
7147 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7148 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7149 player->videodec_linked = 1;
7157 __mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7158 GstCaps *caps, GstElementFactory *factory, gpointer data)
7160 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7161 mmplayer_t *player = (mmplayer_t *)data;
7163 gchar *factory_name = NULL;
7164 gchar *caps_str = NULL;
7165 const gchar *klass = NULL;
7168 factory_name = GST_OBJECT_NAME(factory);
7169 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7170 caps_str = gst_caps_to_string(caps);
7172 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7174 /* store type string */
7175 if (player->type == NULL) {
7176 player->type = gst_caps_to_string(caps);
7177 __mmplayer_update_content_type_info(player);
7180 /* filtering exclude keyword */
7181 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7182 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7183 LOGW("skipping [%s] by exculde keyword [%s]",
7184 factory_name, player->ini.exclude_element_keyword[idx]);
7186 result = GST_AUTOPLUG_SELECT_SKIP;
7191 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7192 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7193 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7194 factory_name, player->ini.unsupported_codec_keyword[idx]);
7195 result = GST_AUTOPLUG_SELECT_SKIP;
7200 /* exclude webm format */
7201 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7202 * because webm format is not supportable.
7203 * If webm is disabled in "autoplug-continue", there is no state change
7204 * failure or error because the decodebin will expose the pad directly.
7205 * It make MSL invoke _prepare_async_callback.
7206 * So, we need to disable webm format in "autoplug-select" */
7207 if (caps_str && strstr(caps_str, "webm")) {
7208 LOGW("webm is not supported");
7209 result = GST_AUTOPLUG_SELECT_SKIP;
7213 /* check factory class for filtering */
7214 /* NOTE : msl don't need to use image plugins.
7215 * So, those plugins should be skipped for error handling.
7217 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7218 LOGD("skipping [%s] by not required", factory_name);
7219 result = GST_AUTOPLUG_SELECT_SKIP;
7223 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7224 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7225 // TO CHECK : subtitle if needed, add subparse exception.
7226 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7227 result = GST_AUTOPLUG_SELECT_SKIP;
7231 if (g_strrstr(factory_name, "mpegpsdemux")) {
7232 LOGD("skipping PS container - not support");
7233 result = GST_AUTOPLUG_SELECT_SKIP;
7237 if (g_strrstr(factory_name, "mssdemux"))
7238 player->smooth_streaming = TRUE;
7240 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7241 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7244 GstStructure *str = NULL;
7245 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7247 /* don't make video because of not required */
7248 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7249 (!player->set_mode.video_export)) {
7250 LOGD("no need video decoding, expose pad");
7251 result = GST_AUTOPLUG_SELECT_EXPOSE;
7255 /* get w/h for omx state-tune */
7256 /* FIXME: deprecated? */
7257 str = gst_caps_get_structure(caps, 0);
7258 gst_structure_get_int(str, "width", &width);
7261 if (player->v_stream_caps) {
7262 gst_caps_unref(player->v_stream_caps);
7263 player->v_stream_caps = NULL;
7266 player->v_stream_caps = gst_caps_copy(caps);
7267 LOGD("take caps for video state tune");
7268 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7272 if (g_strrstr(klass, "Codec/Decoder")) {
7273 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7274 if (result != GST_AUTOPLUG_SELECT_TRY) {
7275 LOGW("skip add decoder");
7281 MMPLAYER_FREEIF(caps_str);
7287 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7290 //mmplayer_t *player = (mmplayer_t *)data;
7291 GstCaps *caps = NULL;
7293 LOGD("[Decodebin2] pad-removed signal");
7295 caps = gst_pad_query_caps(new_pad, NULL);
7297 LOGW("query caps is NULL");
7301 gchar *caps_str = NULL;
7302 caps_str = gst_caps_to_string(caps);
7304 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7306 MMPLAYER_FREEIF(caps_str);
7307 gst_caps_unref(caps);
7311 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7313 mmplayer_t *player = (mmplayer_t *)data;
7314 GstIterator *iter = NULL;
7315 GValue item = { 0, };
7317 gboolean done = FALSE;
7318 gboolean is_all_drained = TRUE;
7321 MMPLAYER_RETURN_IF_FAIL(player);
7323 LOGD("__mmplayer_gst_decode_drained");
7325 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7326 LOGW("Fail to get cmd lock");
7330 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7331 !__mmplayer_verify_gapless_play_path(player)) {
7332 LOGD("decoding is finished.");
7333 __mmplayer_reset_gapless_state(player);
7334 MMPLAYER_CMD_UNLOCK(player);
7338 player->gapless.reconfigure = TRUE;
7340 /* check decodebin src pads whether they received EOS or not */
7341 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7344 switch (gst_iterator_next(iter, &item)) {
7345 case GST_ITERATOR_OK:
7346 pad = g_value_get_object(&item);
7347 if (pad && !GST_PAD_IS_EOS(pad)) {
7348 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7349 is_all_drained = FALSE;
7352 g_value_reset(&item);
7354 case GST_ITERATOR_RESYNC:
7355 gst_iterator_resync(iter);
7357 case GST_ITERATOR_ERROR:
7358 case GST_ITERATOR_DONE:
7363 g_value_unset(&item);
7364 gst_iterator_free(iter);
7366 if (!is_all_drained) {
7367 LOGD("Wait util the all pads get EOS.");
7368 MMPLAYER_CMD_UNLOCK(player);
7373 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7374 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7376 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7377 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7378 __mmplayer_deactivate_old_path(player);
7379 MMPLAYER_CMD_UNLOCK(player);
7385 __mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7387 mmplayer_t *player = (mmplayer_t *)data;
7388 const gchar *klass = NULL;
7389 gchar *factory_name = NULL;
7391 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7392 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7394 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7396 if (__mmplayer_add_dump_buffer_probe(player, element))
7397 LOGD("add buffer probe");
7399 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7400 gchar *selected = NULL;
7401 selected = g_strdup(GST_ELEMENT_NAME(element));
7402 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7405 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7406 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7407 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7409 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7410 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7412 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7413 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7414 "max-video-width", player->adaptive_info.limit.width,
7415 "max-video-height", player->adaptive_info.limit.height, NULL);
7417 } else if (g_strrstr(klass, "Demuxer")) {
7418 //LOGD("plugged element is demuxer. take it");
7419 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7420 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7423 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7424 int surface_type = 0;
7426 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7429 // to support trust-zone only
7430 if (g_strrstr(factory_name, "asfdemux")) {
7431 LOGD("set file-location %s", player->profile.uri);
7432 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7433 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7434 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7435 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7436 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7437 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7438 (__mmplayer_is_only_mp3_type(player->type))) {
7439 LOGD("[mpegaudioparse] set streaming pull mode.");
7440 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7442 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7443 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7446 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7447 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7448 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7450 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7451 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7453 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7454 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7455 (MMPLAYER_IS_DASH_STREAMING(player))) {
7456 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7457 __mm_player_streaming_set_multiqueue(player->streamer, element);
7458 __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7467 __mmplayer_release_misc(mmplayer_t *player)
7470 bool cur_mode = player->set_mode.rich_audio;
7473 MMPLAYER_RETURN_IF_FAIL(player);
7475 player->video_decoded_cb = NULL;
7476 player->video_decoded_cb_user_param = NULL;
7477 player->video_stream_prerolled = false;
7479 player->audio_decoded_cb = NULL;
7480 player->audio_decoded_cb_user_param = NULL;
7481 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7483 player->video_stream_changed_cb = NULL;
7484 player->video_stream_changed_cb_user_param = NULL;
7486 player->audio_stream_changed_cb = NULL;
7487 player->audio_stream_changed_cb_user_param = NULL;
7489 player->sent_bos = FALSE;
7490 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7492 player->seek_state = MMPLAYER_SEEK_NONE;
7494 player->total_bitrate = 0;
7495 player->total_maximum_bitrate = 0;
7497 player->not_found_demuxer = 0;
7499 player->last_position = 0;
7500 player->duration = 0;
7501 player->http_content_size = 0;
7502 player->not_supported_codec = MISSING_PLUGIN_NONE;
7503 player->can_support_codec = FOUND_PLUGIN_NONE;
7504 player->pending_seek.is_pending = false;
7505 player->pending_seek.pos = 0;
7506 player->msg_posted = FALSE;
7507 player->has_many_types = FALSE;
7508 player->is_subtitle_force_drop = FALSE;
7509 player->play_subtitle = FALSE;
7510 player->adjust_subtitle_pos = 0;
7511 player->has_closed_caption = FALSE;
7512 player->set_mode.video_export = false;
7513 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7514 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7516 player->set_mode.rich_audio = cur_mode;
7518 if (mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7519 LOGW("failed to remove audio device_connected_callback");
7520 player->audio_device_cb_id = 0;
7522 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7523 player->bitrate[i] = 0;
7524 player->maximum_bitrate[i] = 0;
7527 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7529 /* remove media stream cb(appsrc cb) */
7530 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7531 player->media_stream_buffer_status_cb[i] = NULL;
7532 player->media_stream_seek_data_cb[i] = NULL;
7533 player->buffer_cb_user_param[i] = NULL;
7534 player->seek_cb_user_param[i] = NULL;
7536 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7538 /* free memory related to audio effect */
7539 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7541 if (player->adaptive_info.var_list) {
7542 g_list_free_full(player->adaptive_info.var_list, g_free);
7543 player->adaptive_info.var_list = NULL;
7546 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7547 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7548 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7550 /* Reset video360 settings to their defaults in case if the pipeline is to be
7553 player->video360_metadata.is_spherical = -1;
7554 player->is_openal_plugin_used = FALSE;
7556 player->is_content_spherical = FALSE;
7557 player->is_video360_enabled = TRUE;
7558 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7559 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7560 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7561 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7562 player->video360_zoom = 1.0f;
7563 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7564 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7566 player->sound.rg_enable = false;
7568 __mmplayer_initialize_video_roi(player);
7573 __mmplayer_release_misc_post(mmplayer_t *player)
7575 char *original_uri = NULL;
7578 /* player->pipeline is already released before. */
7580 MMPLAYER_RETURN_IF_FAIL(player);
7582 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7584 /* clean found audio decoders */
7585 if (player->audio_decoders) {
7586 GList *a_dec = player->audio_decoders;
7587 for (; a_dec; a_dec = g_list_next(a_dec)) {
7588 gchar *name = a_dec->data;
7589 MMPLAYER_FREEIF(name);
7591 g_list_free(player->audio_decoders);
7592 player->audio_decoders = NULL;
7595 /* clean the uri list except original uri */
7596 if (player->uri_info.uri_list) {
7597 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7599 if (player->attrs) {
7600 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7601 LOGD("restore original uri = %s", original_uri);
7603 if (mm_attrs_commit_all(player->attrs))
7604 LOGE("failed to commit the original uri.");
7607 GList *uri_list = player->uri_info.uri_list;
7608 for (; uri_list; uri_list = g_list_next(uri_list)) {
7609 gchar *uri = uri_list->data;
7610 MMPLAYER_FREEIF(uri);
7612 g_list_free(player->uri_info.uri_list);
7613 player->uri_info.uri_list = NULL;
7616 /* clear the audio stream buffer list */
7617 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7619 /* clear the video stream bo list */
7620 __mmplayer_video_stream_destroy_bo_list(player);
7621 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7623 if (player->profile.input_mem.buf) {
7624 free(player->profile.input_mem.buf);
7625 player->profile.input_mem.buf = NULL;
7627 player->profile.input_mem.len = 0;
7628 player->profile.input_mem.offset = 0;
7630 player->uri_info.uri_idx = 0;
7635 __mmplayer_check_subtitle(mmplayer_t *player)
7637 MMHandleType attrs = 0;
7638 char *subtitle_uri = NULL;
7642 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7644 /* get subtitle attribute */
7645 attrs = MMPLAYER_GET_ATTRS(player);
7649 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7650 if (!subtitle_uri || !strlen(subtitle_uri))
7653 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7654 player->is_external_subtitle_present = TRUE;
7662 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7664 MMPLAYER_RETURN_IF_FAIL(player);
7666 if (player->eos_timer) {
7667 LOGD("cancel eos timer");
7668 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7669 player->eos_timer = 0;
7676 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7680 MMPLAYER_RETURN_IF_FAIL(player);
7681 MMPLAYER_RETURN_IF_FAIL(sink);
7683 player->sink_elements = g_list_append(player->sink_elements, sink);
7689 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7693 MMPLAYER_RETURN_IF_FAIL(player);
7694 MMPLAYER_RETURN_IF_FAIL(sink);
7696 player->sink_elements = g_list_remove(player->sink_elements, sink);
7702 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7703 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7705 mmplayer_signal_item_t *item = NULL;
7708 MMPLAYER_RETURN_IF_FAIL(player);
7710 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7711 LOGE("invalid signal type [%d]", type);
7715 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7717 LOGE("cannot connect signal [%s]", signal);
7722 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7723 player->signals[type] = g_list_append(player->signals[type], item);
7729 /* NOTE : be careful with calling this api. please refer to below glib comment
7730 * glib comment : Note that there is a bug in GObject that makes this function much
7731 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7732 * will no longer be called, but, the signal handler is not currently disconnected.
7733 * If the instance is itself being freed at the same time than this doesn't matter,
7734 * since the signal will automatically be removed, but if instance persists,
7735 * then the signal handler will leak. You should not remove the signal yourself
7736 * because in a future versions of GObject, the handler will automatically be
7739 * It's possible to work around this problem in a way that will continue to work
7740 * with future versions of GObject by checking that the signal handler is still
7741 * connected before disconnected it:
7743 * if (g_signal_handler_is_connected(instance, id))
7744 * g_signal_handler_disconnect(instance, id);
7747 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7749 GList *sig_list = NULL;
7750 mmplayer_signal_item_t *item = NULL;
7754 MMPLAYER_RETURN_IF_FAIL(player);
7756 LOGD("release signals type : %d", type);
7758 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7759 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7760 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7761 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7767 sig_list = player->signals[type];
7769 for (; sig_list; sig_list = sig_list->next) {
7770 item = sig_list->data;
7772 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7773 if (g_signal_handler_is_connected(item->obj, item->sig))
7774 g_signal_handler_disconnect(item->obj, item->sig);
7777 MMPLAYER_FREEIF(item);
7780 g_list_free(player->signals[type]);
7781 player->signals[type] = NULL;
7789 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7791 mmplayer_t *player = 0;
7792 int prev_display_surface_type = 0;
7793 void *prev_display_overlay = NULL;
7797 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7798 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7800 player = MM_PLAYER_CAST(handle);
7802 /* check video sinkbin is created */
7803 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7804 LOGE("Videosink is already created");
7805 return MM_ERROR_NONE;
7808 LOGD("videosink element is not yet ready");
7810 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7811 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7813 return MM_ERROR_INVALID_ARGUMENT;
7816 /* load previous attributes */
7817 if (player->attrs) {
7818 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7819 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7820 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7821 if (prev_display_surface_type == surface_type) {
7822 LOGD("incoming display surface type is same as previous one, do nothing..");
7824 return MM_ERROR_NONE;
7827 LOGE("failed to load attributes");
7829 return MM_ERROR_PLAYER_INTERNAL;
7832 /* videobin is not created yet, so we just set attributes related to display surface */
7833 LOGD("store display attribute for given surface type(%d)", surface_type);
7834 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7835 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7836 if (mm_attrs_commit_all(player->attrs)) {
7837 LOGE("failed to commit attribute");
7839 return MM_ERROR_PLAYER_INTERNAL;
7843 return MM_ERROR_NONE;
7846 /* Note : if silent is true, then subtitle would not be displayed. :*/
7848 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7850 mmplayer_t *player = (mmplayer_t *)hplayer;
7854 /* check player handle */
7855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7857 player->set_mode.subtitle_off = silent;
7859 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7863 return MM_ERROR_NONE;
7867 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7869 mmplayer_gst_element_t *mainbin = NULL;
7870 mmplayer_gst_element_t *textbin = NULL;
7871 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7872 GstState current_state = GST_STATE_VOID_PENDING;
7873 GstState element_state = GST_STATE_VOID_PENDING;
7874 GstState element_pending_state = GST_STATE_VOID_PENDING;
7876 GstEvent *event = NULL;
7877 int result = MM_ERROR_NONE;
7879 GstClock *curr_clock = NULL;
7880 GstClockTime base_time, start_time, curr_time;
7885 /* check player handle */
7886 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7888 player->pipeline->mainbin &&
7889 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7891 mainbin = player->pipeline->mainbin;
7892 textbin = player->pipeline->textbin;
7894 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7896 // sync clock with current pipeline
7897 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7898 curr_time = gst_clock_get_time(curr_clock);
7900 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7901 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7903 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7904 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7906 if (current_state > GST_STATE_READY) {
7907 // sync state with current pipeline
7908 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7909 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7910 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7912 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7913 if (GST_STATE_CHANGE_FAILURE == ret) {
7914 LOGE("fail to state change.");
7915 result = MM_ERROR_PLAYER_INTERNAL;
7919 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7920 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7923 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7924 gst_object_unref(curr_clock);
7927 // seek to current position
7928 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7929 result = MM_ERROR_PLAYER_INVALID_STATE;
7930 LOGE("gst_element_query_position failed, invalid state");
7934 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7935 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);
7937 __mmplayer_gst_send_event_to_sink(player, event);
7939 result = MM_ERROR_PLAYER_INTERNAL;
7940 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7944 /* sync state with current pipeline */
7945 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7946 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7947 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7949 return MM_ERROR_NONE;
7952 /* release text pipeline resource */
7953 player->textsink_linked = 0;
7955 /* release signal */
7956 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7958 /* release textbin with it's childs */
7959 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7960 MMPLAYER_FREEIF(player->pipeline->textbin);
7961 player->pipeline->textbin = NULL;
7963 /* release subtitle elem */
7964 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7971 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7973 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7974 GstState current_state = GST_STATE_VOID_PENDING;
7976 MMHandleType attrs = 0;
7977 mmplayer_gst_element_t *mainbin = NULL;
7978 mmplayer_gst_element_t *textbin = NULL;
7980 gchar *subtitle_uri = NULL;
7981 int result = MM_ERROR_NONE;
7982 const gchar *charset = NULL;
7986 /* check player handle */
7987 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7989 player->pipeline->mainbin &&
7990 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7991 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7993 mainbin = player->pipeline->mainbin;
7994 textbin = player->pipeline->textbin;
7996 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7997 if (current_state < GST_STATE_READY) {
7998 result = MM_ERROR_PLAYER_INVALID_STATE;
7999 LOGE("Pipeline is not in proper state");
8003 attrs = MMPLAYER_GET_ATTRS(player);
8005 LOGE("cannot get content attribute");
8006 result = MM_ERROR_PLAYER_INTERNAL;
8010 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8011 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8012 LOGE("subtitle uri is not proper filepath");
8013 result = MM_ERROR_PLAYER_INVALID_URI;
8017 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8018 LOGE("failed to get storage info of subtitle path");
8019 result = MM_ERROR_PLAYER_INVALID_URI;
8023 LOGD("old subtitle file path is [%s]", subtitle_uri);
8024 LOGD("new subtitle file path is [%s]", filepath);
8026 if (!strcmp(filepath, subtitle_uri)) {
8027 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8030 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8031 if (mm_attrs_commit_all(player->attrs)) {
8032 LOGE("failed to commit.");
8037 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8038 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8039 player->subtitle_language_list = NULL;
8040 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8042 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8043 if (ret != GST_STATE_CHANGE_SUCCESS) {
8044 LOGE("failed to change state of textbin to READY");
8045 result = MM_ERROR_PLAYER_INTERNAL;
8049 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8050 if (ret != GST_STATE_CHANGE_SUCCESS) {
8051 LOGE("failed to change state of subparse to READY");
8052 result = MM_ERROR_PLAYER_INTERNAL;
8056 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8057 if (ret != GST_STATE_CHANGE_SUCCESS) {
8058 LOGE("failed to change state of filesrc to READY");
8059 result = MM_ERROR_PLAYER_INTERNAL;
8063 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8065 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8067 charset = util_get_charset(filepath);
8069 LOGD("detected charset is %s", charset);
8070 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8073 result = _mmplayer_sync_subtitle_pipeline(player);
8080 /* API to switch between external subtitles */
8082 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8084 int result = MM_ERROR_NONE;
8085 mmplayer_t *player = (mmplayer_t *)hplayer;
8090 /* check player handle */
8091 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8093 /* filepath can be null in idle state */
8095 /* check file path */
8096 if ((path = strstr(filepath, "file://")))
8097 result = util_exist_file_path(path + 7);
8099 result = util_exist_file_path(filepath);
8101 if (result != MM_ERROR_NONE) {
8102 LOGE("invalid subtitle path 0x%X", result);
8103 return result; /* file not found or permission denied */
8107 if (!player->pipeline) {
8109 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8110 if (mm_attrs_commit_all(player->attrs)) {
8111 LOGE("failed to commit"); /* subtitle path will not be created */
8112 return MM_ERROR_PLAYER_INTERNAL;
8115 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8116 /* check filepath */
8117 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8119 if (!__mmplayer_check_subtitle(player)) {
8120 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8121 if (mm_attrs_commit_all(player->attrs)) {
8122 LOGE("failed to commit");
8123 return MM_ERROR_PLAYER_INTERNAL;
8126 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8127 LOGE("fail to create text pipeline");
8128 return MM_ERROR_PLAYER_INTERNAL;
8131 result = _mmplayer_sync_subtitle_pipeline(player);
8133 result = __mmplayer_change_external_subtitle_language(player, filepath);
8136 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8137 player->is_external_subtitle_added_now = TRUE;
8139 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8140 if (!player->subtitle_language_list) {
8141 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8142 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8143 LOGW("subtitle language list is not updated yet");
8145 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8153 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8155 int result = MM_ERROR_NONE;
8156 gchar *change_pad_name = NULL;
8157 GstPad *sinkpad = NULL;
8158 mmplayer_gst_element_t *mainbin = NULL;
8159 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8160 GstCaps *caps = NULL;
8161 gint total_track_num = 0;
8165 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8166 MM_ERROR_PLAYER_NOT_INITIALIZED);
8168 LOGD("Change Track(%d) to %d", type, index);
8170 mainbin = player->pipeline->mainbin;
8172 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8173 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8174 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8175 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8177 /* Changing Video Track is not supported. */
8178 LOGE("Track Type Error");
8182 if (mainbin[elem_idx].gst == NULL) {
8183 result = MM_ERROR_PLAYER_NO_OP;
8184 LOGD("Req track doesn't exist");
8188 total_track_num = player->selector[type].total_track_num;
8189 if (total_track_num <= 0) {
8190 result = MM_ERROR_PLAYER_NO_OP;
8191 LOGD("Language list is not available");
8195 if ((index < 0) || (index >= total_track_num)) {
8196 result = MM_ERROR_INVALID_ARGUMENT;
8197 LOGD("Not a proper index : %d", index);
8201 /*To get the new pad from the selector*/
8202 change_pad_name = g_strdup_printf("sink_%u", index);
8203 if (change_pad_name == NULL) {
8204 result = MM_ERROR_PLAYER_INTERNAL;
8205 LOGD("Pad does not exists");
8209 LOGD("new active pad name: %s", change_pad_name);
8211 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8212 if (sinkpad == NULL) {
8213 LOGD("sinkpad is NULL");
8214 result = MM_ERROR_PLAYER_INTERNAL;
8218 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8219 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8221 caps = gst_pad_get_current_caps(sinkpad);
8222 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8225 gst_object_unref(sinkpad);
8227 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8228 __mmplayer_set_audio_attrs(player, caps);
8231 MMPLAYER_FREEIF(change_pad_name);
8236 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8238 int result = MM_ERROR_NONE;
8239 mmplayer_t *player = NULL;
8240 mmplayer_gst_element_t *mainbin = NULL;
8242 gint current_active_index = 0;
8244 GstState current_state = GST_STATE_VOID_PENDING;
8245 GstEvent *event = NULL;
8250 player = (mmplayer_t *)hplayer;
8251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8253 if (!player->pipeline) {
8254 LOGE("Track %d pre setting -> %d", type, index);
8256 player->selector[type].active_pad_index = index;
8260 mainbin = player->pipeline->mainbin;
8262 current_active_index = player->selector[type].active_pad_index;
8264 /*If index is same as running index no need to change the pad*/
8265 if (current_active_index == index)
8268 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8269 result = MM_ERROR_PLAYER_INVALID_STATE;
8273 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8274 if (current_state < GST_STATE_PAUSED) {
8275 result = MM_ERROR_PLAYER_INVALID_STATE;
8276 LOGW("Pipeline not in porper state");
8280 result = __mmplayer_change_selector_pad(player, type, index);
8281 if (result != MM_ERROR_NONE) {
8282 LOGE("change selector pad error");
8286 player->selector[type].active_pad_index = index;
8288 if (current_state == GST_STATE_PLAYING) {
8289 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8290 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8291 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8293 __mmplayer_gst_send_event_to_sink(player, event);
8295 result = MM_ERROR_PLAYER_INTERNAL;
8305 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8307 mmplayer_t *player = (mmplayer_t *)hplayer;
8311 /* check player handle */
8312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8314 *silent = player->set_mode.subtitle_off;
8316 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8320 return MM_ERROR_NONE;
8324 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8326 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8327 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8329 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8330 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8334 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8335 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8336 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8337 mmplayer_dump_t *dump_s;
8338 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8339 if (dump_s == NULL) {
8340 LOGE("malloc fail");
8344 dump_s->dump_element_file = NULL;
8345 dump_s->dump_pad = NULL;
8346 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8348 if (dump_s->dump_pad) {
8349 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8350 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]);
8351 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8352 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);
8353 /* add list for removed buffer probe and close FILE */
8354 player->dump_list = g_list_append(player->dump_list, dump_s);
8355 LOGD("%s sink pad added buffer probe for dump", factory_name);
8358 MMPLAYER_FREEIF(dump_s);
8359 LOGE("failed to get %s sink pad added", factory_name);
8366 static GstPadProbeReturn
8367 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8369 FILE *dump_data = (FILE *)u_data;
8371 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8372 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8374 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8376 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8378 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8380 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8382 return GST_PAD_PROBE_OK;
8386 __mmplayer_release_dump_list(GList *dump_list)
8388 GList *d_list = dump_list;
8393 for (; d_list; d_list = g_list_next(d_list)) {
8394 mmplayer_dump_t *dump_s = d_list->data;
8395 if (dump_s->dump_pad) {
8396 if (dump_s->probe_handle_id)
8397 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8398 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8400 if (dump_s->dump_element_file) {
8401 fclose(dump_s->dump_element_file);
8402 dump_s->dump_element_file = NULL;
8404 MMPLAYER_FREEIF(dump_s);
8406 g_list_free(dump_list);
8411 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8413 mmplayer_t *player = (mmplayer_t *)hplayer;
8417 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8418 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8420 *exist = (bool)player->has_closed_caption;
8424 return MM_ERROR_NONE;
8428 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8432 // LOGD("unref internal gst buffer %p", buffer);
8433 gst_buffer_unref((GstBuffer *)buffer);
8440 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8442 mmplayer_t *player = (mmplayer_t *)hplayer;
8446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8447 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8449 if (MMPLAYER_IS_STREAMING(player))
8450 *timeout = (int)player->ini.live_state_change_timeout;
8452 *timeout = (int)player->ini.localplayback_state_change_timeout;
8454 LOGD("timeout = %d", *timeout);
8457 return MM_ERROR_NONE;
8461 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8463 mmplayer_t *player = (mmplayer_t *)hplayer;
8467 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8468 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8470 *num = player->video_num_buffers;
8471 *extra_num = player->video_extra_num_buffers;
8473 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8476 return MM_ERROR_NONE;
8480 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8484 MMPLAYER_RETURN_IF_FAIL(player);
8486 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8488 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8489 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8490 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8491 player->storage_info[i].id = -1;
8492 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8494 if (path_type != MMPLAYER_PATH_MAX)
8503 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8505 int ret = MM_ERROR_NONE;
8506 mmplayer_t *player = (mmplayer_t *)hplayer;
8507 MMMessageParamType msg_param = {0, };
8510 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8512 LOGW("state changed storage %d:%d", id, state);
8514 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8515 return MM_ERROR_NONE;
8517 /* FIXME: text path should be handled seperately. */
8518 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8519 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8520 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8521 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8522 LOGW("external storage is removed");
8524 if (player->msg_posted == FALSE) {
8525 memset(&msg_param, 0, sizeof(MMMessageParamType));
8526 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8527 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8528 player->msg_posted = TRUE;
8531 /* unrealize the player */
8532 ret = _mmplayer_unrealize(hplayer);
8533 if (ret != MM_ERROR_NONE)
8534 LOGE("failed to unrealize");
8542 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8544 int ret = MM_ERROR_NONE;
8545 mmplayer_t *player = (mmplayer_t *)hplayer;
8546 int idx = 0, total = 0;
8547 gchar *result = NULL, *tmp = NULL;
8550 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8551 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8553 total = *num = g_list_length(player->adaptive_info.var_list);
8555 LOGW("There is no stream variant info.");
8559 result = g_strdup("");
8560 for (idx = 0 ; idx < total ; idx++) {
8561 stream_variant_t *v_data = NULL;
8562 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8565 gchar data[64] = {0};
8566 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8568 tmp = g_strconcat(result, data, NULL);
8572 LOGW("There is no variant data in %d", idx);
8577 *var_info = (char *)result;
8579 LOGD("variant info %d:%s", *num, *var_info);
8585 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8587 int ret = MM_ERROR_NONE;
8588 mmplayer_t *player = (mmplayer_t *)hplayer;
8591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8593 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8595 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8596 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8597 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8599 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8600 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8601 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8602 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8604 /* FIXME: seek to current position for applying new variant limitation */
8613 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8615 int ret = MM_ERROR_NONE;
8616 mmplayer_t *player = (mmplayer_t *)hplayer;
8619 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8620 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8622 *bandwidth = player->adaptive_info.limit.bandwidth;
8623 *width = player->adaptive_info.limit.width;
8624 *height = player->adaptive_info.limit.height;
8626 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8633 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8635 int ret = MM_ERROR_NONE;
8636 mmplayer_t *player = (mmplayer_t *)hplayer;
8639 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8640 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8641 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8643 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8645 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8646 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8647 else /* live case */
8648 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8650 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8657 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8659 #define IDX_FIRST_SW_CODEC 0
8660 mmplayer_t *player = (mmplayer_t *)hplayer;
8661 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8662 MMHandleType attrs = 0;
8665 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8667 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8668 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8669 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8671 switch (stream_type) {
8672 case MM_PLAYER_STREAM_TYPE_AUDIO:
8673 /* to support audio codec selection, codec info have to be added in ini file as below.
8674 audio codec element hw = xxxx
8675 audio codec element sw = avdec */
8676 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8677 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8678 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8679 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8680 LOGE("There is no audio codec info for codec_type %d", codec_type);
8681 return MM_ERROR_PLAYER_NO_OP;
8684 case MM_PLAYER_STREAM_TYPE_VIDEO:
8685 /* to support video codec selection, codec info have to be added in ini file as below.
8686 video codec element hw = omx
8687 video codec element sw = avdec */
8688 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8689 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8690 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8691 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8692 LOGE("There is no video codec info for codec_type %d", codec_type);
8693 return MM_ERROR_PLAYER_NO_OP;
8697 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8698 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8702 LOGD("update %s codec_type to %d", attr_name, codec_type);
8704 attrs = MMPLAYER_GET_ATTRS(player);
8705 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8707 if (mm_attrs_commit_all(player->attrs)) {
8708 LOGE("failed to commit codec_type attributes");
8709 return MM_ERROR_PLAYER_INTERNAL;
8713 return MM_ERROR_NONE;
8717 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8719 mmplayer_t *player = (mmplayer_t *)hplayer;
8720 GstElement *rg_vol_element = NULL;
8724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8726 player->sound.rg_enable = enabled;
8728 /* just hold rgvolume enable value if pipeline is not ready */
8729 if (!player->pipeline || !player->pipeline->audiobin) {
8730 LOGD("pipeline is not ready. holding rgvolume enable value");
8731 return MM_ERROR_NONE;
8734 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8736 if (!rg_vol_element) {
8737 LOGD("rgvolume element is not created");
8738 return MM_ERROR_PLAYER_INTERNAL;
8742 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8744 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8748 return MM_ERROR_NONE;
8752 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8754 mmplayer_t *player = (mmplayer_t *)hplayer;
8755 GstElement *rg_vol_element = NULL;
8756 gboolean enable = FALSE;
8760 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8761 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8763 /* just hold enable_rg value if pipeline is not ready */
8764 if (!player->pipeline || !player->pipeline->audiobin) {
8765 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8766 *enabled = player->sound.rg_enable;
8767 return MM_ERROR_NONE;
8770 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8772 if (!rg_vol_element) {
8773 LOGD("rgvolume element is not created");
8774 return MM_ERROR_PLAYER_INTERNAL;
8777 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8778 *enabled = (bool)enable;
8782 return MM_ERROR_NONE;
8786 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8788 mmplayer_t *player = (mmplayer_t *)hplayer;
8789 MMHandleType attrs = 0;
8790 void *handle = NULL;
8791 int ret = MM_ERROR_NONE;
8795 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8797 attrs = MMPLAYER_GET_ATTRS(player);
8798 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8800 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8802 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8803 return MM_ERROR_PLAYER_INTERNAL;
8806 player->video_roi.scale_x = scale_x;
8807 player->video_roi.scale_y = scale_y;
8808 player->video_roi.scale_width = scale_width;
8809 player->video_roi.scale_height = scale_height;
8811 /* check video sinkbin is created */
8812 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8813 return MM_ERROR_NONE;
8815 if (!gst_video_overlay_set_video_roi_area(
8816 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8817 scale_x, scale_y, scale_width, scale_height))
8818 ret = MM_ERROR_PLAYER_INTERNAL;
8820 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8821 scale_x, scale_y, scale_width, scale_height);
8829 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8831 mmplayer_t *player = (mmplayer_t *)hplayer;
8832 int ret = MM_ERROR_NONE;
8836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8837 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8839 *scale_x = player->video_roi.scale_x;
8840 *scale_y = player->video_roi.scale_y;
8841 *scale_width = player->video_roi.scale_width;
8842 *scale_height = player->video_roi.scale_height;
8844 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8845 *scale_x, *scale_y, *scale_width, *scale_height);
8851 __mmplayer_update_duration_value(mmplayer_t *player)
8853 gboolean ret = FALSE;
8854 gint64 dur_nsec = 0;
8855 LOGD("try to update duration");
8857 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8858 player->duration = dur_nsec;
8859 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8863 if (player->duration < 0) {
8864 LOGW("duration is Non-Initialized !!!");
8865 player->duration = 0;
8868 /* update streaming service type */
8869 player->streaming_type = __mmplayer_get_stream_service_type(player);
8871 /* check duration is OK */
8872 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8873 /* FIXIT : find another way to get duration here. */
8874 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8880 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8882 /* update audio params
8883 NOTE : We need original audio params and it can be only obtained from src pad of audio
8884 decoder. Below code only valid when we are not using 'resampler' just before
8885 'audioconverter'. */
8886 GstCaps *caps_a = NULL;
8888 gint samplerate = 0, channels = 0;
8889 GstStructure *p = NULL;
8891 LOGD("try to update audio attrs");
8893 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8894 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8896 pad = gst_element_get_static_pad(
8897 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8900 LOGW("failed to get pad from audiosink");
8904 caps_a = gst_pad_get_current_caps(pad);
8906 LOGW("not ready to get audio caps");
8907 gst_object_unref(pad);
8911 p = gst_caps_get_structure(caps_a, 0);
8913 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8915 gst_structure_get_int(p, "rate", &samplerate);
8916 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8918 gst_structure_get_int(p, "channels", &channels);
8919 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8921 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8923 gst_caps_unref(caps_a);
8924 gst_object_unref(pad);
8930 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8932 LOGD("try to update video attrs");
8934 GstCaps *caps_v = NULL;
8938 GstStructure *p = NULL;
8940 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8941 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8943 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8945 LOGD("no videosink sink pad");
8949 caps_v = gst_pad_get_current_caps(pad);
8950 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8951 if (!caps_v && player->v_stream_caps) {
8952 caps_v = player->v_stream_caps;
8953 gst_caps_ref(caps_v);
8957 LOGD("no negitiated caps from videosink");
8958 gst_object_unref(pad);
8962 p = gst_caps_get_structure(caps_v, 0);
8963 gst_structure_get_int(p, "width", &width);
8964 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8966 gst_structure_get_int(p, "height", &height);
8967 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8969 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8971 SECURE_LOGD("width : %d height : %d", width, height);
8973 gst_caps_unref(caps_v);
8974 gst_object_unref(pad);
8977 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8978 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8985 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8987 gboolean ret = FALSE;
8988 guint64 data_size = 0;
8992 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8993 if (!player->duration)
8996 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8997 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8998 if (stat(path, &sb) == 0)
8999 data_size = (guint64)sb.st_size;
9001 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9002 data_size = player->http_content_size;
9005 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9008 guint64 bitrate = 0;
9009 guint64 msec_dur = 0;
9011 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9013 bitrate = data_size * 8 * 1000 / msec_dur;
9014 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9015 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9019 LOGD("player duration is less than 0");
9023 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9024 if (player->total_bitrate) {
9025 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9034 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9036 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9037 data->uri_type = uri_type;
9041 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9043 int ret = MM_ERROR_PLAYER_INVALID_URI;
9045 char *buffer = NULL;
9046 char *seperator = strchr(path, ',');
9047 char ext[100] = {0,}, size[100] = {0,};
9050 if ((buffer = strstr(path, "ext="))) {
9051 buffer += strlen("ext=");
9053 if (strlen(buffer)) {
9054 strncpy(ext, buffer, 99);
9056 if ((seperator = strchr(ext, ','))
9057 || (seperator = strchr(ext, ' '))
9058 || (seperator = strchr(ext, '\0'))) {
9059 seperator[0] = '\0';
9064 if ((buffer = strstr(path, "size="))) {
9065 buffer += strlen("size=");
9067 if (strlen(buffer) > 0) {
9068 strncpy(size, buffer, 99);
9070 if ((seperator = strchr(size, ','))
9071 || (seperator = strchr(size, ' '))
9072 || (seperator = strchr(size, '\0'))) {
9073 seperator[0] = '\0';
9076 mem_size = atoi(size);
9081 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9083 if (mem_size && param) {
9084 if (data->input_mem.buf)
9085 free(data->input_mem.buf);
9086 data->input_mem.buf = malloc(mem_size);
9088 if (data->input_mem.buf) {
9089 memcpy(data->input_mem.buf, param, mem_size);
9090 data->input_mem.len = mem_size;
9091 ret = MM_ERROR_NONE;
9093 LOGE("failed to alloc mem %d", mem_size);
9094 ret = MM_ERROR_PLAYER_INTERNAL;
9097 data->input_mem.offset = 0;
9098 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9105 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9107 gchar *location = NULL;
9110 int ret = MM_ERROR_NONE;
9112 if ((path = strstr(uri, "file://"))) {
9113 location = g_filename_from_uri(uri, NULL, &err);
9114 if (!location || (err != NULL)) {
9115 LOGE("Invalid URI '%s' for filesrc: %s", path,
9116 (err != NULL) ? err->message : "unknown error");
9120 MMPLAYER_FREEIF(location);
9122 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9123 return MM_ERROR_PLAYER_INVALID_URI;
9125 LOGD("path from uri: %s", location);
9128 path = (location != NULL) ? (location) : ((char *)uri);
9131 ret = util_exist_file_path(path);
9133 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9134 if (ret == MM_ERROR_NONE) {
9135 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9136 if (util_is_sdp_file(path)) {
9137 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9138 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9140 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9142 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9143 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9145 LOGE("invalid uri, could not play..");
9146 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9149 MMPLAYER_FREEIF(location);
9154 static mmplayer_video_decoded_data_info_t *
9155 __mmplayer_create_stream_from_pad(GstPad *pad)
9157 GstCaps *caps = NULL;
9158 GstStructure *structure = NULL;
9159 unsigned int fourcc = 0;
9160 const gchar *string_format = NULL;
9161 mmplayer_video_decoded_data_info_t *stream = NULL;
9163 MMPixelFormatType format;
9166 caps = gst_pad_get_current_caps(pad);
9168 LOGE("Caps is NULL.");
9172 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9173 structure = gst_caps_get_structure(caps, 0);
9174 gst_structure_get_int(structure, "width", &width);
9175 gst_structure_get_int(structure, "height", &height);
9176 string_format = gst_structure_get_string(structure, "format");
9179 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9180 format = util_get_pixtype(fourcc);
9181 gst_video_info_from_caps(&info, caps);
9182 gst_caps_unref(caps);
9185 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9186 LOGE("Wrong condition!!");
9190 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9192 LOGE("failed to alloc mem for video data");
9196 stream->width = width;
9197 stream->height = height;
9198 stream->format = format;
9199 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9205 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9207 unsigned int pitch = 0;
9209 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9212 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9213 bo = gst_tizen_memory_get_bos(mem, index);
9215 stream->bo[index] = tbm_bo_ref(bo);
9217 LOGE("failed to get bo for index %d", index);
9220 for (index = 0; index < stream->plane_num; index++) {
9221 tbm_surface_internal_get_plane_data(surface, index, NULL, NULL, &pitch);
9222 stream->stride[index] = pitch;
9223 stream->elevation[index] = stream->height;
9228 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9230 if (stream->format == MM_PIXEL_FORMAT_I420) {
9231 int ret = TBM_SURFACE_ERROR_NONE;
9232 tbm_surface_h surface;
9233 tbm_surface_info_s info;
9235 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9237 ret = tbm_surface_get_info(surface, &info);
9238 if (ret != TBM_SURFACE_ERROR_NONE) {
9239 tbm_surface_destroy(surface);
9243 tbm_surface_destroy(surface);
9244 stream->stride[0] = info.planes[0].stride;
9245 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9246 stream->stride[1] = info.planes[1].stride;
9247 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9248 stream->stride[2] = info.planes[2].stride;
9249 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9250 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9251 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9252 stream->stride[0] = stream->width * 4;
9253 stream->elevation[0] = stream->height;
9254 stream->bo_size = stream->stride[0] * stream->height;
9256 LOGE("Not support format %d", stream->format);
9264 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9266 tbm_bo_handle thandle;
9268 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9269 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9270 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9274 unsigned char *src = NULL;
9275 unsigned char *dest = NULL;
9276 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9278 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9280 LOGE("fail to gst_memory_map");
9284 if (!mapinfo.data) {
9285 LOGE("data pointer is wrong");
9289 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9290 if (!stream->bo[0]) {
9291 LOGE("Fail to tbm_bo_alloc!!");
9295 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9297 LOGE("thandle pointer is wrong");
9301 if (stream->format == MM_PIXEL_FORMAT_I420) {
9302 src_stride[0] = GST_ROUND_UP_4(stream->width);
9303 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9304 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9305 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9308 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9309 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9311 for (i = 0; i < 3; i++) {
9312 src = mapinfo.data + src_offset[i];
9313 dest = thandle.ptr + dest_offset[i];
9318 for (j = 0; j < stream->height >> k; j++) {
9319 memcpy(dest, src, stream->width>>k);
9320 src += src_stride[i];
9321 dest += stream->stride[i];
9324 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9325 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9327 LOGE("Not support format %d", stream->format);
9331 tbm_bo_unmap(stream->bo[0]);
9332 gst_memory_unmap(mem, &mapinfo);
9338 tbm_bo_unmap(stream->bo[0]);
9341 gst_memory_unmap(mem, &mapinfo);
9347 __mmplayer_set_pause_state(mmplayer_t *player)
9349 if (player->sent_bos)
9352 /* rtsp case, get content attrs by GstMessage */
9353 if (MMPLAYER_IS_RTSP_STREAMING(player))
9356 /* it's first time to update all content attrs. */
9357 __mmplayer_update_content_attrs(player, ATTR_ALL);
9361 __mmplayer_set_playing_state(mmplayer_t *player)
9363 gchar *audio_codec = NULL;
9365 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9366 /* initialize because auto resume is done well. */
9367 player->resumed_by_rewind = FALSE;
9368 player->playback_rate = 1.0;
9371 if (player->sent_bos)
9374 /* try to get content metadata */
9376 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9377 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9378 * legacy mmfw-player api
9380 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9382 if ((player->cmd == MMPLAYER_COMMAND_START)
9383 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9384 __mmplayer_handle_missed_plugin(player);
9387 /* check audio codec field is set or not
9388 * we can get it from typefinder or codec's caps.
9390 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9392 /* The codec format can't be sent for audio only case like amr, mid etc.
9393 * Because, parser don't make related TAG.
9394 * So, if it's not set yet, fill it with found data.
9397 if (g_strrstr(player->type, "audio/midi"))
9398 audio_codec = "MIDI";
9399 else if (g_strrstr(player->type, "audio/x-amr"))
9400 audio_codec = "AMR";
9401 else if (g_strrstr(player->type, "audio/mpeg")
9402 && !g_strrstr(player->type, "mpegversion=(int)1"))
9403 audio_codec = "AAC";
9405 audio_codec = "unknown";
9407 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9409 if (mm_attrs_commit_all(player->attrs))
9410 LOGE("failed to update attributes");
9412 LOGD("set audio codec type with caps");