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 (player->audio_device_cb_id > 0 &&
7519 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7520 LOGW("failed to remove audio device_connected_callback");
7521 player->audio_device_cb_id = 0;
7523 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7524 player->bitrate[i] = 0;
7525 player->maximum_bitrate[i] = 0;
7528 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7530 /* remove media stream cb(appsrc cb) */
7531 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7532 player->media_stream_buffer_status_cb[i] = NULL;
7533 player->media_stream_seek_data_cb[i] = NULL;
7534 player->buffer_cb_user_param[i] = NULL;
7535 player->seek_cb_user_param[i] = NULL;
7537 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7539 /* free memory related to audio effect */
7540 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7542 if (player->adaptive_info.var_list) {
7543 g_list_free_full(player->adaptive_info.var_list, g_free);
7544 player->adaptive_info.var_list = NULL;
7547 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7548 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7549 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7551 /* Reset video360 settings to their defaults in case if the pipeline is to be
7554 player->video360_metadata.is_spherical = -1;
7555 player->is_openal_plugin_used = FALSE;
7557 player->is_content_spherical = FALSE;
7558 player->is_video360_enabled = TRUE;
7559 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7560 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7561 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7562 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7563 player->video360_zoom = 1.0f;
7564 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7565 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7567 player->sound.rg_enable = false;
7569 __mmplayer_initialize_video_roi(player);
7574 __mmplayer_release_misc_post(mmplayer_t *player)
7576 char *original_uri = NULL;
7579 /* player->pipeline is already released before. */
7581 MMPLAYER_RETURN_IF_FAIL(player);
7583 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7585 /* clean found audio decoders */
7586 if (player->audio_decoders) {
7587 GList *a_dec = player->audio_decoders;
7588 for (; a_dec; a_dec = g_list_next(a_dec)) {
7589 gchar *name = a_dec->data;
7590 MMPLAYER_FREEIF(name);
7592 g_list_free(player->audio_decoders);
7593 player->audio_decoders = NULL;
7596 /* clean the uri list except original uri */
7597 if (player->uri_info.uri_list) {
7598 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7600 if (player->attrs) {
7601 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7602 LOGD("restore original uri = %s", original_uri);
7604 if (mm_attrs_commit_all(player->attrs))
7605 LOGE("failed to commit the original uri.");
7608 GList *uri_list = player->uri_info.uri_list;
7609 for (; uri_list; uri_list = g_list_next(uri_list)) {
7610 gchar *uri = uri_list->data;
7611 MMPLAYER_FREEIF(uri);
7613 g_list_free(player->uri_info.uri_list);
7614 player->uri_info.uri_list = NULL;
7617 /* clear the audio stream buffer list */
7618 __mmplayer_audio_stream_clear_buffer(player, FALSE);
7620 /* clear the video stream bo list */
7621 __mmplayer_video_stream_destroy_bo_list(player);
7622 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7624 if (player->profile.input_mem.buf) {
7625 free(player->profile.input_mem.buf);
7626 player->profile.input_mem.buf = NULL;
7628 player->profile.input_mem.len = 0;
7629 player->profile.input_mem.offset = 0;
7631 player->uri_info.uri_idx = 0;
7636 __mmplayer_check_subtitle(mmplayer_t *player)
7638 MMHandleType attrs = 0;
7639 char *subtitle_uri = NULL;
7643 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7645 /* get subtitle attribute */
7646 attrs = MMPLAYER_GET_ATTRS(player);
7650 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7651 if (!subtitle_uri || !strlen(subtitle_uri))
7654 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7655 player->is_external_subtitle_present = TRUE;
7663 __mmplayer_cancel_eos_timer(mmplayer_t *player)
7665 MMPLAYER_RETURN_IF_FAIL(player);
7667 if (player->eos_timer) {
7668 LOGD("cancel eos timer");
7669 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7670 player->eos_timer = 0;
7677 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7681 MMPLAYER_RETURN_IF_FAIL(player);
7682 MMPLAYER_RETURN_IF_FAIL(sink);
7684 player->sink_elements = g_list_append(player->sink_elements, sink);
7690 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7694 MMPLAYER_RETURN_IF_FAIL(player);
7695 MMPLAYER_RETURN_IF_FAIL(sink);
7697 player->sink_elements = g_list_remove(player->sink_elements, sink);
7703 __mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7704 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7706 mmplayer_signal_item_t *item = NULL;
7709 MMPLAYER_RETURN_IF_FAIL(player);
7711 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7712 LOGE("invalid signal type [%d]", type);
7716 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7718 LOGE("cannot connect signal [%s]", signal);
7723 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7724 player->signals[type] = g_list_append(player->signals[type], item);
7730 /* NOTE : be careful with calling this api. please refer to below glib comment
7731 * glib comment : Note that there is a bug in GObject that makes this function much
7732 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7733 * will no longer be called, but, the signal handler is not currently disconnected.
7734 * If the instance is itself being freed at the same time than this doesn't matter,
7735 * since the signal will automatically be removed, but if instance persists,
7736 * then the signal handler will leak. You should not remove the signal yourself
7737 * because in a future versions of GObject, the handler will automatically be
7740 * It's possible to work around this problem in a way that will continue to work
7741 * with future versions of GObject by checking that the signal handler is still
7742 * connected before disconnected it:
7744 * if (g_signal_handler_is_connected(instance, id))
7745 * g_signal_handler_disconnect(instance, id);
7748 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7750 GList *sig_list = NULL;
7751 mmplayer_signal_item_t *item = NULL;
7755 MMPLAYER_RETURN_IF_FAIL(player);
7757 LOGD("release signals type : %d", type);
7759 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7760 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7761 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7764 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7768 sig_list = player->signals[type];
7770 for (; sig_list; sig_list = sig_list->next) {
7771 item = sig_list->data;
7773 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7774 if (g_signal_handler_is_connected(item->obj, item->sig))
7775 g_signal_handler_disconnect(item->obj, item->sig);
7778 MMPLAYER_FREEIF(item);
7781 g_list_free(player->signals[type]);
7782 player->signals[type] = NULL;
7790 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7792 mmplayer_t *player = 0;
7793 int prev_display_surface_type = 0;
7794 void *prev_display_overlay = NULL;
7798 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7799 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7801 player = MM_PLAYER_CAST(handle);
7803 /* check video sinkbin is created */
7804 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7805 LOGE("Videosink is already created");
7806 return MM_ERROR_NONE;
7809 LOGD("videosink element is not yet ready");
7811 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7812 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7814 return MM_ERROR_INVALID_ARGUMENT;
7817 /* load previous attributes */
7818 if (player->attrs) {
7819 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7820 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7821 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7822 if (prev_display_surface_type == surface_type) {
7823 LOGD("incoming display surface type is same as previous one, do nothing..");
7825 return MM_ERROR_NONE;
7828 LOGE("failed to load attributes");
7830 return MM_ERROR_PLAYER_INTERNAL;
7833 /* videobin is not created yet, so we just set attributes related to display surface */
7834 LOGD("store display attribute for given surface type(%d)", surface_type);
7835 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7836 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7837 if (mm_attrs_commit_all(player->attrs)) {
7838 LOGE("failed to commit attribute");
7840 return MM_ERROR_PLAYER_INTERNAL;
7844 return MM_ERROR_NONE;
7847 /* Note : if silent is true, then subtitle would not be displayed. :*/
7849 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7851 mmplayer_t *player = (mmplayer_t *)hplayer;
7855 /* check player handle */
7856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7858 player->set_mode.subtitle_off = silent;
7860 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7864 return MM_ERROR_NONE;
7868 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7870 mmplayer_gst_element_t *mainbin = NULL;
7871 mmplayer_gst_element_t *textbin = NULL;
7872 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7873 GstState current_state = GST_STATE_VOID_PENDING;
7874 GstState element_state = GST_STATE_VOID_PENDING;
7875 GstState element_pending_state = GST_STATE_VOID_PENDING;
7877 GstEvent *event = NULL;
7878 int result = MM_ERROR_NONE;
7880 GstClock *curr_clock = NULL;
7881 GstClockTime base_time, start_time, curr_time;
7886 /* check player handle */
7887 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7889 player->pipeline->mainbin &&
7890 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7892 mainbin = player->pipeline->mainbin;
7893 textbin = player->pipeline->textbin;
7895 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7897 // sync clock with current pipeline
7898 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7899 curr_time = gst_clock_get_time(curr_clock);
7901 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7902 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7904 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7905 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7907 if (current_state > GST_STATE_READY) {
7908 // sync state with current pipeline
7909 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7910 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7911 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7913 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7914 if (GST_STATE_CHANGE_FAILURE == ret) {
7915 LOGE("fail to state change.");
7916 result = MM_ERROR_PLAYER_INTERNAL;
7920 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7921 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7924 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7925 gst_object_unref(curr_clock);
7928 // seek to current position
7929 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7930 result = MM_ERROR_PLAYER_INVALID_STATE;
7931 LOGE("gst_element_query_position failed, invalid state");
7935 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7936 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);
7938 __mmplayer_gst_send_event_to_sink(player, event);
7940 result = MM_ERROR_PLAYER_INTERNAL;
7941 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7945 /* sync state with current pipeline */
7946 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7947 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7948 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7950 return MM_ERROR_NONE;
7953 /* release text pipeline resource */
7954 player->textsink_linked = 0;
7956 /* release signal */
7957 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7959 /* release textbin with it's childs */
7960 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7961 MMPLAYER_FREEIF(player->pipeline->textbin);
7962 player->pipeline->textbin = NULL;
7964 /* release subtitle elem */
7965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7966 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7972 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7974 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7975 GstState current_state = GST_STATE_VOID_PENDING;
7977 MMHandleType attrs = 0;
7978 mmplayer_gst_element_t *mainbin = NULL;
7979 mmplayer_gst_element_t *textbin = NULL;
7981 gchar *subtitle_uri = NULL;
7982 int result = MM_ERROR_NONE;
7983 const gchar *charset = NULL;
7987 /* check player handle */
7988 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7990 player->pipeline->mainbin &&
7991 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7992 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7994 mainbin = player->pipeline->mainbin;
7995 textbin = player->pipeline->textbin;
7997 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7998 if (current_state < GST_STATE_READY) {
7999 result = MM_ERROR_PLAYER_INVALID_STATE;
8000 LOGE("Pipeline is not in proper state");
8004 attrs = MMPLAYER_GET_ATTRS(player);
8006 LOGE("cannot get content attribute");
8007 result = MM_ERROR_PLAYER_INTERNAL;
8011 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8012 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8013 LOGE("subtitle uri is not proper filepath");
8014 result = MM_ERROR_PLAYER_INVALID_URI;
8018 if (!util_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8019 LOGE("failed to get storage info of subtitle path");
8020 result = MM_ERROR_PLAYER_INVALID_URI;
8024 LOGD("old subtitle file path is [%s]", subtitle_uri);
8025 LOGD("new subtitle file path is [%s]", filepath);
8027 if (!strcmp(filepath, subtitle_uri)) {
8028 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
8031 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8032 if (mm_attrs_commit_all(player->attrs)) {
8033 LOGE("failed to commit.");
8038 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8039 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8040 player->subtitle_language_list = NULL;
8041 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8043 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8044 if (ret != GST_STATE_CHANGE_SUCCESS) {
8045 LOGE("failed to change state of textbin to READY");
8046 result = MM_ERROR_PLAYER_INTERNAL;
8050 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8051 if (ret != GST_STATE_CHANGE_SUCCESS) {
8052 LOGE("failed to change state of subparse to READY");
8053 result = MM_ERROR_PLAYER_INTERNAL;
8057 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8058 if (ret != GST_STATE_CHANGE_SUCCESS) {
8059 LOGE("failed to change state of filesrc to READY");
8060 result = MM_ERROR_PLAYER_INTERNAL;
8064 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8066 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8068 charset = util_get_charset(filepath);
8070 LOGD("detected charset is %s", charset);
8071 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8074 result = _mmplayer_sync_subtitle_pipeline(player);
8081 /* API to switch between external subtitles */
8083 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8085 int result = MM_ERROR_NONE;
8086 mmplayer_t *player = (mmplayer_t *)hplayer;
8091 /* check player handle */
8092 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8094 /* filepath can be null in idle state */
8096 /* check file path */
8097 if ((path = strstr(filepath, "file://")))
8098 result = util_exist_file_path(path + 7);
8100 result = util_exist_file_path(filepath);
8102 if (result != MM_ERROR_NONE) {
8103 LOGE("invalid subtitle path 0x%X", result);
8104 return result; /* file not found or permission denied */
8108 if (!player->pipeline) {
8110 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8111 if (mm_attrs_commit_all(player->attrs)) {
8112 LOGE("failed to commit"); /* subtitle path will not be created */
8113 return MM_ERROR_PLAYER_INTERNAL;
8116 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8117 /* check filepath */
8118 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8120 if (!__mmplayer_check_subtitle(player)) {
8121 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8122 if (mm_attrs_commit_all(player->attrs)) {
8123 LOGE("failed to commit");
8124 return MM_ERROR_PLAYER_INTERNAL;
8127 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8128 LOGE("fail to create text pipeline");
8129 return MM_ERROR_PLAYER_INTERNAL;
8132 result = _mmplayer_sync_subtitle_pipeline(player);
8134 result = __mmplayer_change_external_subtitle_language(player, filepath);
8137 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8138 player->is_external_subtitle_added_now = TRUE;
8140 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8141 if (!player->subtitle_language_list) {
8142 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8143 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8144 LOGW("subtitle language list is not updated yet");
8146 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8154 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8156 int result = MM_ERROR_NONE;
8157 gchar *change_pad_name = NULL;
8158 GstPad *sinkpad = NULL;
8159 mmplayer_gst_element_t *mainbin = NULL;
8160 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8161 GstCaps *caps = NULL;
8162 gint total_track_num = 0;
8166 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8167 MM_ERROR_PLAYER_NOT_INITIALIZED);
8169 LOGD("Change Track(%d) to %d", type, index);
8171 mainbin = player->pipeline->mainbin;
8173 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8174 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8175 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8176 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8178 /* Changing Video Track is not supported. */
8179 LOGE("Track Type Error");
8183 if (mainbin[elem_idx].gst == NULL) {
8184 result = MM_ERROR_PLAYER_NO_OP;
8185 LOGD("Req track doesn't exist");
8189 total_track_num = player->selector[type].total_track_num;
8190 if (total_track_num <= 0) {
8191 result = MM_ERROR_PLAYER_NO_OP;
8192 LOGD("Language list is not available");
8196 if ((index < 0) || (index >= total_track_num)) {
8197 result = MM_ERROR_INVALID_ARGUMENT;
8198 LOGD("Not a proper index : %d", index);
8202 /*To get the new pad from the selector*/
8203 change_pad_name = g_strdup_printf("sink_%u", index);
8204 if (change_pad_name == NULL) {
8205 result = MM_ERROR_PLAYER_INTERNAL;
8206 LOGD("Pad does not exists");
8210 LOGD("new active pad name: %s", change_pad_name);
8212 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8213 if (sinkpad == NULL) {
8214 LOGD("sinkpad is NULL");
8215 result = MM_ERROR_PLAYER_INTERNAL;
8219 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8220 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8222 caps = gst_pad_get_current_caps(sinkpad);
8223 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8226 gst_object_unref(sinkpad);
8228 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8229 __mmplayer_set_audio_attrs(player, caps);
8232 MMPLAYER_FREEIF(change_pad_name);
8237 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8239 int result = MM_ERROR_NONE;
8240 mmplayer_t *player = NULL;
8241 mmplayer_gst_element_t *mainbin = NULL;
8243 gint current_active_index = 0;
8245 GstState current_state = GST_STATE_VOID_PENDING;
8246 GstEvent *event = NULL;
8251 player = (mmplayer_t *)hplayer;
8252 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8254 if (!player->pipeline) {
8255 LOGE("Track %d pre setting -> %d", type, index);
8257 player->selector[type].active_pad_index = index;
8261 mainbin = player->pipeline->mainbin;
8263 current_active_index = player->selector[type].active_pad_index;
8265 /*If index is same as running index no need to change the pad*/
8266 if (current_active_index == index)
8269 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8270 result = MM_ERROR_PLAYER_INVALID_STATE;
8274 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8275 if (current_state < GST_STATE_PAUSED) {
8276 result = MM_ERROR_PLAYER_INVALID_STATE;
8277 LOGW("Pipeline not in porper state");
8281 result = __mmplayer_change_selector_pad(player, type, index);
8282 if (result != MM_ERROR_NONE) {
8283 LOGE("change selector pad error");
8287 player->selector[type].active_pad_index = index;
8289 if (current_state == GST_STATE_PLAYING) {
8290 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8291 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8292 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8294 __mmplayer_gst_send_event_to_sink(player, event);
8296 result = MM_ERROR_PLAYER_INTERNAL;
8306 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8308 mmplayer_t *player = (mmplayer_t *)hplayer;
8312 /* check player handle */
8313 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8315 *silent = player->set_mode.subtitle_off;
8317 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8321 return MM_ERROR_NONE;
8325 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8327 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8328 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8330 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8331 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8335 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8336 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8337 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8338 mmplayer_dump_t *dump_s;
8339 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8340 if (dump_s == NULL) {
8341 LOGE("malloc fail");
8345 dump_s->dump_element_file = NULL;
8346 dump_s->dump_pad = NULL;
8347 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8349 if (dump_s->dump_pad) {
8350 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8351 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]);
8352 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8353 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);
8354 /* add list for removed buffer probe and close FILE */
8355 player->dump_list = g_list_append(player->dump_list, dump_s);
8356 LOGD("%s sink pad added buffer probe for dump", factory_name);
8359 MMPLAYER_FREEIF(dump_s);
8360 LOGE("failed to get %s sink pad added", factory_name);
8367 static GstPadProbeReturn
8368 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8370 FILE *dump_data = (FILE *)u_data;
8372 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8373 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8375 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8377 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8379 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8381 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8383 gst_buffer_unmap(buffer, &probe_info);
8385 return GST_PAD_PROBE_OK;
8389 __mmplayer_release_dump_list(GList *dump_list)
8391 GList *d_list = dump_list;
8396 for (; d_list; d_list = g_list_next(d_list)) {
8397 mmplayer_dump_t *dump_s = d_list->data;
8398 if (dump_s->dump_pad) {
8399 if (dump_s->probe_handle_id)
8400 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8401 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8403 if (dump_s->dump_element_file) {
8404 fclose(dump_s->dump_element_file);
8405 dump_s->dump_element_file = NULL;
8407 MMPLAYER_FREEIF(dump_s);
8409 g_list_free(dump_list);
8414 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8416 mmplayer_t *player = (mmplayer_t *)hplayer;
8420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8421 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8423 *exist = (bool)player->has_closed_caption;
8427 return MM_ERROR_NONE;
8431 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8435 // LOGD("unref internal gst buffer %p", buffer);
8436 gst_buffer_unref((GstBuffer *)buffer);
8443 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8445 mmplayer_t *player = (mmplayer_t *)hplayer;
8449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8450 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8452 if (MMPLAYER_IS_STREAMING(player))
8453 *timeout = (int)player->ini.live_state_change_timeout;
8455 *timeout = (int)player->ini.localplayback_state_change_timeout;
8457 LOGD("timeout = %d", *timeout);
8460 return MM_ERROR_NONE;
8464 _mmplayer_get_num_of_video_out_buffers(MMHandleType hplayer, int *num, int *extra_num)
8466 mmplayer_t *player = (mmplayer_t *)hplayer;
8470 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8471 MMPLAYER_RETURN_VAL_IF_FAIL(num && extra_num, MM_ERROR_COMMON_INVALID_ARGUMENT);
8473 *num = player->video_num_buffers;
8474 *extra_num = player->video_extra_num_buffers;
8476 LOGD("state %d, num %d(%d)", MMPLAYER_CURRENT_STATE(player), *num, *extra_num);
8479 return MM_ERROR_NONE;
8483 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8487 MMPLAYER_RETURN_IF_FAIL(player);
8489 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8491 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8492 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8493 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8494 player->storage_info[i].id = -1;
8495 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8497 if (path_type != MMPLAYER_PATH_MAX)
8506 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8508 int ret = MM_ERROR_NONE;
8509 mmplayer_t *player = (mmplayer_t *)hplayer;
8510 MMMessageParamType msg_param = {0, };
8513 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8515 LOGW("state changed storage %d:%d", id, state);
8517 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8518 return MM_ERROR_NONE;
8520 /* FIXME: text path should be handled seperately. */
8521 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8522 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8523 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8524 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8525 LOGW("external storage is removed");
8527 if (player->msg_posted == FALSE) {
8528 memset(&msg_param, 0, sizeof(MMMessageParamType));
8529 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8530 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8531 player->msg_posted = TRUE;
8534 /* unrealize the player */
8535 ret = _mmplayer_unrealize(hplayer);
8536 if (ret != MM_ERROR_NONE)
8537 LOGE("failed to unrealize");
8545 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8547 int ret = MM_ERROR_NONE;
8548 mmplayer_t *player = (mmplayer_t *)hplayer;
8549 int idx = 0, total = 0;
8550 gchar *result = NULL, *tmp = NULL;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8554 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8556 total = *num = g_list_length(player->adaptive_info.var_list);
8558 LOGW("There is no stream variant info.");
8562 result = g_strdup("");
8563 for (idx = 0 ; idx < total ; idx++) {
8564 stream_variant_t *v_data = NULL;
8565 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8568 gchar data[64] = {0};
8569 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8571 tmp = g_strconcat(result, data, NULL);
8575 LOGW("There is no variant data in %d", idx);
8580 *var_info = (char *)result;
8582 LOGD("variant info %d:%s", *num, *var_info);
8588 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8590 int ret = MM_ERROR_NONE;
8591 mmplayer_t *player = (mmplayer_t *)hplayer;
8594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8596 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8598 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8599 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8600 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8602 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8603 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8604 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8605 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8607 /* FIXME: seek to current position for applying new variant limitation */
8616 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8618 int ret = MM_ERROR_NONE;
8619 mmplayer_t *player = (mmplayer_t *)hplayer;
8622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8623 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8625 *bandwidth = player->adaptive_info.limit.bandwidth;
8626 *width = player->adaptive_info.limit.width;
8627 *height = player->adaptive_info.limit.height;
8629 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8636 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8638 int ret = MM_ERROR_NONE;
8639 mmplayer_t *player = (mmplayer_t *)hplayer;
8642 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8643 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8644 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8646 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8648 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8649 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8650 else /* live case */
8651 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8653 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8660 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8662 #define IDX_FIRST_SW_CODEC 0
8663 mmplayer_t *player = (mmplayer_t *)hplayer;
8664 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8665 MMHandleType attrs = 0;
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8670 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8671 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8672 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8674 switch (stream_type) {
8675 case MM_PLAYER_STREAM_TYPE_AUDIO:
8676 /* to support audio codec selection, codec info have to be added in ini file as below.
8677 audio codec element hw = xxxx
8678 audio codec element sw = avdec */
8679 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8680 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8681 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8682 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8683 LOGE("There is no audio codec info for codec_type %d", codec_type);
8684 return MM_ERROR_PLAYER_NO_OP;
8687 case MM_PLAYER_STREAM_TYPE_VIDEO:
8688 /* to support video codec selection, codec info have to be added in ini file as below.
8689 video codec element hw = omx
8690 video codec element sw = avdec */
8691 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8692 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8693 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8694 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8695 LOGE("There is no video codec info for codec_type %d", codec_type);
8696 return MM_ERROR_PLAYER_NO_OP;
8700 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8701 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8705 LOGD("update %s codec_type to %d", attr_name, codec_type);
8707 attrs = MMPLAYER_GET_ATTRS(player);
8708 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8710 if (mm_attrs_commit_all(player->attrs)) {
8711 LOGE("failed to commit codec_type attributes");
8712 return MM_ERROR_PLAYER_INTERNAL;
8716 return MM_ERROR_NONE;
8720 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8722 mmplayer_t *player = (mmplayer_t *)hplayer;
8723 GstElement *rg_vol_element = NULL;
8727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8729 player->sound.rg_enable = enabled;
8731 /* just hold rgvolume enable value if pipeline is not ready */
8732 if (!player->pipeline || !player->pipeline->audiobin) {
8733 LOGD("pipeline is not ready. holding rgvolume enable value");
8734 return MM_ERROR_NONE;
8737 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8739 if (!rg_vol_element) {
8740 LOGD("rgvolume element is not created");
8741 return MM_ERROR_PLAYER_INTERNAL;
8745 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8747 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8751 return MM_ERROR_NONE;
8755 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8757 mmplayer_t *player = (mmplayer_t *)hplayer;
8758 GstElement *rg_vol_element = NULL;
8759 gboolean enable = FALSE;
8763 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8764 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8766 /* just hold enable_rg value if pipeline is not ready */
8767 if (!player->pipeline || !player->pipeline->audiobin) {
8768 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8769 *enabled = player->sound.rg_enable;
8770 return MM_ERROR_NONE;
8773 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8775 if (!rg_vol_element) {
8776 LOGD("rgvolume element is not created");
8777 return MM_ERROR_PLAYER_INTERNAL;
8780 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8781 *enabled = (bool)enable;
8785 return MM_ERROR_NONE;
8789 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8791 mmplayer_t *player = (mmplayer_t *)hplayer;
8792 MMHandleType attrs = 0;
8793 void *handle = NULL;
8794 int ret = MM_ERROR_NONE;
8798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8800 attrs = MMPLAYER_GET_ATTRS(player);
8801 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8803 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8805 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8806 return MM_ERROR_PLAYER_INTERNAL;
8809 player->video_roi.scale_x = scale_x;
8810 player->video_roi.scale_y = scale_y;
8811 player->video_roi.scale_width = scale_width;
8812 player->video_roi.scale_height = scale_height;
8814 /* check video sinkbin is created */
8815 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8816 return MM_ERROR_NONE;
8818 if (!gst_video_overlay_set_video_roi_area(
8819 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8820 scale_x, scale_y, scale_width, scale_height))
8821 ret = MM_ERROR_PLAYER_INTERNAL;
8823 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8824 scale_x, scale_y, scale_width, scale_height);
8832 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8834 mmplayer_t *player = (mmplayer_t *)hplayer;
8835 int ret = MM_ERROR_NONE;
8839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8840 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8842 *scale_x = player->video_roi.scale_x;
8843 *scale_y = player->video_roi.scale_y;
8844 *scale_width = player->video_roi.scale_width;
8845 *scale_height = player->video_roi.scale_height;
8847 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8848 *scale_x, *scale_y, *scale_width, *scale_height);
8854 __mmplayer_update_duration_value(mmplayer_t *player)
8856 gboolean ret = FALSE;
8857 gint64 dur_nsec = 0;
8858 LOGD("try to update duration");
8860 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8861 player->duration = dur_nsec;
8862 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8866 if (player->duration < 0) {
8867 LOGW("duration is Non-Initialized !!!");
8868 player->duration = 0;
8871 /* update streaming service type */
8872 player->streaming_type = __mmplayer_get_stream_service_type(player);
8874 /* check duration is OK */
8875 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8876 /* FIXIT : find another way to get duration here. */
8877 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8883 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8885 /* update audio params
8886 NOTE : We need original audio params and it can be only obtained from src pad of audio
8887 decoder. Below code only valid when we are not using 'resampler' just before
8888 'audioconverter'. */
8889 GstCaps *caps_a = NULL;
8891 gint samplerate = 0, channels = 0;
8892 GstStructure *p = NULL;
8894 LOGD("try to update audio attrs");
8896 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8897 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, FALSE);
8899 pad = gst_element_get_static_pad(
8900 player->pipeline->audiobin[MMPLAYER_A_CONV].gst, "sink");
8903 LOGW("failed to get pad from audiosink");
8907 caps_a = gst_pad_get_current_caps(pad);
8909 LOGW("not ready to get audio caps");
8910 gst_object_unref(pad);
8914 p = gst_caps_get_structure(caps_a, 0);
8916 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8918 gst_structure_get_int(p, "rate", &samplerate);
8919 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8921 gst_structure_get_int(p, "channels", &channels);
8922 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8924 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8926 gst_caps_unref(caps_a);
8927 gst_object_unref(pad);
8933 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8935 LOGD("try to update video attrs");
8937 GstCaps *caps_v = NULL;
8941 GstStructure *p = NULL;
8943 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8944 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8946 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8948 LOGD("no videosink sink pad");
8952 caps_v = gst_pad_get_current_caps(pad);
8953 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8954 if (!caps_v && player->v_stream_caps) {
8955 caps_v = player->v_stream_caps;
8956 gst_caps_ref(caps_v);
8960 LOGD("no negitiated caps from videosink");
8961 gst_object_unref(pad);
8965 p = gst_caps_get_structure(caps_v, 0);
8966 gst_structure_get_int(p, "width", &width);
8967 mm_attrs_set_int_by_name(attrs, "content_video_width", width);
8969 gst_structure_get_int(p, "height", &height);
8970 mm_attrs_set_int_by_name(attrs, "content_video_height", height);
8972 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8974 SECURE_LOGD("width : %d height : %d", width, height);
8976 gst_caps_unref(caps_v);
8977 gst_object_unref(pad);
8980 mm_attrs_set_int_by_name(attrs, "content_video_fps", tmpNu / tmpDe);
8981 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8988 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8990 gboolean ret = FALSE;
8991 guint64 data_size = 0;
8995 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8996 if (!player->duration)
8999 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9000 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9001 if (stat(path, &sb) == 0)
9002 data_size = (guint64)sb.st_size;
9004 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9005 data_size = player->http_content_size;
9008 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9011 guint64 bitrate = 0;
9012 guint64 msec_dur = 0;
9014 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9016 bitrate = data_size * 8 * 1000 / msec_dur;
9017 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9018 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", bitrate);
9022 LOGD("player duration is less than 0");
9026 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9027 if (player->total_bitrate) {
9028 mm_attrs_set_int_by_name(attrs, "content_video_bitrate", player->total_bitrate);
9037 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9039 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9040 data->uri_type = uri_type;
9044 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9046 int ret = MM_ERROR_PLAYER_INVALID_URI;
9048 char *buffer = NULL;
9049 char *seperator = strchr(path, ',');
9050 char ext[100] = {0,}, size[100] = {0,};
9053 if ((buffer = strstr(path, "ext="))) {
9054 buffer += strlen("ext=");
9056 if (strlen(buffer)) {
9057 strncpy(ext, buffer, 99);
9059 if ((seperator = strchr(ext, ','))
9060 || (seperator = strchr(ext, ' '))
9061 || (seperator = strchr(ext, '\0'))) {
9062 seperator[0] = '\0';
9067 if ((buffer = strstr(path, "size="))) {
9068 buffer += strlen("size=");
9070 if (strlen(buffer) > 0) {
9071 strncpy(size, buffer, 99);
9073 if ((seperator = strchr(size, ','))
9074 || (seperator = strchr(size, ' '))
9075 || (seperator = strchr(size, '\0'))) {
9076 seperator[0] = '\0';
9079 mem_size = atoi(size);
9084 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9086 if (mem_size && param) {
9087 if (data->input_mem.buf)
9088 free(data->input_mem.buf);
9089 data->input_mem.buf = malloc(mem_size);
9091 if (data->input_mem.buf) {
9092 memcpy(data->input_mem.buf, param, mem_size);
9093 data->input_mem.len = mem_size;
9094 ret = MM_ERROR_NONE;
9096 LOGE("failed to alloc mem %d", mem_size);
9097 ret = MM_ERROR_PLAYER_INTERNAL;
9100 data->input_mem.offset = 0;
9101 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9108 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9110 gchar *location = NULL;
9113 int ret = MM_ERROR_NONE;
9115 if ((path = strstr(uri, "file://"))) {
9116 location = g_filename_from_uri(uri, NULL, &err);
9117 if (!location || (err != NULL)) {
9118 LOGE("Invalid URI '%s' for filesrc: %s", path,
9119 (err != NULL) ? err->message : "unknown error");
9123 MMPLAYER_FREEIF(location);
9125 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9126 return MM_ERROR_PLAYER_INVALID_URI;
9128 LOGD("path from uri: %s", location);
9131 path = (location != NULL) ? (location) : ((char *)uri);
9134 ret = util_exist_file_path(path);
9136 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9137 if (ret == MM_ERROR_NONE) {
9138 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9139 if (util_is_sdp_file(path)) {
9140 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9141 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9143 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9145 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9146 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9148 LOGE("invalid uri, could not play..");
9149 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9152 MMPLAYER_FREEIF(location);
9157 static mmplayer_video_decoded_data_info_t *
9158 __mmplayer_create_stream_from_pad(GstPad *pad)
9160 GstCaps *caps = NULL;
9161 GstStructure *structure = NULL;
9162 unsigned int fourcc = 0;
9163 const gchar *string_format = NULL;
9164 mmplayer_video_decoded_data_info_t *stream = NULL;
9166 MMPixelFormatType format;
9169 caps = gst_pad_get_current_caps(pad);
9171 LOGE("Caps is NULL.");
9175 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9176 structure = gst_caps_get_structure(caps, 0);
9177 gst_structure_get_int(structure, "width", &width);
9178 gst_structure_get_int(structure, "height", &height);
9179 string_format = gst_structure_get_string(structure, "format");
9182 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9183 format = util_get_pixtype(fourcc);
9184 gst_video_info_from_caps(&info, caps);
9185 gst_caps_unref(caps);
9188 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9189 LOGE("Wrong condition!!");
9193 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9195 LOGE("failed to alloc mem for video data");
9199 stream->width = width;
9200 stream->height = height;
9201 stream->format = format;
9202 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9208 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9210 unsigned int pitch = 0;
9211 unsigned int size = 0;
9213 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9216 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9217 bo = gst_tizen_memory_get_bos(mem, index);
9219 stream->bo[index] = tbm_bo_ref(bo);
9221 LOGE("failed to get bo for index %d", index);
9224 for (index = 0; index < stream->plane_num; index++) {
9225 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9226 stream->stride[index] = pitch;
9228 stream->elevation[index] = size / pitch;
9230 stream->elevation[index] = stream->height;
9235 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9237 if (stream->format == MM_PIXEL_FORMAT_I420) {
9238 int ret = TBM_SURFACE_ERROR_NONE;
9239 tbm_surface_h surface;
9240 tbm_surface_info_s info;
9242 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9244 ret = tbm_surface_get_info(surface, &info);
9245 if (ret != TBM_SURFACE_ERROR_NONE) {
9246 tbm_surface_destroy(surface);
9250 tbm_surface_destroy(surface);
9251 stream->stride[0] = info.planes[0].stride;
9252 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9253 stream->stride[1] = info.planes[1].stride;
9254 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9255 stream->stride[2] = info.planes[2].stride;
9256 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9257 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9258 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9259 stream->stride[0] = stream->width * 4;
9260 stream->elevation[0] = stream->height;
9261 stream->bo_size = stream->stride[0] * stream->height;
9263 LOGE("Not support format %d", stream->format);
9271 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9273 tbm_bo_handle thandle;
9275 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9276 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9277 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9281 unsigned char *src = NULL;
9282 unsigned char *dest = NULL;
9283 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9285 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9287 LOGE("fail to gst_memory_map");
9291 if (!mapinfo.data) {
9292 LOGE("data pointer is wrong");
9296 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9297 if (!stream->bo[0]) {
9298 LOGE("Fail to tbm_bo_alloc!!");
9302 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9304 LOGE("thandle pointer is wrong");
9308 if (stream->format == MM_PIXEL_FORMAT_I420) {
9309 src_stride[0] = GST_ROUND_UP_4(stream->width);
9310 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9311 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9312 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9315 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9316 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9318 for (i = 0; i < 3; i++) {
9319 src = mapinfo.data + src_offset[i];
9320 dest = thandle.ptr + dest_offset[i];
9325 for (j = 0; j < stream->height >> k; j++) {
9326 memcpy(dest, src, stream->width>>k);
9327 src += src_stride[i];
9328 dest += stream->stride[i];
9331 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9332 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9334 LOGE("Not support format %d", stream->format);
9338 tbm_bo_unmap(stream->bo[0]);
9339 gst_memory_unmap(mem, &mapinfo);
9345 tbm_bo_unmap(stream->bo[0]);
9348 gst_memory_unmap(mem, &mapinfo);
9354 __mmplayer_set_pause_state(mmplayer_t *player)
9356 if (player->sent_bos)
9359 /* rtsp case, get content attrs by GstMessage */
9360 if (MMPLAYER_IS_RTSP_STREAMING(player))
9363 /* it's first time to update all content attrs. */
9364 __mmplayer_update_content_attrs(player, ATTR_ALL);
9368 __mmplayer_set_playing_state(mmplayer_t *player)
9370 gchar *audio_codec = NULL;
9372 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9373 /* initialize because auto resume is done well. */
9374 player->resumed_by_rewind = FALSE;
9375 player->playback_rate = 1.0;
9378 if (player->sent_bos)
9381 /* try to get content metadata */
9383 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9384 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9385 * legacy mmfw-player api
9387 __mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9389 if ((player->cmd == MMPLAYER_COMMAND_START)
9390 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9391 __mmplayer_handle_missed_plugin(player);
9394 /* check audio codec field is set or not
9395 * we can get it from typefinder or codec's caps.
9397 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9399 /* The codec format can't be sent for audio only case like amr, mid etc.
9400 * Because, parser don't make related TAG.
9401 * So, if it's not set yet, fill it with found data.
9404 if (g_strrstr(player->type, "audio/midi"))
9405 audio_codec = "MIDI";
9406 else if (g_strrstr(player->type, "audio/x-amr"))
9407 audio_codec = "AMR";
9408 else if (g_strrstr(player->type, "audio/mpeg")
9409 && !g_strrstr(player->type, "mpegversion=(int)1"))
9410 audio_codec = "AAC";
9412 audio_codec = "unknown";
9414 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9416 if (mm_attrs_commit_all(player->attrs))
9417 LOGE("failed to update attributes");
9419 LOGD("set audio codec type with caps");