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
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
214 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
218 count = gst_tag_list_get_tag_size(list, tag);
220 LOGD("count = %d", count);
222 for (i = 0; i < count; i++) {
225 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
226 if (!gst_tag_list_get_string_index(list, tag, i, &str))
227 g_assert_not_reached();
229 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
233 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
235 g_print(" : %s", str);
242 /* This function should be called after the pipeline goes PAUSED or higher
245 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
247 static gboolean has_duration = FALSE;
248 static gboolean has_video_attrs = FALSE;
249 static gboolean has_audio_attrs = FALSE;
250 static gboolean has_bitrate = FALSE;
251 gboolean missing_only = FALSE;
252 gboolean all = FALSE;
253 MMHandleType attrs = 0;
257 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
259 /* check player state here */
260 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
261 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
262 /* give warning now only */
263 LOGW("be careful. content attributes may not available in this state ");
266 /* get content attribute first */
267 attrs = MMPLAYER_GET_ATTRS(player);
269 LOGE("cannot get content attribute");
273 /* get update flag */
275 if (flag & ATTR_MISSING_ONLY) {
277 LOGD("updating missed attr only");
280 if (flag & ATTR_ALL) {
282 has_duration = FALSE;
283 has_video_attrs = FALSE;
284 has_audio_attrs = FALSE;
287 LOGD("updating all attrs");
290 if (missing_only && all) {
291 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
292 missing_only = FALSE;
295 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
296 has_duration = __mmplayer_update_duration_value(player);
298 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
299 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
301 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
302 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
304 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
305 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
308 if (mm_attrs_commit_all(attrs)) {
309 LOGE("failed to update attributes");
319 _mmplayer_get_stream_service_type(mmplayer_t *player)
321 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
325 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
327 player->pipeline->mainbin &&
328 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
329 STREAMING_SERVICE_NONE);
331 /* streaming service type if streaming */
332 if (!MMPLAYER_IS_STREAMING(player))
333 return STREAMING_SERVICE_NONE;
335 streaming_type = (player->duration == 0) ?
336 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
338 switch (streaming_type) {
339 case STREAMING_SERVICE_LIVE:
340 LOGD("it's live streaming");
342 case STREAMING_SERVICE_VOD:
343 LOGD("it's vod streaming");
346 LOGE("should not get here");
352 return streaming_type;
355 /* this function sets the player state and also report
356 * it to applicaton by calling callback function
359 _mmplayer_set_state(mmplayer_t *player, int state)
361 MMMessageParamType msg = {0, };
363 MMPLAYER_RETURN_IF_FAIL(player);
365 if (MMPLAYER_CURRENT_STATE(player) == state) {
366 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
371 /* update player states */
372 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
373 MMPLAYER_CURRENT_STATE(player) = state;
375 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
376 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
379 MMPLAYER_PRINT_STATE(player);
381 switch (MMPLAYER_CURRENT_STATE(player)) {
382 case MM_PLAYER_STATE_NULL:
383 case MM_PLAYER_STATE_READY:
385 case MM_PLAYER_STATE_PAUSED:
386 __mmplayer_set_pause_state(player);
388 case MM_PLAYER_STATE_PLAYING:
389 __mmplayer_set_playing_state(player);
391 case MM_PLAYER_STATE_NONE:
393 LOGW("invalid target state, there is nothing to do.");
398 /* post message to application */
399 if (MMPLAYER_TARGET_STATE(player) == state) {
400 /* fill the message with state of player */
401 msg.union_type = MM_MSG_UNION_STATE;
402 msg.state.previous = MMPLAYER_PREV_STATE(player);
403 msg.state.current = MMPLAYER_CURRENT_STATE(player);
405 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
407 /* state changed by resource callback */
408 if (player->interrupted_by_resource)
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
410 else /* state changed by usecase */
411 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
414 LOGD("intermediate state, do nothing.");
415 MMPLAYER_PRINT_STATE(player);
419 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
420 && !player->sent_bos) {
421 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
422 player->sent_bos = TRUE;
429 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
431 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
432 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
436 //LOGD("incomming command : %d ", command);
438 current_state = MMPLAYER_CURRENT_STATE(player);
439 pending_state = MMPLAYER_PENDING_STATE(player);
441 MMPLAYER_PRINT_STATE(player);
444 case MMPLAYER_COMMAND_CREATE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL ||
449 current_state == MM_PLAYER_STATE_READY ||
450 current_state == MM_PLAYER_STATE_PAUSED ||
451 current_state == MM_PLAYER_STATE_PLAYING)
456 case MMPLAYER_COMMAND_DESTROY:
458 /* destroy can called anytime */
460 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
464 case MMPLAYER_COMMAND_REALIZE:
466 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
468 if (pending_state != MM_PLAYER_STATE_NONE) {
471 /* need ready state to realize */
472 if (current_state == MM_PLAYER_STATE_READY)
475 if (current_state != MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_UNREALIZE:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
485 if (current_state == MM_PLAYER_STATE_NULL)
490 case MMPLAYER_COMMAND_START:
492 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
494 if (pending_state == MM_PLAYER_STATE_NONE) {
495 if (current_state == MM_PLAYER_STATE_PLAYING)
497 else if (current_state != MM_PLAYER_STATE_READY &&
498 current_state != MM_PLAYER_STATE_PAUSED)
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
503 LOGD("player is going to paused state, just change the pending state as playing");
510 case MMPLAYER_COMMAND_STOP:
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
514 if (current_state == MM_PLAYER_STATE_READY)
517 /* need playing/paused state to stop */
518 if (current_state != MM_PLAYER_STATE_PLAYING &&
519 current_state != MM_PLAYER_STATE_PAUSED)
524 case MMPLAYER_COMMAND_PAUSE:
526 if (MMPLAYER_IS_LIVE_STREAMING(player))
529 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
530 goto NOT_COMPLETED_SEEK;
532 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
534 if (pending_state == MM_PLAYER_STATE_NONE) {
535 if (current_state == MM_PLAYER_STATE_PAUSED)
537 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
539 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
541 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
542 if (current_state == MM_PLAYER_STATE_PAUSED)
543 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
550 case MMPLAYER_COMMAND_RESUME:
552 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
553 goto NOT_COMPLETED_SEEK;
555 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
557 if (pending_state == MM_PLAYER_STATE_NONE) {
558 if (current_state == MM_PLAYER_STATE_PLAYING)
560 else if (current_state != MM_PLAYER_STATE_PAUSED)
562 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
564 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
565 LOGD("player is going to paused state, just change the pending state as playing");
575 player->cmd = command;
577 return MM_ERROR_NONE;
580 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
581 MMPLAYER_STATE_GET_NAME(current_state), command);
582 return MM_ERROR_PLAYER_INVALID_STATE;
585 LOGW("not completed seek");
586 return MM_ERROR_PLAYER_DOING_SEEK;
589 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
590 return MM_ERROR_PLAYER_NO_OP;
593 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
594 return MM_ERROR_PLAYER_NO_OP;
597 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
600 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
603 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
604 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
606 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
607 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
610 LOGE("invalid mmplayer resource type %d", type);
611 return MM_ERROR_PLAYER_INTERNAL;
614 if (player->hw_resource[type] != NULL) {
615 LOGD("[%d type] resource was already acquired", type);
616 return MM_ERROR_NONE;
619 LOGD("mark for acquire [%d type] resource", type);
620 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
621 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
622 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
623 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
624 return MM_ERROR_PLAYER_INTERNAL;
627 rm_ret = mm_resource_manager_commit(player->resource_manager);
628 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
629 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
630 return MM_ERROR_PLAYER_INTERNAL;
634 return MM_ERROR_NONE;
637 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
639 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
643 if (player->hw_resource[type] == NULL) {
644 LOGD("there is no acquired [%d type] resource", type);
645 return MM_ERROR_NONE;
648 LOGD("mark for release [%d type] resource", type);
649 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
655 player->hw_resource[type] = NULL;
657 rm_ret = mm_resource_manager_commit(player->resource_manager);
658 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
659 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
660 return MM_ERROR_PLAYER_INTERNAL;
664 return MM_ERROR_NONE;
668 __mmplayer_initialize_gapless_play(mmplayer_t *player)
674 player->smooth_streaming = FALSE;
675 player->videodec_linked = 0;
676 player->audiodec_linked = 0;
677 player->textsink_linked = 0;
678 player->is_external_subtitle_present = FALSE;
679 player->is_external_subtitle_added_now = FALSE;
680 player->not_supported_codec = MISSING_PLUGIN_NONE;
681 player->can_support_codec = FOUND_PLUGIN_NONE;
682 player->pending_seek.is_pending = false;
683 player->pending_seek.pos = 0;
684 player->msg_posted = FALSE;
685 player->has_many_types = FALSE;
686 player->no_more_pad = FALSE;
687 player->not_found_demuxer = 0;
688 player->seek_state = MMPLAYER_SEEK_NONE;
689 player->is_subtitle_force_drop = FALSE;
690 player->play_subtitle = FALSE;
691 player->adjust_subtitle_pos = 0;
693 player->total_bitrate = 0;
694 player->total_maximum_bitrate = 0;
696 _mmplayer_track_initialize(player);
697 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
699 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
700 player->bitrate[i] = 0;
701 player->maximum_bitrate[i] = 0;
704 if (player->v_stream_caps) {
705 gst_caps_unref(player->v_stream_caps);
706 player->v_stream_caps = NULL;
709 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
711 /* clean found audio decoders */
712 if (player->audio_decoders) {
713 GList *a_dec = player->audio_decoders;
714 for (; a_dec; a_dec = g_list_next(a_dec)) {
715 gchar *name = a_dec->data;
716 MMPLAYER_FREEIF(name);
718 g_list_free(player->audio_decoders);
719 player->audio_decoders = NULL;
722 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
728 __mmplayer_gapless_play_thread(gpointer data)
730 mmplayer_t *player = (mmplayer_t *)data;
731 mmplayer_gst_element_t *mainbin = NULL;
733 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
735 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
736 while (!player->gapless_play_thread_exit) {
737 LOGD("gapless play thread started. waiting for signal.");
738 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
740 LOGD("reconfigure pipeline for gapless play.");
742 if (player->gapless_play_thread_exit) {
743 if (player->gapless.reconfigure) {
744 player->gapless.reconfigure = false;
745 MMPLAYER_PLAYBACK_UNLOCK(player);
747 LOGD("exiting gapless play thread");
751 mainbin = player->pipeline->mainbin;
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
754 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
755 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
756 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
757 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
759 /* Initialize Player values */
760 __mmplayer_initialize_gapless_play(player);
762 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
764 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
770 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
772 GSource *source = NULL;
776 source = g_main_context_find_source_by_id(context, source_id);
777 if (source != NULL) {
778 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
779 g_source_destroy(source);
786 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
788 mmplayer_t *player = (mmplayer_t *)hplayer;
789 GstMessage *msg = NULL;
790 GQueue *queue = NULL;
793 MMPLAYER_RETURN_IF_FAIL(player);
795 /* disconnecting bus watch */
796 if (player->bus_watcher)
797 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
798 player->bus_watcher = 0;
800 /* destroy the gst bus msg thread */
801 if (player->bus_msg_thread) {
802 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
803 player->bus_msg_thread_exit = TRUE;
804 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
805 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
807 LOGD("gst bus msg thread exit.");
808 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
809 player->bus_msg_thread = NULL;
811 g_mutex_clear(&player->bus_msg_thread_mutex);
812 g_cond_clear(&player->bus_msg_thread_cond);
815 g_mutex_lock(&player->bus_msg_q_lock);
816 queue = player->bus_msg_q;
817 while (!g_queue_is_empty(queue)) {
818 msg = (GstMessage *)g_queue_pop_head(queue);
823 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
824 gst_message_unref(msg);
826 g_mutex_unlock(&player->bus_msg_q_lock);
832 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
834 GstElement *parent = NULL;
836 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
837 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
840 MMPLAYER_FSINK_LOCK(player);
842 /* get parent of fakesink */
843 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
845 LOGD("fakesink already removed");
849 gst_element_set_locked_state(fakesink->gst, TRUE);
851 /* setting the state to NULL never returns async
852 * so no need to wait for completion of state transiton
854 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
855 LOGE("fakesink state change failure!");
856 /* FIXIT : should I return here? or try to proceed to next? */
859 /* remove fakesink from it's parent */
860 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
861 LOGE("failed to remove fakesink");
863 gst_object_unref(parent);
868 gst_object_unref(parent);
870 LOGD("state-holder removed");
872 gst_element_set_locked_state(fakesink->gst, FALSE);
874 MMPLAYER_FSINK_UNLOCK(player);
879 gst_element_set_locked_state(fakesink->gst, FALSE);
881 MMPLAYER_FSINK_UNLOCK(player);
885 static GstPadProbeReturn
886 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
888 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
889 return GST_PAD_PROBE_OK;
893 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
895 gint64 stop_running_time = 0;
896 gint64 position_running_time = 0;
900 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
901 if ((player->gapless.update_segment[idx] == TRUE) ||
902 !(player->selector[idx].event_probe_id)) {
903 /* LOGW("[%d] skip", idx); */
907 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
909 gst_segment_to_running_time(&player->gapless.segment[idx],
910 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
911 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
913 gst_segment_to_running_time(&player->gapless.segment[idx],
914 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
916 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
918 gst_segment_to_running_time(&player->gapless.segment[idx],
919 GST_FORMAT_TIME, player->duration);
922 position_running_time =
923 gst_segment_to_running_time(&player->gapless.segment[idx],
924 GST_FORMAT_TIME, player->gapless.segment[idx].position);
926 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
927 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
929 GST_TIME_ARGS(stop_running_time),
930 GST_TIME_ARGS(position_running_time),
931 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
932 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
934 position_running_time = MAX(position_running_time, stop_running_time);
935 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
936 GST_FORMAT_TIME, player->gapless.segment[idx].start);
937 position_running_time = MAX(0, position_running_time);
938 position = MAX(position, position_running_time);
942 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
944 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
946 player->gapless.start_time[stream_type] += position;
952 static GstPadProbeReturn
953 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
955 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
956 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
957 mmplayer_t *player = (mmplayer_t *)data;
958 GstCaps *caps = NULL;
959 GstStructure *str = NULL;
960 const gchar *name = NULL;
961 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
962 gboolean caps_ret = TRUE;
964 if (GST_EVENT_IS_DOWNSTREAM(event) &&
965 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
966 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
967 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
968 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
970 } else if (GST_EVENT_IS_UPSTREAM(event) &&
971 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
975 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
979 if (strstr(name, "audio")) {
980 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
981 } else if (strstr(name, "video")) {
982 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
984 /* text track is not supportable */
985 LOGE("invalid name %s", name);
989 switch (GST_EVENT_TYPE(event)) {
992 /* in case of gapless, drop eos event not to send it to sink */
993 if (player->gapless.reconfigure && !player->msg_posted) {
994 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
995 ret = GST_PAD_PROBE_DROP;
999 case GST_EVENT_STREAM_START:
1001 __mmplayer_gst_selector_update_start_time(player, stream_type);
1004 case GST_EVENT_FLUSH_STOP:
1006 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1007 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1008 player->gapless.start_time[stream_type] = 0;
1011 case GST_EVENT_SEGMENT:
1016 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1017 gst_event_copy_segment(event, &segment);
1019 if (segment.format != GST_FORMAT_TIME)
1022 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1023 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1024 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1025 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1026 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1027 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1029 /* keep the all the segment ev to cover the seeking */
1030 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1031 player->gapless.update_segment[stream_type] = TRUE;
1033 if (!player->gapless.running)
1036 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1038 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1040 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1041 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1042 gst_event_unref(event);
1043 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1049 gdouble proportion = 0.0;
1050 GstClockTimeDiff diff = 0;
1051 GstClockTime timestamp = 0;
1052 gint64 running_time_diff = -1;
1053 GstQOSType type = 0;
1054 GstEvent *tmpev = NULL;
1056 running_time_diff = player->gapless.segment[stream_type].base;
1058 if (running_time_diff <= 0) /* don't need to adjust */
1061 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1062 gst_event_unref(event);
1064 if (timestamp < running_time_diff) {
1065 LOGW("QOS event from previous group");
1066 ret = GST_PAD_PROBE_DROP;
1070 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1071 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1072 stream_type, GST_TIME_ARGS(timestamp),
1073 GST_TIME_ARGS(running_time_diff),
1074 GST_TIME_ARGS(timestamp - running_time_diff));
1076 timestamp -= running_time_diff;
1078 /* That case is invalid for QoS events */
1079 if (diff < 0 && -diff > timestamp) {
1080 LOGW("QOS event from previous group");
1081 ret = GST_PAD_PROBE_DROP;
1085 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1086 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1096 gst_caps_unref(caps);
1100 /* create fakesink for audio or video path witout audiobin or videobin */
1102 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1104 GstElement *pipeline = NULL;
1105 GstElement *fakesink = NULL;
1106 GstPad *sinkpad = NULL;
1109 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1111 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1114 fakesink = gst_element_factory_make("fakesink", NULL);
1115 if (fakesink == NULL) {
1116 LOGE("failed to create fakesink");
1120 /* store it as it's sink element */
1121 __mmplayer_add_sink(player, fakesink);
1123 gst_bin_add(GST_BIN(pipeline), fakesink);
1126 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1128 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1130 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1131 LOGE("failed to link fakesink");
1132 gst_object_unref(GST_OBJECT(fakesink));
1136 if (strstr(name, "video")) {
1137 if (player->v_stream_caps) {
1138 gst_caps_unref(player->v_stream_caps);
1139 player->v_stream_caps = NULL;
1141 if (player->ini.set_dump_element_flag)
1142 __mmplayer_add_dump_buffer_probe(player, fakesink);
1145 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1146 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1150 gst_object_unref(GST_OBJECT(sinkpad));
1157 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1159 GstElement *pipeline = NULL;
1160 GstElement *selector = NULL;
1161 GstPad *srcpad = NULL;
1164 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1166 selector = gst_element_factory_make("input-selector", NULL);
1168 LOGE("failed to create input-selector");
1171 g_object_set(selector, "sync-streams", TRUE, NULL);
1173 player->pipeline->mainbin[elem_idx].id = elem_idx;
1174 player->pipeline->mainbin[elem_idx].gst = selector;
1176 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1178 srcpad = gst_element_get_static_pad(selector, "src");
1180 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1181 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1182 __mmplayer_gst_selector_blocked, NULL, NULL);
1183 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1184 __mmplayer_gst_selector_event_probe, player, NULL);
1186 gst_element_set_state(selector, GST_STATE_PAUSED);
1188 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1189 gst_bin_add(GST_BIN(pipeline), selector);
1191 gst_object_unref(GST_OBJECT(srcpad));
1198 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1200 mmplayer_t *player = (mmplayer_t *)data;
1201 GstElement *selector = NULL;
1202 GstCaps *caps = NULL;
1203 GstStructure *str = NULL;
1204 const gchar *name = NULL;
1205 GstPad *sinkpad = NULL;
1206 gboolean first_track = FALSE;
1207 gboolean caps_ret = TRUE;
1209 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1210 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1213 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1214 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1216 LOGD("pad-added signal handling");
1218 /* get mimetype from caps */
1219 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1223 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1224 /* LOGD("detected mimetype : %s", name); */
1226 if (strstr(name, "video")) {
1228 gchar *caps_str = NULL;
1230 caps_str = gst_caps_to_string(caps);
1231 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1232 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1233 player->set_mode.video_zc = true;
1235 MMPLAYER_FREEIF(caps_str);
1237 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1238 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1240 LOGD("surface type : %d", stype);
1242 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1243 __mmplayer_gst_create_sinkbin(elem, pad, player);
1247 /* in case of exporting video frame, it requires the 360 video filter.
1248 * it will be handled in _no_more_pads(). */
1249 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1250 __mmplayer_gst_make_fakesink(player, pad, name);
1254 LOGD("video selector is required");
1255 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1256 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1257 } else if (strstr(name, "audio")) {
1258 gint samplerate = 0;
1261 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1262 if (player->build_audio_offload)
1263 player->no_more_pad = TRUE; /* remove state holder */
1264 __mmplayer_gst_create_sinkbin(elem, pad, player);
1268 gst_structure_get_int(str, "rate", &samplerate);
1269 gst_structure_get_int(str, "channels", &channels);
1271 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1272 __mmplayer_gst_make_fakesink(player, pad, name);
1276 LOGD("audio selector is required");
1277 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1278 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1280 } else if (strstr(name, "text")) {
1281 LOGD("text selector is required");
1282 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1283 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1285 LOGE("invalid caps info");
1289 /* check selector and create it */
1290 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1291 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1296 LOGD("input-selector is already created.");
1300 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1302 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1304 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1305 LOGE("failed to link selector");
1306 gst_object_unref(GST_OBJECT(selector));
1311 LOGD("this track will be activated");
1312 g_object_set(selector, "active-pad", sinkpad, NULL);
1315 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1321 gst_caps_unref(caps);
1324 gst_object_unref(GST_OBJECT(sinkpad));
1332 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1334 GstPad *srcpad = NULL;
1337 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1339 LOGD("type %d", type);
1342 LOGD("there is no %d track", type);
1346 srcpad = gst_element_get_static_pad(selector, "src");
1348 LOGE("failed to get srcpad from selector");
1352 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1354 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1356 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1357 if (player->selector[type].block_id) {
1358 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1359 player->selector[type].block_id = 0;
1363 gst_object_unref(GST_OBJECT(srcpad));
1372 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1374 MMHandleType attrs = 0;
1375 gint active_index = 0;
1378 MMPLAYER_RETURN_IF_FAIL(player);
1380 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1382 /* change track to active pad */
1383 active_index = player->selector[type].active_pad_index;
1384 if ((active_index != DEFAULT_TRACK) &&
1385 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1386 LOGW("failed to change %d type track to %d", type, active_index);
1387 player->selector[type].active_pad_index = DEFAULT_TRACK;
1391 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1392 attrs = MMPLAYER_GET_ATTRS(player);
1394 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1395 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1397 if (mm_attrs_commit_all(attrs))
1398 LOGW("failed to commit attrs.");
1400 LOGW("cannot get content attribute");
1409 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1412 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1414 if (!audio_selector) {
1415 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1417 /* in case the source is changed, output can be changed. */
1418 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1419 LOGD("remove previous audiobin if it exist");
1421 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1422 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1424 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1425 MMPLAYER_FREEIF(player->pipeline->audiobin);
1428 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1429 __mmplayer_pipeline_complete(NULL, player);
1434 /* apply the audio track information */
1435 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1437 /* create audio sink path */
1438 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1439 LOGE("failed to create audio sink path");
1448 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1451 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1453 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1454 LOGD("text path is not supproted");
1458 /* apply the text track information */
1459 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1461 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1462 player->has_closed_caption = TRUE;
1464 /* create text decode path */
1465 player->no_more_pad = TRUE;
1467 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1468 LOGE("failed to create text sink path");
1477 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1479 gint64 dur_bytes = 0L;
1482 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1483 player->pipeline->mainbin && player->streamer, FALSE);
1485 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1486 LOGE("fail to get duration.");
1488 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1489 * use file information was already set on Q2 when it was created. */
1490 _mm_player_streaming_set_queue2(player->streamer,
1491 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1492 TRUE, /* use_buffering */
1493 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1494 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1501 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1503 mmplayer_t *player = NULL;
1504 GstElement *video_selector = NULL;
1505 GstElement *audio_selector = NULL;
1506 GstElement *text_selector = NULL;
1509 player = (mmplayer_t *)data;
1511 LOGD("no-more-pad signal handling");
1513 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1514 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1515 LOGW("player is shutting down");
1519 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1520 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1521 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1522 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1523 LOGE("failed to set queue2 buffering");
1528 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1529 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1530 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1532 if (!video_selector && !audio_selector && !text_selector) {
1533 LOGW("there is no selector");
1534 player->no_more_pad = TRUE;
1538 /* create video path followed by video-select */
1539 if (video_selector && !audio_selector && !text_selector)
1540 player->no_more_pad = TRUE;
1542 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1545 /* create audio path followed by audio-select */
1546 if (audio_selector && !text_selector)
1547 player->no_more_pad = TRUE;
1549 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1552 /* create text path followed by text-select */
1553 __mmplayer_create_text_sink_path(player, text_selector);
1556 if (player->gapless.reconfigure) {
1557 player->gapless.reconfigure = FALSE;
1558 MMPLAYER_PLAYBACK_UNLOCK(player);
1565 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1567 gboolean ret = FALSE;
1568 GstElement *pipeline = NULL;
1569 GstPad *sinkpad = NULL;
1572 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1573 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1575 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1577 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1579 LOGE("failed to get pad from sinkbin");
1585 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1586 LOGE("failed to link sinkbin for reusing");
1587 goto EXIT; /* exit either pass or fail */
1591 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1592 LOGE("failed to set state(READY) to sinkbin");
1597 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1598 LOGE("failed to add sinkbin to pipeline");
1603 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1604 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1609 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1610 LOGE("failed to set state(PAUSED) to sinkbin");
1619 gst_object_unref(GST_OBJECT(sinkpad));
1627 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1629 mmplayer_t *player = NULL;
1630 GstCaps *caps = NULL;
1631 gchar *caps_str = NULL;
1632 GstStructure *str = NULL;
1633 const gchar *name = NULL;
1634 GstElement *sinkbin = NULL;
1635 gboolean reusing = FALSE;
1636 gboolean caps_ret = TRUE;
1637 gchar *sink_pad_name = "sink";
1640 player = (mmplayer_t *)data;
1643 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1644 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1646 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1650 caps_str = gst_caps_to_string(caps);
1652 /* LOGD("detected mimetype : %s", name); */
1653 if (strstr(name, "audio")) {
1654 if (player->pipeline->audiobin == NULL) {
1655 const gchar *audio_format = gst_structure_get_string(str, "format");
1657 LOGD("original audio format %s", audio_format);
1658 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1661 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1662 LOGE("failed to create audiobin. continuing without audio");
1666 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1667 LOGD("creating audiobin success");
1670 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1671 LOGD("reusing audiobin");
1672 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1674 } else if (strstr(name, "video")) {
1675 /* 1. zero copy is updated at _decode_pad_added()
1676 * 2. NULL surface type is handled in _decode_pad_added() */
1677 LOGD("zero copy %d", player->set_mode.video_zc);
1678 if (player->pipeline->videobin == NULL) {
1679 int surface_type = 0;
1680 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1681 LOGD("display_surface_type (%d)", surface_type);
1683 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1684 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1685 LOGE("failed to acquire video overlay resource");
1689 player->interrupted_by_resource = FALSE;
1691 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1692 LOGE("failed to create videobin. continuing without video");
1696 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1697 LOGD("creating videosink bin success");
1700 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1701 LOGD("re-using videobin");
1702 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1704 } else if (strstr(name, "text")) {
1705 if (player->pipeline->textbin == NULL) {
1706 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1707 LOGE("failed to create text sink bin. continuing without text");
1711 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1712 player->textsink_linked = 1;
1713 LOGD("creating textsink bin success");
1715 if (!player->textsink_linked) {
1716 LOGD("re-using textbin");
1718 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1719 player->textsink_linked = 1;
1721 /* linked textbin exist which means that the external subtitle path exist already */
1722 LOGW("ignoring internal subtutle since external subtitle is available");
1725 sink_pad_name = "text_sink";
1727 LOGW("unknown mime type %s, ignoring it", name);
1731 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1734 LOGD("[handle: %p] success to create and link sink bin", player);
1736 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1737 * streaming task. if the task blocked, then buffer will not flow to the next element
1738 *(autoplugging element). so this is special hack for streaming. please try to remove it
1740 /* dec stream count. we can remove fakesink if it's zero */
1741 if (player->num_dynamic_pad)
1742 player->num_dynamic_pad--;
1744 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1746 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1747 __mmplayer_pipeline_complete(NULL, player);
1751 MMPLAYER_FREEIF(caps_str);
1754 gst_caps_unref(caps);
1760 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1762 int required_angle = 0; /* Angle required for straight view */
1763 int rotation_angle = 0;
1765 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1766 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1768 /* Counter clockwise */
1769 switch (orientation) {
1774 required_angle = 270;
1777 required_angle = 180;
1780 required_angle = 90;
1784 rotation_angle = display_angle + required_angle;
1785 if (rotation_angle >= 360)
1786 rotation_angle -= 360;
1788 /* chech if supported or not */
1789 if (rotation_angle % 90) {
1790 LOGD("not supported rotation angle = %d", rotation_angle);
1794 switch (rotation_angle) {
1796 *value = MM_DISPLAY_ROTATION_NONE;
1799 *value = MM_DISPLAY_ROTATION_90;
1802 *value = MM_DISPLAY_ROTATION_180;
1805 *value = MM_DISPLAY_ROTATION_270;
1809 LOGD("setting rotation property value : %d", *value);
1815 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1817 /* check video sinkbin is created */
1818 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1820 player->pipeline->videobin &&
1821 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1822 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1823 MM_ERROR_PLAYER_NOT_INITIALIZED);
1825 return MM_ERROR_NONE;
1829 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1831 int display_rotation = 0;
1832 gchar *org_orient = NULL;
1833 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1836 LOGE("cannot get content attribute");
1837 return MM_ERROR_PLAYER_INTERNAL;
1840 if (display_angle) {
1841 /* update user roation */
1842 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1844 /* Counter clockwise */
1845 switch (display_rotation) {
1846 case MM_DISPLAY_ROTATION_NONE:
1849 case MM_DISPLAY_ROTATION_90:
1850 *display_angle = 90;
1852 case MM_DISPLAY_ROTATION_180:
1853 *display_angle = 180;
1855 case MM_DISPLAY_ROTATION_270:
1856 *display_angle = 270;
1859 LOGW("wrong angle type : %d", display_rotation);
1862 LOGD("check user angle: %d", *display_angle);
1866 /* Counter clockwise */
1867 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1870 if (!strcmp(org_orient, "rotate-90"))
1872 else if (!strcmp(org_orient, "rotate-180"))
1874 else if (!strcmp(org_orient, "rotate-270"))
1877 LOGD("original rotation is %s", org_orient);
1879 LOGD("content_video_orientation get fail");
1882 LOGD("check orientation: %d", *orientation);
1885 return MM_ERROR_NONE;
1889 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1891 int rotation_value = 0;
1892 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1893 int display_angle = 0;
1896 /* check video sinkbin is created */
1897 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1900 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1902 /* get rotation value to set */
1903 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1904 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1905 LOGD("set video param : rotate %d", rotation_value);
1909 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1911 MMHandleType attrs = 0;
1915 /* check video sinkbin is created */
1916 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1919 attrs = MMPLAYER_GET_ATTRS(player);
1920 MMPLAYER_RETURN_IF_FAIL(attrs);
1922 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1923 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1924 LOGD("set video param : visible %d", visible);
1928 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1930 MMHandleType attrs = 0;
1931 int display_method = 0;
1934 /* check video sinkbin is created */
1935 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1938 attrs = MMPLAYER_GET_ATTRS(player);
1939 MMPLAYER_RETURN_IF_FAIL(attrs);
1941 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1942 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1943 LOGD("set video param : method %d", display_method);
1947 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1949 MMHandleType attrs = 0;
1950 void *handle = NULL;
1953 /* check video sinkbin is created */
1954 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1955 LOGW("There is no video sink");
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1961 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1963 gst_video_overlay_set_video_roi_area(
1964 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1965 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1966 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1967 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1972 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1974 MMHandleType attrs = 0;
1975 void *handle = NULL;
1979 int win_roi_width = 0;
1980 int win_roi_height = 0;
1983 /* check video sinkbin is created */
1984 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1985 LOGW("There is no video sink");
1989 attrs = MMPLAYER_GET_ATTRS(player);
1990 MMPLAYER_RETURN_IF_FAIL(attrs);
1992 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1995 /* It should be set after setting window */
1996 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1997 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1998 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1999 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2001 /* After setting window handle, set display roi area */
2002 gst_video_overlay_set_display_roi_area(
2003 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2004 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2005 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2006 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2011 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2013 MMHandleType attrs = 0;
2014 void *handle = NULL;
2016 /* check video sinkbin is created */
2017 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2020 attrs = MMPLAYER_GET_ATTRS(player);
2021 MMPLAYER_RETURN_IF_FAIL(attrs);
2023 /* common case if using overlay surface */
2024 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2027 /* default is using wl_surface_id */
2028 unsigned int wl_surface_id = 0;
2029 wl_surface_id = *(int *)handle;
2030 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2031 gst_video_overlay_set_wl_window_wl_surface_id(
2032 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2035 /* FIXIT : is it error case? */
2036 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2041 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2043 gboolean update_all_param = FALSE;
2046 /* check video sinkbin is created */
2047 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2048 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2050 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2051 LOGE("can not find tizenwlsink");
2052 return MM_ERROR_PLAYER_INTERNAL;
2055 LOGD("param_name : %s", param_name);
2056 if (!g_strcmp0(param_name, "update_all_param"))
2057 update_all_param = TRUE;
2059 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2060 __mmplayer_video_param_set_display_overlay(player);
2061 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2062 __mmplayer_video_param_set_display_method(player);
2063 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2064 __mmplayer_video_param_set_display_visible(player);
2065 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2066 __mmplayer_video_param_set_display_rotation(player);
2067 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2068 __mmplayer_video_param_set_roi_area(player);
2069 if (update_all_param)
2070 __mmplayer_video_param_set_video_roi_area(player);
2072 return MM_ERROR_NONE;
2076 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2078 MMHandleType attrs = 0;
2079 int surface_type = 0;
2080 int ret = MM_ERROR_NONE;
2084 /* check video sinkbin is created */
2085 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2086 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2088 attrs = MMPLAYER_GET_ATTRS(player);
2090 LOGE("cannot get content attribute");
2091 return MM_ERROR_PLAYER_INTERNAL;
2093 LOGD("param_name : %s", param_name);
2095 /* update display surface */
2096 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2097 LOGD("check display surface type attribute: %d", surface_type);
2099 /* configuring display */
2100 switch (surface_type) {
2101 case MM_DISPLAY_SURFACE_OVERLAY:
2103 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2104 if (ret != MM_ERROR_NONE)
2112 return MM_ERROR_NONE;
2116 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2118 gboolean disable_overlay = FALSE;
2119 mmplayer_t *player = (mmplayer_t *)hplayer;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2123 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2124 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2125 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2127 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2128 LOGW("Display control is not supported");
2129 return MM_ERROR_PLAYER_INTERNAL;
2132 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2134 if (audio_only == (bool)disable_overlay) {
2135 LOGE("It's the same with current setting: (%d)", audio_only);
2136 return MM_ERROR_NONE;
2140 LOGE("disable overlay");
2141 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2143 /* release overlay resource */
2144 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2145 LOGE("failed to release overlay resource");
2149 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2150 LOGE("failed to acquire video overlay resource");
2153 player->interrupted_by_resource = FALSE;
2155 LOGD("enable overlay");
2156 __mmplayer_video_param_set_display_overlay(player);
2157 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2162 return MM_ERROR_NONE;
2166 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2168 mmplayer_t *player = (mmplayer_t *)hplayer;
2169 gboolean disable_overlay = FALSE;
2173 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2174 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2175 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2176 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2177 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2179 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2180 LOGW("Display control is not supported");
2181 return MM_ERROR_PLAYER_INTERNAL;
2184 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2186 *paudio_only = (bool)disable_overlay;
2188 LOGD("audio_only : %d", *paudio_only);
2192 return MM_ERROR_NONE;
2196 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2198 GList *bucket = element_bucket;
2199 mmplayer_gst_element_t *element = NULL;
2200 mmplayer_gst_element_t *prv_element = NULL;
2201 GstElement *tee_element = NULL;
2202 gint successful_link_count = 0;
2206 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2208 prv_element = (mmplayer_gst_element_t *)bucket->data;
2209 bucket = bucket->next;
2211 for (; bucket; bucket = bucket->next) {
2212 element = (mmplayer_gst_element_t *)bucket->data;
2214 if (element && element->gst) {
2215 if (prv_element && prv_element->gst) {
2216 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2218 prv_element->gst = tee_element;
2220 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2221 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2222 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2226 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2227 LOGD("linking [%s] to [%s] success",
2228 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2229 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2230 successful_link_count++;
2231 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2232 LOGD("keep audio-tee element for next audio pipeline branch");
2233 tee_element = prv_element->gst;
2236 LOGD("linking [%s] to [%s] failed",
2237 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2238 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2244 prv_element = element;
2249 return successful_link_count;
2253 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2255 GList *bucket = element_bucket;
2256 mmplayer_gst_element_t *element = NULL;
2257 int successful_add_count = 0;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2262 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2264 for (; bucket; bucket = bucket->next) {
2265 element = (mmplayer_gst_element_t *)bucket->data;
2267 if (element && element->gst) {
2268 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2269 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2270 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2271 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2274 successful_add_count++;
2280 return successful_add_count;
2284 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2286 mmplayer_t *player = (mmplayer_t *)data;
2287 GstCaps *caps = NULL;
2288 GstStructure *str = NULL;
2290 gboolean caps_ret = TRUE;
2294 MMPLAYER_RETURN_IF_FAIL(pad);
2295 MMPLAYER_RETURN_IF_FAIL(unused);
2296 MMPLAYER_RETURN_IF_FAIL(data);
2298 caps = gst_pad_get_current_caps(pad);
2302 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2306 LOGD("name = %s", name);
2308 if (strstr(name, "audio")) {
2309 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2311 if (player->audio_stream_changed_cb) {
2312 LOGE("call the audio stream changed cb");
2313 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2315 } else if (strstr(name, "video")) {
2316 if ((name = gst_structure_get_string(str, "format")))
2317 player->set_mode.video_zc = name[0] == 'S';
2319 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2320 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2322 LOGW("invalid caps info");
2327 gst_caps_unref(caps);
2335 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2340 MMPLAYER_RETURN_IF_FAIL(player);
2342 if (player->audio_stream_buff_list) {
2343 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2344 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2347 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2348 __mmplayer_audio_stream_send_data(player, tmp);
2350 MMPLAYER_FREEIF(tmp->pcm_data);
2351 MMPLAYER_FREEIF(tmp);
2354 g_list_free(player->audio_stream_buff_list);
2355 player->audio_stream_buff_list = NULL;
2362 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2364 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2367 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2369 audio_stream.bitrate = a_buffer->bitrate;
2370 audio_stream.channel = a_buffer->channel;
2371 audio_stream.depth = a_buffer->depth;
2372 audio_stream.is_little_endian = a_buffer->is_little_endian;
2373 audio_stream.channel_mask = a_buffer->channel_mask;
2374 audio_stream.data_size = a_buffer->data_size;
2375 audio_stream.data = a_buffer->pcm_data;
2376 audio_stream.pcm_format = a_buffer->pcm_format;
2378 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2379 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2385 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2387 mmplayer_t *player = (mmplayer_t *)data;
2388 const gchar *pcm_format = NULL;
2392 gint endianness = 0;
2393 guint64 channel_mask = 0;
2394 void *a_data = NULL;
2396 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2397 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2401 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2403 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2404 a_data = mapinfo.data;
2405 a_size = mapinfo.size;
2407 GstCaps *caps = gst_pad_get_current_caps(pad);
2408 GstStructure *structure = gst_caps_get_structure(caps, 0);
2410 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2411 pcm_format = gst_structure_get_string(structure, "format");
2412 gst_structure_get_int(structure, "rate", &rate);
2413 gst_structure_get_int(structure, "channels", &channel);
2414 gst_structure_get_int(structure, "depth", &depth);
2415 gst_structure_get_int(structure, "endianness", &endianness);
2416 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2417 gst_caps_unref(GST_CAPS(caps));
2419 /* In case of the sync is false, use buffer list. *
2420 * The num of buffer list depends on the num of audio channels */
2421 if (player->audio_stream_buff_list) {
2422 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2423 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2425 if (channel_mask == tmp->channel_mask) {
2426 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2427 if (tmp->data_size + a_size < tmp->buff_size) {
2428 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2429 tmp->data_size += a_size;
2431 /* send data to client */
2432 __mmplayer_audio_stream_send_data(player, tmp);
2434 if (a_size > tmp->buff_size) {
2435 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2436 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2437 if (tmp->pcm_data == NULL) {
2438 LOGE("failed to realloc data.");
2441 tmp->buff_size = a_size;
2443 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2444 memcpy(tmp->pcm_data, a_data, a_size);
2445 tmp->data_size = a_size;
2450 LOGE("data is empty in list.");
2456 /* create new audio stream data for newly found audio channel */
2457 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2458 if (a_buffer == NULL) {
2459 LOGE("failed to alloc data.");
2462 a_buffer->bitrate = rate;
2463 a_buffer->channel = channel;
2464 a_buffer->depth = depth;
2465 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2466 a_buffer->channel_mask = channel_mask;
2467 a_buffer->data_size = a_size;
2468 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2470 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2471 /* If sync is FALSE, use buffer list to reduce the IPC. */
2472 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2473 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2474 if (a_buffer->pcm_data == NULL) {
2475 LOGE("failed to alloc data.");
2476 MMPLAYER_FREEIF(a_buffer);
2479 memcpy(a_buffer->pcm_data, a_data, a_size);
2480 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2481 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2483 /* If sync is TRUE, send data directly. */
2484 a_buffer->pcm_data = a_data;
2485 __mmplayer_audio_stream_send_data(player, a_buffer);
2486 MMPLAYER_FREEIF(a_buffer);
2490 gst_buffer_unmap(buffer, &mapinfo);
2495 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2497 mmplayer_t *player = (mmplayer_t *)data;
2498 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2499 GstPad *sinkpad = NULL;
2500 GstElement *queue = NULL, *sink = NULL;
2503 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2505 queue = gst_element_factory_make("queue", NULL);
2506 if (queue == NULL) {
2507 LOGD("fail make queue");
2511 sink = gst_element_factory_make("fakesink", NULL);
2513 LOGD("fail make fakesink");
2517 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2519 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2520 LOGW("failed to link queue & sink");
2524 sinkpad = gst_element_get_static_pad(queue, "sink");
2526 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2527 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2531 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2533 gst_object_unref(sinkpad);
2534 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2535 g_object_set(sink, "sync", TRUE, NULL);
2536 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2538 /* keep the first sink reference only */
2539 if (!audiobin[MMPLAYER_A_SINK].gst) {
2540 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2541 audiobin[MMPLAYER_A_SINK].gst = sink;
2544 gst_element_set_state(sink, GST_STATE_PAUSED);
2545 gst_element_set_state(queue, GST_STATE_PAUSED);
2547 _mmplayer_add_signal_connection(player,
2549 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2551 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2554 __mmplayer_add_sink(player, sink);
2560 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2562 gst_object_unref(GST_OBJECT(queue));
2566 gst_object_unref(GST_OBJECT(sink));
2570 gst_object_unref(GST_OBJECT(sinkpad));
2578 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2580 #define MAX_PROPS_LEN 128
2581 mmplayer_gst_element_t *audiobin = NULL;
2582 gint latency_mode = 0;
2583 gchar *stream_type = NULL;
2584 gchar *latency = NULL;
2586 gchar stream_props[MAX_PROPS_LEN] = {0,};
2587 GstStructure *props = NULL;
2590 * It should be set after player creation through attribute.
2591 * But, it can not be changed during playing.
2594 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2596 audiobin = player->pipeline->audiobin;
2598 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2599 if (player->sound.mute) {
2600 LOGD("mute enabled");
2601 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2604 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2605 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2608 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2610 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2611 stream_type, stream_id, player->client_pid);
2613 props = gst_structure_from_string(stream_props, NULL);
2614 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2615 LOGI("props result[%s].", stream_props);
2616 gst_structure_free(props);
2618 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2620 switch (latency_mode) {
2621 case AUDIO_LATENCY_MODE_LOW:
2622 latency = g_strndup("low", 3);
2624 case AUDIO_LATENCY_MODE_MID:
2625 latency = g_strndup("mid", 3);
2627 case AUDIO_LATENCY_MODE_HIGH:
2628 latency = g_strndup("high", 4);
2632 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2634 LOGD("audiosink property - latency=%s", latency);
2636 MMPLAYER_FREEIF(latency);
2642 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2644 mmplayer_gst_element_t *audiobin = NULL;
2647 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2649 audiobin = player->pipeline->audiobin;
2651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2652 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2653 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2655 if (player->video360_yaw_radians <= M_PI &&
2656 player->video360_yaw_radians >= -M_PI &&
2657 player->video360_pitch_radians <= M_PI_2 &&
2658 player->video360_pitch_radians >= -M_PI_2) {
2659 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2660 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2661 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2662 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2663 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2664 "source-orientation-y", player->video360_metadata.init_view_heading,
2665 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2672 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2674 mmplayer_gst_element_t *audiobin = NULL;
2675 GstPad *sink_pad = NULL;
2676 GstCaps *acaps = NULL;
2678 int pitch_control = 0;
2679 double pitch_value = 1.0;
2682 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2683 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2685 audiobin = player->pipeline->audiobin;
2687 LOGD("make element for normal audio playback");
2689 /* audio bin structure for playback. {} means optional.
2690 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2692 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2693 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2696 /* for pitch control */
2697 mm_attrs_multiple_get(player->attrs, NULL,
2698 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2699 MM_PLAYER_PITCH_VALUE, &pitch_value,
2702 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2703 if (pitch_control && (player->videodec_linked == 0)) {
2704 GstElementFactory *factory;
2706 factory = gst_element_factory_find("pitch");
2708 gst_object_unref(factory);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2715 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2717 LOGW("there is no pitch element");
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2724 /* replaygain volume */
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2726 if (player->sound.rg_enable)
2727 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2729 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2732 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2734 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2735 /* currently, only openalsink uses volume element */
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2739 if (player->sound.mute) {
2740 LOGD("mute enabled");
2741 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2745 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2747 /* audio effect element. if audio effect is enabled */
2748 if ((strcmp(player->ini.audioeffect_element, ""))
2750 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2751 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2753 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2755 if ((!player->bypass_audio_effect)
2756 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2757 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2758 if (!_mmplayer_audio_effect_custom_apply(player))
2759 LOGI("apply audio effect(custom) setting success");
2763 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2764 && (player->set_mode.rich_audio)) {
2765 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2769 /* create audio sink */
2770 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2771 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2772 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2774 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2775 if (player->is_360_feature_enabled &&
2776 player->is_content_spherical &&
2778 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2779 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2780 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2782 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2784 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2786 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2787 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2788 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2789 gst_caps_unref(acaps);
2791 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2793 player->is_openal_plugin_used = TRUE;
2795 if (player->is_360_feature_enabled && player->is_content_spherical)
2796 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2797 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2800 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2801 (player->videodec_linked && player->ini.use_system_clock)) {
2802 LOGD("system clock will be used.");
2803 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2806 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2807 __mmplayer_gst_set_pulsesink_property(player);
2808 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2809 __mmplayer_gst_set_openalsink_property(player);
2812 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2813 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2815 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2816 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2817 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2818 gst_object_unref(GST_OBJECT(sink_pad));
2820 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2823 return MM_ERROR_NONE;
2825 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2827 return MM_ERROR_PLAYER_INTERNAL;
2831 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2833 mmplayer_gst_element_t *audiobin = NULL;
2834 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2836 gchar *dst_format = NULL;
2838 int dst_samplerate = 0;
2839 int dst_channels = 0;
2840 GstCaps *caps = NULL;
2841 char *caps_str = NULL;
2844 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2845 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2847 audiobin = player->pipeline->audiobin;
2849 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2851 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2853 [case 1] extract interleave audio pcm without playback
2854 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2855 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2857 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2859 [case 2] deinterleave for each channel without playback
2860 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2861 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2863 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2864 - fakesink (sync or not)
2867 [case 3] [case 1(sync only)] + playback
2868 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2870 * src - ... - tee - queue1 - playback path
2871 - queue2 - [case1 pipeline with sync]
2873 [case 4] [case 2(sync only)] + playback
2874 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2876 * src - ... - tee - queue1 - playback path
2877 - queue2 - [case2 pipeline with sync]
2881 /* 1. create tee and playback path
2882 'tee' should be added at first to copy the decoded stream
2884 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2885 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2886 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2888 /* tee - path 1 : for playback path */
2889 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2890 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2892 /* tee - path 2 : for extract path */
2893 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2894 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2897 /* if there is tee, 'tee - path 2' is linked here */
2899 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2902 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2904 /* 2. decide the extract pcm format */
2905 mm_attrs_multiple_get(player->attrs, NULL,
2906 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2907 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2908 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2911 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2912 dst_format, dst_len, dst_samplerate, dst_channels);
2914 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2915 mm_attrs_multiple_get(player->attrs, NULL,
2916 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2917 "content_audio_samplerate", &dst_samplerate,
2918 "content_audio_channels", &dst_channels,
2921 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2922 dst_format, dst_len, dst_samplerate, dst_channels);
2924 /* If there is no enough information, set it to platform default value. */
2925 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2926 LOGD("set platform default format");
2927 dst_format = DEFAULT_PCM_OUT_FORMAT;
2929 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2930 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2933 /* 3. create capsfilter */
2934 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2935 caps = gst_caps_new_simple("audio/x-raw",
2936 "format", G_TYPE_STRING, dst_format,
2937 "rate", G_TYPE_INT, dst_samplerate,
2938 "channels", G_TYPE_INT, dst_channels,
2941 caps_str = gst_caps_to_string(caps);
2942 LOGD("new caps : %s", caps_str);
2944 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2947 gst_caps_unref(caps);
2948 MMPLAYER_FREEIF(caps_str);
2950 /* 4-1. create deinterleave to extract pcm for each channel */
2951 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2952 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2953 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2955 /* audiosink will be added after getting signal for each channel */
2956 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2957 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2959 /* 4-2. create fakesink to extract interlevaed pcm */
2960 LOGD("add audio fakesink for interleaved audio");
2961 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2962 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2963 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2964 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2966 _mmplayer_add_signal_connection(player,
2967 G_OBJECT(audiobin[extract_sink_id].gst),
2968 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2970 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2973 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2977 return MM_ERROR_NONE;
2979 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2981 return MM_ERROR_PLAYER_INTERNAL;
2985 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2987 int ret = MM_ERROR_NONE;
2988 mmplayer_gst_element_t *audiobin = NULL;
2989 GList *element_bucket = NULL;
2992 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2993 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2995 audiobin = player->pipeline->audiobin;
2997 if (player->build_audio_offload) { /* skip all the audio filters */
2998 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3000 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3001 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3002 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3004 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3008 /* FIXME: need to mention the supportable condition at API reference */
3009 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3010 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3012 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3014 if (ret != MM_ERROR_NONE)
3017 LOGD("success to make audio bin element");
3018 *bucket = element_bucket;
3021 return MM_ERROR_NONE;
3024 LOGE("failed to make audio bin element");
3025 g_list_free(element_bucket);
3029 return MM_ERROR_PLAYER_INTERNAL;
3033 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3035 mmplayer_gst_element_t *first_element = NULL;
3036 mmplayer_gst_element_t *audiobin = NULL;
3038 GstPad *ghostpad = NULL;
3039 GList *element_bucket = NULL;
3043 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3046 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3048 LOGE("failed to allocate memory for audiobin");
3049 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3053 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3054 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3055 if (!audiobin[MMPLAYER_A_BIN].gst) {
3056 LOGE("failed to create audiobin");
3061 player->pipeline->audiobin = audiobin;
3063 /* create audio filters and audiosink */
3064 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3067 /* adding created elements to bin */
3068 LOGD("adding created elements to bin");
3069 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3072 /* linking elements in the bucket by added order. */
3073 LOGD("Linking elements in the bucket by added order.");
3074 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3077 /* get first element's sinkpad for creating ghostpad */
3078 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3079 if (!first_element) {
3080 LOGE("failed to get first elem");
3084 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3086 LOGE("failed to get pad from first element of audiobin");
3090 ghostpad = gst_ghost_pad_new("sink", pad);
3092 LOGE("failed to create ghostpad");
3096 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3097 LOGE("failed to add ghostpad to audiobin");
3101 gst_object_unref(pad);
3103 g_list_free(element_bucket);
3106 return MM_ERROR_NONE;
3109 LOGD("ERROR : releasing audiobin");
3112 gst_object_unref(GST_OBJECT(pad));
3115 gst_object_unref(GST_OBJECT(ghostpad));
3118 g_list_free(element_bucket);
3120 /* release element which are not added to bin */
3121 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3122 /* NOTE : skip bin */
3123 if (audiobin[i].gst) {
3124 GstObject *parent = NULL;
3125 parent = gst_element_get_parent(audiobin[i].gst);
3128 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3129 audiobin[i].gst = NULL;
3131 gst_object_unref(GST_OBJECT(parent));
3135 /* release audiobin with it's childs */
3136 if (audiobin[MMPLAYER_A_BIN].gst)
3137 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3139 MMPLAYER_FREEIF(audiobin);
3141 player->pipeline->audiobin = NULL;
3143 return MM_ERROR_PLAYER_INTERNAL;
3147 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3149 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3153 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3155 int ret = MM_ERROR_NONE;
3157 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3158 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3160 MMPLAYER_VIDEO_BO_LOCK(player);
3162 if (player->video_bo_list) {
3163 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3164 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3165 if (tmp && tmp->bo == bo) {
3167 LOGD("release bo %p", bo);
3168 tbm_bo_unref(tmp->bo);
3169 MMPLAYER_VIDEO_BO_UNLOCK(player);
3170 MMPLAYER_VIDEO_BO_SIGNAL(player);
3175 /* hw codec is running or the list was reset for DRC. */
3176 LOGW("there is no bo list.");
3178 MMPLAYER_VIDEO_BO_UNLOCK(player);
3180 LOGW("failed to find bo %p", bo);
3185 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3190 MMPLAYER_RETURN_IF_FAIL(player);
3192 MMPLAYER_VIDEO_BO_LOCK(player);
3193 if (player->video_bo_list) {
3194 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3195 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3196 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3199 tbm_bo_unref(tmp->bo);
3203 g_list_free(player->video_bo_list);
3204 player->video_bo_list = NULL;
3206 player->video_bo_size = 0;
3207 MMPLAYER_VIDEO_BO_UNLOCK(player);
3214 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3217 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3218 gboolean ret = TRUE;
3220 /* check DRC, if it is, destroy the prev bo list to create again */
3221 if (player->video_bo_size != size) {
3222 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3223 __mmplayer_video_stream_destroy_bo_list(player);
3224 player->video_bo_size = size;
3227 MMPLAYER_VIDEO_BO_LOCK(player);
3229 if ((!player->video_bo_list) ||
3230 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3232 /* create bo list */
3234 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3236 if (player->video_bo_list) {
3237 /* if bo list did not created all, try it again. */
3238 idx = g_list_length(player->video_bo_list);
3239 LOGD("bo list exist(len: %d)", idx);
3242 for (; idx < player->ini.num_of_video_bo; idx++) {
3243 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3245 LOGE("Fail to alloc bo_info.");
3248 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3250 LOGE("Fail to tbm_bo_alloc.");
3251 MMPLAYER_FREEIF(bo_info);
3254 bo_info->used = FALSE;
3255 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3258 /* update video num buffers */
3259 LOGD("video_num_buffers : %d", idx);
3260 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3261 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3264 MMPLAYER_VIDEO_BO_UNLOCK(player);
3270 /* get bo from list*/
3271 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3272 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3273 if (tmp && (tmp->used == FALSE)) {
3274 LOGD("found bo %p to use", tmp->bo);
3276 MMPLAYER_VIDEO_BO_UNLOCK(player);
3277 return tbm_bo_ref(tmp->bo);
3281 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3282 MMPLAYER_VIDEO_BO_UNLOCK(player);
3286 if (player->ini.video_bo_timeout <= 0) {
3287 MMPLAYER_VIDEO_BO_WAIT(player);
3289 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3290 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3297 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3299 mmplayer_t *player = (mmplayer_t *)data;
3301 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3303 /* send prerolled pkt */
3304 player->video_stream_prerolled = false;
3306 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3308 /* not to send prerolled pkt again */
3309 player->video_stream_prerolled = true;
3313 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3315 mmplayer_t *player = (mmplayer_t *)data;
3316 mmplayer_video_decoded_data_info_t *stream = NULL;
3317 GstMemory *mem = NULL;
3320 MMPLAYER_RETURN_IF_FAIL(player);
3321 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3323 if (player->video_stream_prerolled) {
3324 player->video_stream_prerolled = false;
3325 LOGD("skip the prerolled pkt not to send it again");
3329 /* clear stream data structure */
3330 stream = __mmplayer_create_stream_from_pad(pad);
3332 LOGE("failed to alloc stream");
3336 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3338 /* set size and timestamp */
3339 mem = gst_buffer_peek_memory(buffer, 0);
3340 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3341 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3343 /* check zero-copy */
3344 if (player->set_mode.video_zc &&
3345 player->set_mode.video_export &&
3346 gst_is_tizen_memory(mem)) {
3347 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3348 stream->internal_buffer = gst_buffer_ref(buffer);
3349 } else { /* sw codec */
3350 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3353 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3357 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3358 LOGE("failed to send video decoded data.");
3365 LOGE("release video stream resource.");
3366 if (gst_is_tizen_memory(mem)) {
3368 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3370 tbm_bo_unref(stream->bo[i]);
3373 /* unref gst buffer */
3374 if (stream->internal_buffer)
3375 gst_buffer_unref(stream->internal_buffer);
3378 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3380 MMPLAYER_FREEIF(stream);
3385 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3387 mmplayer_gst_element_t *videobin = NULL;
3390 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3392 videobin = player->pipeline->videobin;
3394 /* Set spatial media metadata and/or user settings to the element.
3396 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3397 "projection-type", player->video360_metadata.projection_type, NULL);
3399 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3400 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3402 if (player->video360_metadata.full_pano_width_pixels &&
3403 player->video360_metadata.full_pano_height_pixels &&
3404 player->video360_metadata.cropped_area_image_width &&
3405 player->video360_metadata.cropped_area_image_height) {
3406 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3407 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3408 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3409 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3410 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3411 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3412 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3416 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3417 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3418 "horizontal-fov", player->video360_horizontal_fov,
3419 "vertical-fov", player->video360_vertical_fov, NULL);
3422 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3423 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3424 "zoom", 1.0f / player->video360_zoom, NULL);
3427 if (player->video360_yaw_radians <= M_PI &&
3428 player->video360_yaw_radians >= -M_PI &&
3429 player->video360_pitch_radians <= M_PI_2 &&
3430 player->video360_pitch_radians >= -M_PI_2) {
3431 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3432 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3433 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3434 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3435 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3436 "pose-yaw", player->video360_metadata.init_view_heading,
3437 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3440 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3441 "passthrough", !player->is_video360_enabled, NULL);
3448 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3450 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3451 GList *element_bucket = NULL;
3454 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3456 /* create video360 filter */
3457 if (player->is_360_feature_enabled && player->is_content_spherical) {
3458 LOGD("create video360 element");
3459 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3460 __mmplayer_gst_set_video360_property(player);
3464 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3465 LOGD("skip creating the videoconv and rotator");
3466 return MM_ERROR_NONE;
3469 /* in case of sw codec & overlay surface type, except 360 playback.
3470 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3471 LOGD("create video converter: %s", video_csc);
3472 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3475 *bucket = element_bucket;
3477 return MM_ERROR_NONE;
3479 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3480 g_list_free(element_bucket);
3484 return MM_ERROR_PLAYER_INTERNAL;
3488 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3490 gchar *factory_name = NULL;
3492 switch (surface_type) {
3493 case MM_DISPLAY_SURFACE_OVERLAY:
3494 if (strlen(player->ini.videosink_element_overlay) > 0)
3495 factory_name = player->ini.videosink_element_overlay;
3497 case MM_DISPLAY_SURFACE_REMOTE:
3498 case MM_DISPLAY_SURFACE_NULL:
3499 if (strlen(player->ini.videosink_element_fake) > 0)
3500 factory_name = player->ini.videosink_element_fake;
3503 LOGE("unidentified surface type");
3507 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3508 return factory_name;
3512 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3514 gchar *factory_name = NULL;
3515 mmplayer_gst_element_t *videobin = NULL;
3520 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3522 videobin = player->pipeline->videobin;
3523 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3525 attrs = MMPLAYER_GET_ATTRS(player);
3527 LOGE("cannot get content attribute");
3528 return MM_ERROR_PLAYER_INTERNAL;
3531 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3532 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3533 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3535 /* support shard memory with S/W codec on HawkP */
3536 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3537 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3538 "use-tbm", use_tbm, NULL);
3542 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3543 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3546 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3548 LOGD("disable last-sample");
3549 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3552 if (player->set_mode.video_export) {
3554 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3555 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3556 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3558 _mmplayer_add_signal_connection(player,
3559 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3560 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3562 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3565 _mmplayer_add_signal_connection(player,
3566 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3567 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3569 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3573 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3574 return MM_ERROR_PLAYER_INTERNAL;
3576 if (videobin[MMPLAYER_V_SINK].gst) {
3577 GstPad *sink_pad = NULL;
3578 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3580 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3581 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3582 gst_object_unref(GST_OBJECT(sink_pad));
3584 LOGE("failed to get sink pad from videosink");
3588 return MM_ERROR_NONE;
3593 * - video overlay surface(arm/x86) : tizenwlsink
3596 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3599 GList *element_bucket = NULL;
3600 mmplayer_gst_element_t *first_element = NULL;
3601 mmplayer_gst_element_t *videobin = NULL;
3602 gchar *videosink_factory_name = NULL;
3605 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3608 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3610 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3612 player->pipeline->videobin = videobin;
3615 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3616 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3617 if (!videobin[MMPLAYER_V_BIN].gst) {
3618 LOGE("failed to create videobin");
3622 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3625 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3626 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3628 /* additional setting for sink plug-in */
3629 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3630 LOGE("failed to set video property");
3634 /* store it as it's sink element */
3635 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3637 /* adding created elements to bin */
3638 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3639 LOGE("failed to add elements");
3643 /* Linking elements in the bucket by added order */
3644 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3645 LOGE("failed to link elements");
3649 /* get first element's sinkpad for creating ghostpad */
3650 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3651 if (!first_element) {
3652 LOGE("failed to get first element from bucket");
3656 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3658 LOGE("failed to get pad from first element");
3662 /* create ghostpad */
3663 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3664 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3665 LOGE("failed to add ghostpad to videobin");
3668 gst_object_unref(pad);
3670 /* done. free allocated variables */
3671 g_list_free(element_bucket);
3675 return MM_ERROR_NONE;
3678 LOGE("ERROR : releasing videobin");
3679 g_list_free(element_bucket);
3682 gst_object_unref(GST_OBJECT(pad));
3684 /* release videobin with it's childs */
3685 if (videobin[MMPLAYER_V_BIN].gst)
3686 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3688 MMPLAYER_FREEIF(videobin);
3689 player->pipeline->videobin = NULL;
3691 return MM_ERROR_PLAYER_INTERNAL;
3695 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3697 GList *element_bucket = NULL;
3698 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3700 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3701 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3702 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3703 "signal-handoffs", FALSE,
3706 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3707 _mmplayer_add_signal_connection(player,
3708 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3709 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3711 G_CALLBACK(__mmplayer_update_subtitle),
3714 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3715 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3717 if (!player->play_subtitle) {
3718 LOGD("add textbin sink as sink element of whole pipeline.");
3719 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3722 /* adding created elements to bin */
3723 LOGD("adding created elements to bin");
3724 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3725 LOGE("failed to add elements");
3729 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3730 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3731 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3733 /* linking elements in the bucket by added order. */
3734 LOGD("Linking elements in the bucket by added order.");
3735 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3736 LOGE("failed to link elements");
3740 /* done. free allocated variables */
3741 g_list_free(element_bucket);
3743 if (textbin[MMPLAYER_T_QUEUE].gst) {
3745 GstPad *ghostpad = NULL;
3747 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3749 LOGE("failed to get sink pad of text queue");
3753 ghostpad = gst_ghost_pad_new("text_sink", pad);
3754 gst_object_unref(pad);
3757 LOGE("failed to create ghostpad of textbin");
3761 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3762 LOGE("failed to add ghostpad to textbin");
3763 gst_object_unref(ghostpad);
3768 return MM_ERROR_NONE;
3771 g_list_free(element_bucket);
3773 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3774 LOGE("remove textbin sink from sink list");
3775 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3778 /* release element at __mmplayer_gst_create_text_sink_bin */
3779 return MM_ERROR_PLAYER_INTERNAL;
3783 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3785 mmplayer_gst_element_t *textbin = NULL;
3786 GList *element_bucket = NULL;
3787 int surface_type = 0;
3792 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3795 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3797 LOGE("failed to allocate memory for textbin");
3798 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3802 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3803 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3804 if (!textbin[MMPLAYER_T_BIN].gst) {
3805 LOGE("failed to create textbin");
3810 player->pipeline->textbin = textbin;
3813 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3814 LOGD("surface type for subtitle : %d", surface_type);
3815 switch (surface_type) {
3816 case MM_DISPLAY_SURFACE_OVERLAY:
3817 case MM_DISPLAY_SURFACE_NULL:
3818 case MM_DISPLAY_SURFACE_REMOTE:
3819 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3820 LOGE("failed to make plain text elements");
3831 return MM_ERROR_NONE;
3835 LOGD("ERROR : releasing textbin");
3837 g_list_free(element_bucket);
3839 /* release signal */
3840 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3842 /* release element which are not added to bin */
3843 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3844 /* NOTE : skip bin */
3845 if (textbin[i].gst) {
3846 GstObject *parent = NULL;
3847 parent = gst_element_get_parent(textbin[i].gst);
3850 gst_object_unref(GST_OBJECT(textbin[i].gst));
3851 textbin[i].gst = NULL;
3853 gst_object_unref(GST_OBJECT(parent));
3858 /* release textbin with it's childs */
3859 if (textbin[MMPLAYER_T_BIN].gst)
3860 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3862 MMPLAYER_FREEIF(player->pipeline->textbin);
3863 player->pipeline->textbin = NULL;
3866 return MM_ERROR_PLAYER_INTERNAL;
3870 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3872 mmplayer_gst_element_t *mainbin = NULL;
3873 mmplayer_gst_element_t *textbin = NULL;
3874 MMHandleType attrs = 0;
3875 GstElement *subsrc = NULL;
3876 GstElement *subparse = NULL;
3877 gchar *subtitle_uri = NULL;
3878 const gchar *charset = NULL;
3884 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3886 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3888 mainbin = player->pipeline->mainbin;
3890 attrs = MMPLAYER_GET_ATTRS(player);
3892 LOGE("cannot get content attribute");
3893 return MM_ERROR_PLAYER_INTERNAL;
3896 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3897 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3898 LOGE("subtitle uri is not proper filepath.");
3899 return MM_ERROR_PLAYER_INVALID_URI;
3902 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3903 LOGE("failed to get storage info of subtitle path");
3904 return MM_ERROR_PLAYER_INVALID_URI;
3907 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3909 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3910 player->subtitle_language_list = NULL;
3911 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3913 /* create the subtitle source */
3914 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3916 LOGE("failed to create filesrc element");
3919 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3921 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3922 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3924 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3925 LOGW("failed to add queue");
3926 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3927 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3928 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3933 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3935 LOGE("failed to create subparse element");
3939 charset = _mmplayer_get_charset(subtitle_uri);
3941 LOGD("detected charset is %s", charset);
3942 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3945 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3946 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3948 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3949 LOGW("failed to add subparse");
3950 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3951 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3952 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3956 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3957 LOGW("failed to link subsrc and subparse");
3961 player->play_subtitle = TRUE;
3962 player->adjust_subtitle_pos = 0;
3964 LOGD("play subtitle using subtitle file");
3966 if (player->pipeline->textbin == NULL) {
3967 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3968 LOGE("failed to create text sink bin. continuing without text");
3972 textbin = player->pipeline->textbin;
3974 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3975 LOGW("failed to add textbin");
3977 /* release signal */
3978 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3980 /* release textbin with it's childs */
3981 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3982 MMPLAYER_FREEIF(player->pipeline->textbin);
3983 player->pipeline->textbin = textbin = NULL;
3987 LOGD("link text input selector and textbin ghost pad");
3989 player->textsink_linked = 1;
3990 player->external_text_idx = 0;
3991 LOGI("textsink is linked");
3993 textbin = player->pipeline->textbin;
3994 LOGD("text bin has been created. reuse it.");
3995 player->external_text_idx = 1;
3998 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3999 LOGW("failed to link subparse and textbin");
4003 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4005 LOGE("failed to get sink pad from textsink to probe data");
4009 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4010 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4012 gst_object_unref(pad);
4015 /* create dot. for debugging */
4016 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4019 return MM_ERROR_NONE;
4022 /* release text pipeline resource */
4023 player->textsink_linked = 0;
4025 /* release signal */
4026 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4028 if (player->pipeline->textbin) {
4029 LOGE("remove textbin");
4031 /* release textbin with it's childs */
4032 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4033 MMPLAYER_FREEIF(player->pipeline->textbin);
4034 player->pipeline->textbin = NULL;
4038 /* release subtitle elem */
4039 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4040 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4042 return MM_ERROR_PLAYER_INTERNAL;
4046 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4048 mmplayer_t *player = (mmplayer_t *)data;
4049 MMMessageParamType msg = {0, };
4050 GstClockTime duration = 0;
4051 gpointer text = NULL;
4052 guint text_size = 0;
4053 gboolean ret = TRUE;
4054 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4058 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4059 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4061 if (player->is_subtitle_force_drop) {
4062 LOGW("subtitle is dropped forcedly.");
4066 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4067 text = mapinfo.data;
4068 text_size = mapinfo.size;
4070 if (player->set_mode.subtitle_off) {
4071 LOGD("subtitle is OFF.");
4075 if (!text || (text_size == 0)) {
4076 LOGD("There is no subtitle to be displayed.");
4080 msg.data = (void *)text;
4082 duration = GST_BUFFER_DURATION(buffer);
4084 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4085 if (player->duration > GST_BUFFER_PTS(buffer))
4086 duration = player->duration - GST_BUFFER_PTS(buffer);
4089 LOGI("subtitle duration is invalid, subtitle duration change "
4090 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4092 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4094 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4096 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4097 gst_buffer_unmap(buffer, &mapinfo);
4104 static GstPadProbeReturn
4105 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4107 mmplayer_t *player = (mmplayer_t *)u_data;
4108 GstClockTime cur_timestamp = 0;
4109 gint64 adjusted_timestamp = 0;
4110 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4112 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4114 if (player->set_mode.subtitle_off) {
4115 LOGD("subtitle is OFF.");
4119 if (player->adjust_subtitle_pos == 0) {
4120 LOGD("nothing to do");
4124 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4125 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4127 if (adjusted_timestamp < 0) {
4128 LOGD("adjusted_timestamp under zero");
4133 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4134 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4135 GST_TIME_ARGS(cur_timestamp),
4136 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4138 return GST_PAD_PROBE_OK;
4142 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4146 /* check player and subtitlebin are created */
4147 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4148 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4150 if (position == 0) {
4151 LOGD("nothing to do");
4153 return MM_ERROR_NONE;
4156 /* check current postion */
4157 player->adjust_subtitle_pos = position;
4159 LOGD("save adjust_subtitle_pos in player");
4163 return MM_ERROR_NONE;
4167 * This function is to create audio or video pipeline for playing.
4169 * @param player [in] handle of player
4171 * @return This function returns zero on success.
4176 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4178 int ret = MM_ERROR_NONE;
4179 mmplayer_gst_element_t *mainbin = NULL;
4180 MMHandleType attrs = 0;
4183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4185 /* get profile attribute */
4186 attrs = MMPLAYER_GET_ATTRS(player);
4188 LOGE("failed to get content attribute");
4192 /* create pipeline handles */
4193 if (player->pipeline) {
4194 LOGE("pipeline should be released before create new one");
4198 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4199 if (player->pipeline == NULL)
4202 /* create mainbin */
4203 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4204 if (mainbin == NULL)
4207 /* create pipeline */
4208 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4209 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4210 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4211 LOGE("failed to create pipeline");
4216 player->pipeline->mainbin = mainbin;
4218 /* create the source and decoder elements */
4219 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4220 ret = _mmplayer_gst_build_es_pipeline(player);
4222 ret = _mmplayer_gst_build_pipeline(player);
4224 if (ret != MM_ERROR_NONE) {
4225 LOGE("failed to create some elements");
4229 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4230 if (__mmplayer_check_subtitle(player)
4231 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4232 LOGE("failed to create text pipeline");
4235 ret = _mmplayer_gst_add_bus_watch(player);
4236 if (ret != MM_ERROR_NONE) {
4237 LOGE("failed to add bus watch");
4242 return MM_ERROR_NONE;
4245 __mmplayer_gst_destroy_pipeline(player);
4246 return MM_ERROR_PLAYER_INTERNAL;
4250 __mmplayer_reset_gapless_state(mmplayer_t *player)
4253 MMPLAYER_RETURN_IF_FAIL(player
4255 && player->pipeline->audiobin
4256 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4258 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4265 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4268 int ret = MM_ERROR_NONE;
4272 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4274 /* cleanup stuffs */
4275 MMPLAYER_FREEIF(player->type);
4276 player->no_more_pad = FALSE;
4277 player->num_dynamic_pad = 0;
4278 player->demux_pad_index = 0;
4280 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4281 player->subtitle_language_list = NULL;
4282 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4284 __mmplayer_reset_gapless_state(player);
4286 if (player->streamer) {
4287 _mm_player_streaming_initialize(player->streamer, FALSE);
4288 _mm_player_streaming_destroy(player->streamer);
4289 player->streamer = NULL;
4292 /* cleanup unlinked mime type */
4293 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4294 MMPLAYER_FREEIF(player->unlinked_video_mime);
4295 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4297 /* cleanup running stuffs */
4298 _mmplayer_cancel_eos_timer(player);
4300 /* cleanup gst stuffs */
4301 if (player->pipeline) {
4302 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4303 GstTagList *tag_list = player->pipeline->tag_list;
4305 /* first we need to disconnect all signal hander */
4306 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4309 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4310 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4311 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4312 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4313 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4314 gst_object_unref(bus);
4316 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4317 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4318 if (ret != MM_ERROR_NONE) {
4319 LOGE("fail to change state to NULL");
4320 return MM_ERROR_PLAYER_INTERNAL;
4323 LOGW("succeeded in changing state to NULL");
4325 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4328 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4329 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4331 /* free avsysaudiosink
4332 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4333 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4335 MMPLAYER_FREEIF(audiobin);
4336 MMPLAYER_FREEIF(videobin);
4337 MMPLAYER_FREEIF(textbin);
4338 MMPLAYER_FREEIF(mainbin);
4342 gst_tag_list_unref(tag_list);
4344 MMPLAYER_FREEIF(player->pipeline);
4346 MMPLAYER_FREEIF(player->album_art);
4348 if (player->v_stream_caps) {
4349 gst_caps_unref(player->v_stream_caps);
4350 player->v_stream_caps = NULL;
4353 if (player->a_stream_caps) {
4354 gst_caps_unref(player->a_stream_caps);
4355 player->a_stream_caps = NULL;
4358 if (player->s_stream_caps) {
4359 gst_caps_unref(player->s_stream_caps);
4360 player->s_stream_caps = NULL;
4362 _mmplayer_track_destroy(player);
4364 if (player->sink_elements)
4365 g_list_free(player->sink_elements);
4366 player->sink_elements = NULL;
4368 if (player->bufmgr) {
4369 tbm_bufmgr_deinit(player->bufmgr);
4370 player->bufmgr = NULL;
4373 LOGW("finished destroy pipeline");
4381 __mmplayer_gst_realize(mmplayer_t *player)
4384 int ret = MM_ERROR_NONE;
4388 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4390 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4392 ret = __mmplayer_gst_create_pipeline(player);
4394 LOGE("failed to create pipeline");
4398 /* set pipeline state to READY */
4399 /* NOTE : state change to READY must be performed sync. */
4400 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4401 ret = _mmplayer_gst_set_state(player,
4402 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4404 if (ret != MM_ERROR_NONE) {
4405 /* return error if failed to set state */
4406 LOGE("failed to set READY state");
4410 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4412 /* create dot before error-return. for debugging */
4413 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4421 __mmplayer_gst_unrealize(mmplayer_t *player)
4423 int ret = MM_ERROR_NONE;
4427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4429 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4430 MMPLAYER_PRINT_STATE(player);
4432 /* release miscellaneous information */
4433 __mmplayer_release_misc(player);
4435 /* destroy pipeline */
4436 ret = __mmplayer_gst_destroy_pipeline(player);
4437 if (ret != MM_ERROR_NONE) {
4438 LOGE("failed to destory pipeline");
4442 /* release miscellaneous information.
4443 these info needs to be released after pipeline is destroyed. */
4444 __mmplayer_release_misc_post(player);
4446 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4454 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4459 LOGW("set_message_callback is called with invalid player handle");
4460 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4463 player->msg_cb = callback;
4464 player->msg_cb_param = user_param;
4466 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4470 return MM_ERROR_NONE;
4474 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4476 int ret = MM_ERROR_NONE;
4481 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4482 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4483 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4485 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4487 if (strstr(uri, "es_buff://")) {
4488 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4489 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4490 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4491 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4493 tmp = g_ascii_strdown(uri, strlen(uri));
4494 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4495 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4497 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4499 } else if (strstr(uri, "mms://")) {
4500 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4501 } else if ((path = strstr(uri, "mem://"))) {
4502 ret = __mmplayer_set_mem_uri(data, path, param);
4504 ret = __mmplayer_set_file_uri(data, uri);
4507 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4508 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4509 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4510 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4512 /* dump parse result */
4513 SECURE_LOGW("incoming uri : %s", uri);
4514 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4515 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4523 __mmplayer_can_do_interrupt(mmplayer_t *player)
4525 if (!player || !player->pipeline || !player->attrs) {
4526 LOGW("not initialized");
4530 if (player->audio_decoded_cb) {
4531 LOGW("not support in pcm extraction mode");
4535 /* check if seeking */
4536 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4537 MMMessageParamType msg_param;
4538 memset(&msg_param, 0, sizeof(MMMessageParamType));
4539 msg_param.code = MM_ERROR_PLAYER_SEEK;
4540 player->seek_state = MMPLAYER_SEEK_NONE;
4541 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4545 /* check other thread */
4546 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4547 LOGW("locked already, cmd state : %d", player->cmd);
4549 /* check application command */
4550 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4551 LOGW("playing.. should wait cmd lock then, will be interrupted");
4553 /* lock will be released at mrp_resource_release_cb() */
4554 MMPLAYER_CMD_LOCK(player);
4557 LOGW("nothing to do");
4560 LOGW("can interrupt immediately");
4564 FAILED: /* with CMD UNLOCKED */
4567 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4572 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4575 mmplayer_t *player = NULL;
4576 MMMessageParamType msg = {0, };
4578 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4583 LOGE("user_data is null");
4586 player = (mmplayer_t *)user_data;
4588 if (!__mmplayer_can_do_interrupt(player)) {
4589 LOGW("no need to interrupt, so leave");
4590 /* FIXME: there is no way to avoid releasing resource. */
4594 player->interrupted_by_resource = TRUE;
4596 /* get last play position */
4597 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4598 msg.union_type = MM_MSG_UNION_TIME;
4599 msg.time.elapsed = pos;
4600 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4602 LOGW("failed to get play position.");
4605 LOGD("video resource conflict so, resource will be freed by unrealizing");
4606 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4607 LOGE("failed to unrealize");
4609 /* lock is called in __mmplayer_can_do_interrupt() */
4610 MMPLAYER_CMD_UNLOCK(player);
4612 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4613 player->hw_resource[res_idx] = NULL;
4617 return TRUE; /* release all the resources */
4621 __mmplayer_initialize_video_roi(mmplayer_t *player)
4623 player->video_roi.scale_x = 0.0;
4624 player->video_roi.scale_y = 0.0;
4625 player->video_roi.scale_width = 1.0;
4626 player->video_roi.scale_height = 1.0;
4630 _mmplayer_create_player(MMHandleType handle)
4632 int ret = MM_ERROR_PLAYER_INTERNAL;
4633 bool enabled = false;
4635 mmplayer_t *player = MM_PLAYER_CAST(handle);
4639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4641 /* initialize player state */
4642 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4643 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4644 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4645 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4647 /* check current state */
4648 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4650 /* construct attributes */
4651 player->attrs = _mmplayer_construct_attribute(handle);
4653 if (!player->attrs) {
4654 LOGE("Failed to construct attributes");
4658 /* initialize gstreamer with configured parameter */
4659 if (!__mmplayer_init_gstreamer(player)) {
4660 LOGE("Initializing gstreamer failed");
4661 _mmplayer_deconstruct_attribute(handle);
4665 /* create lock. note that g_tread_init() has already called in gst_init() */
4666 g_mutex_init(&player->fsink_lock);
4668 /* create update tag lock */
4669 g_mutex_init(&player->update_tag_lock);
4671 /* create gapless play mutex */
4672 g_mutex_init(&player->gapless_play_thread_mutex);
4674 /* create gapless play cond */
4675 g_cond_init(&player->gapless_play_thread_cond);
4677 /* create gapless play thread */
4678 player->gapless_play_thread =
4679 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4680 if (!player->gapless_play_thread) {
4681 LOGE("failed to create gapless play thread");
4682 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4683 g_mutex_clear(&player->gapless_play_thread_mutex);
4684 g_cond_clear(&player->gapless_play_thread_cond);
4688 player->bus_msg_q = g_queue_new();
4689 if (!player->bus_msg_q) {
4690 LOGE("failed to create queue for bus_msg");
4691 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4695 ret = _mmplayer_initialize_video_capture(player);
4696 if (ret != MM_ERROR_NONE) {
4697 LOGE("failed to initialize video capture");
4701 /* initialize resource manager */
4702 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4703 __resource_release_cb, player, &player->resource_manager)
4704 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4705 LOGE("failed to initialize resource manager");
4706 ret = MM_ERROR_PLAYER_INTERNAL;
4710 /* create video bo lock and cond */
4711 g_mutex_init(&player->video_bo_mutex);
4712 g_cond_init(&player->video_bo_cond);
4714 /* create subtitle info lock and cond */
4715 g_mutex_init(&player->subtitle_info_mutex);
4716 g_cond_init(&player->subtitle_info_cond);
4718 player->streaming_type = STREAMING_SERVICE_NONE;
4720 /* give default value of audio effect setting */
4721 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4722 player->sound.rg_enable = false;
4723 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4725 player->play_subtitle = FALSE;
4726 player->has_closed_caption = FALSE;
4727 player->pending_resume = FALSE;
4728 if (player->ini.dump_element_keyword[0][0] == '\0')
4729 player->ini.set_dump_element_flag = FALSE;
4731 player->ini.set_dump_element_flag = TRUE;
4733 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4734 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4735 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4737 /* Set video360 settings to their defaults for just-created player.
4740 player->is_360_feature_enabled = FALSE;
4741 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4742 LOGI("spherical feature info: %d", enabled);
4744 player->is_360_feature_enabled = TRUE;
4746 LOGE("failed to get spherical feature info");
4749 player->is_content_spherical = FALSE;
4750 player->is_video360_enabled = TRUE;
4751 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4752 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4753 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4754 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4755 player->video360_zoom = 1.0f;
4756 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4757 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4759 __mmplayer_initialize_video_roi(player);
4761 /* set player state to null */
4762 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4763 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4767 return MM_ERROR_NONE;
4771 g_mutex_clear(&player->fsink_lock);
4772 /* free update tag lock */
4773 g_mutex_clear(&player->update_tag_lock);
4774 g_queue_free(player->bus_msg_q);
4775 player->bus_msg_q = NULL;
4776 /* free gapless play thread */
4777 if (player->gapless_play_thread) {
4778 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4779 player->gapless_play_thread_exit = TRUE;
4780 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4781 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4783 g_thread_join(player->gapless_play_thread);
4784 player->gapless_play_thread = NULL;
4786 g_mutex_clear(&player->gapless_play_thread_mutex);
4787 g_cond_clear(&player->gapless_play_thread_cond);
4790 /* release attributes */
4791 _mmplayer_deconstruct_attribute(handle);
4799 __mmplayer_init_gstreamer(mmplayer_t *player)
4801 static gboolean initialized = FALSE;
4802 static const int max_argc = 50;
4804 gchar **argv = NULL;
4805 gchar **argv2 = NULL;
4811 LOGD("gstreamer already initialized.");
4816 argc = malloc(sizeof(int));
4817 argv = malloc(sizeof(gchar *) * max_argc);
4818 argv2 = malloc(sizeof(gchar *) * max_argc);
4820 if (!argc || !argv || !argv2)
4823 memset(argv, 0, sizeof(gchar *) * max_argc);
4824 memset(argv2, 0, sizeof(gchar *) * max_argc);
4828 argv[0] = g_strdup("mmplayer");
4831 for (i = 0; i < 5; i++) {
4832 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4833 if (strlen(player->ini.gst_param[i]) > 0) {
4834 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4839 /* we would not do fork for scanning plugins */
4840 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4843 /* check disable registry scan */
4844 if (player->ini.skip_rescan) {
4845 argv[*argc] = g_strdup("--gst-disable-registry-update");
4849 /* check disable segtrap */
4850 if (player->ini.disable_segtrap) {
4851 argv[*argc] = g_strdup("--gst-disable-segtrap");
4855 LOGD("initializing gstreamer with following parameter");
4856 LOGD("argc : %d", *argc);
4859 for (i = 0; i < arg_count; i++) {
4861 LOGD("argv[%d] : %s", i, argv2[i]);
4864 /* initializing gstreamer */
4865 if (!gst_init_check(argc, &argv, &err)) {
4866 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4873 for (i = 0; i < arg_count; i++) {
4874 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4875 MMPLAYER_FREEIF(argv2[i]);
4878 MMPLAYER_FREEIF(argv);
4879 MMPLAYER_FREEIF(argv2);
4880 MMPLAYER_FREEIF(argc);
4890 for (i = 0; i < arg_count; i++) {
4891 LOGD("free[%d] : %s", i, argv2[i]);
4892 MMPLAYER_FREEIF(argv2[i]);
4895 MMPLAYER_FREEIF(argv);
4896 MMPLAYER_FREEIF(argv2);
4897 MMPLAYER_FREEIF(argc);
4903 __mmplayer_check_async_state_transition(mmplayer_t *player)
4905 GstState element_state = GST_STATE_VOID_PENDING;
4906 GstState element_pending_state = GST_STATE_VOID_PENDING;
4907 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4908 GstElement *element = NULL;
4909 gboolean async = FALSE;
4911 /* check player handle */
4912 MMPLAYER_RETURN_IF_FAIL(player &&
4914 player->pipeline->mainbin &&
4915 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4918 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4920 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4921 LOGD("don't need to check the pipeline state");
4925 MMPLAYER_PRINT_STATE(player);
4927 /* wait for state transition */
4928 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4929 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4931 if (ret == GST_STATE_CHANGE_FAILURE) {
4932 LOGE(" [%s] state : %s pending : %s",
4933 GST_ELEMENT_NAME(element),
4934 gst_element_state_get_name(element_state),
4935 gst_element_state_get_name(element_pending_state));
4937 /* dump state of all element */
4938 _mmplayer_dump_pipeline_state(player);
4943 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4948 _mmplayer_destroy(MMHandleType handle)
4950 mmplayer_t *player = MM_PLAYER_CAST(handle);
4954 /* check player handle */
4955 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4957 /* destroy can called at anytime */
4958 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4960 /* check async state transition */
4961 __mmplayer_check_async_state_transition(player);
4963 /* release gapless play thread */
4964 if (player->gapless_play_thread) {
4965 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4966 player->gapless_play_thread_exit = TRUE;
4967 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4968 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4970 LOGD("waitting for gapless play thread exit");
4971 g_thread_join(player->gapless_play_thread);
4972 g_mutex_clear(&player->gapless_play_thread_mutex);
4973 g_cond_clear(&player->gapless_play_thread_cond);
4974 LOGD("gapless play thread released");
4977 _mmplayer_release_video_capture(player);
4979 /* de-initialize resource manager */
4980 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4981 player->resource_manager))
4982 LOGE("failed to deinitialize resource manager");
4984 /* release pipeline */
4985 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4986 LOGE("failed to destory pipeline");
4987 return MM_ERROR_PLAYER_INTERNAL;
4990 g_queue_free(player->bus_msg_q);
4992 /* release subtitle info lock and cond */
4993 g_mutex_clear(&player->subtitle_info_mutex);
4994 g_cond_clear(&player->subtitle_info_cond);
4996 __mmplayer_release_dump_list(player->dump_list);
4998 /* release miscellaneous information */
4999 __mmplayer_release_misc(player);
5001 /* release miscellaneous information.
5002 these info needs to be released after pipeline is destroyed. */
5003 __mmplayer_release_misc_post(player);
5005 /* release attributes */
5006 _mmplayer_deconstruct_attribute(handle);
5009 g_mutex_clear(&player->fsink_lock);
5012 g_mutex_clear(&player->update_tag_lock);
5014 /* release video bo lock and cond */
5015 g_mutex_clear(&player->video_bo_mutex);
5016 g_cond_clear(&player->video_bo_cond);
5020 return MM_ERROR_NONE;
5024 _mmplayer_realize(MMHandleType hplayer)
5026 mmplayer_t *player = (mmplayer_t *)hplayer;
5029 MMHandleType attrs = 0;
5030 int ret = MM_ERROR_NONE;
5034 /* check player handle */
5035 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5037 /* check current state */
5038 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5040 attrs = MMPLAYER_GET_ATTRS(player);
5042 LOGE("fail to get attributes.");
5043 return MM_ERROR_PLAYER_INTERNAL;
5045 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5046 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5048 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5049 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5051 if (ret != MM_ERROR_NONE) {
5052 LOGE("failed to parse profile");
5057 if (uri && (strstr(uri, "es_buff://"))) {
5058 if (strstr(uri, "es_buff://push_mode"))
5059 player->es_player_push_mode = TRUE;
5061 player->es_player_push_mode = FALSE;
5064 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5065 LOGW("mms protocol is not supported format.");
5066 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5069 if (MMPLAYER_IS_STREAMING(player))
5070 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5072 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5074 player->smooth_streaming = FALSE;
5075 player->videodec_linked = 0;
5076 player->audiodec_linked = 0;
5077 player->textsink_linked = 0;
5078 player->is_external_subtitle_present = FALSE;
5079 player->is_external_subtitle_added_now = FALSE;
5080 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5081 player->video360_metadata.is_spherical = -1;
5082 player->is_openal_plugin_used = FALSE;
5083 player->demux_pad_index = 0;
5084 player->subtitle_language_list = NULL;
5085 player->is_subtitle_force_drop = FALSE;
5087 _mmplayer_track_initialize(player);
5088 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5090 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5091 gint prebuffer_ms = 0, rebuffer_ms = 0;
5093 player->streamer = _mm_player_streaming_create();
5094 _mm_player_streaming_initialize(player->streamer, TRUE);
5096 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5097 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5099 if (prebuffer_ms > 0) {
5100 prebuffer_ms = MAX(prebuffer_ms, 1000);
5101 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5104 if (rebuffer_ms > 0) {
5105 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5106 rebuffer_ms = MAX(rebuffer_ms, 1000);
5107 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5110 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5111 player->streamer->buffering_req.rebuffer_time);
5114 /* realize pipeline */
5115 ret = __mmplayer_gst_realize(player);
5116 if (ret != MM_ERROR_NONE)
5117 LOGE("fail to realize the player.");
5119 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5127 _mmplayer_unrealize(MMHandleType hplayer)
5129 mmplayer_t *player = (mmplayer_t *)hplayer;
5130 int ret = MM_ERROR_NONE;
5134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5136 MMPLAYER_CMD_UNLOCK(player);
5137 /* destroy the gst bus msg thread which is created during realize.
5138 this funct have to be called before getting cmd lock. */
5139 _mmplayer_bus_msg_thread_destroy(player);
5140 MMPLAYER_CMD_LOCK(player);
5142 /* check current state */
5143 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5145 /* check async state transition */
5146 __mmplayer_check_async_state_transition(player);
5148 /* unrealize pipeline */
5149 ret = __mmplayer_gst_unrealize(player);
5151 if (!player->interrupted_by_resource) {
5152 if ((__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) ||
5153 (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE))
5154 LOGE("failed to release video resources");
5162 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5164 mmplayer_t *player = (mmplayer_t *)hplayer;
5166 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5168 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5172 _mmplayer_get_state(MMHandleType hplayer, int *state)
5174 mmplayer_t *player = (mmplayer_t *)hplayer;
5176 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5178 *state = MMPLAYER_CURRENT_STATE(player);
5180 return MM_ERROR_NONE;
5184 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5186 GstElement *vol_element = NULL;
5187 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5190 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5191 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5193 /* check pipeline handle */
5194 if (!player->pipeline || !player->pipeline->audiobin) {
5195 LOGD("'%s' will be applied when audiobin is created", prop_name);
5197 /* NOTE : stored value will be used in create_audiobin
5198 * returning MM_ERROR_NONE here makes application to able to
5199 * set audio volume or mute at anytime.
5201 return MM_ERROR_NONE;
5204 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5205 volume_elem_id = MMPLAYER_A_SINK;
5207 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5209 LOGE("failed to get vol element %d", volume_elem_id);
5210 return MM_ERROR_PLAYER_INTERNAL;
5213 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5215 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5216 LOGE("there is no '%s' property", prop_name);
5217 return MM_ERROR_PLAYER_INTERNAL;
5220 if (!strcmp(prop_name, "volume")) {
5221 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5222 } else if (!strcmp(prop_name, "mute")) {
5223 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5225 LOGE("invalid property %s", prop_name);
5226 return MM_ERROR_PLAYER_INTERNAL;
5229 return MM_ERROR_NONE;
5233 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5235 int ret = MM_ERROR_NONE;
5236 mmplayer_t *player = (mmplayer_t *)hplayer;
5239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5241 LOGD("volume = %f", volume);
5243 /* invalid factor range or not */
5244 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5245 LOGE("Invalid volume value");
5246 return MM_ERROR_INVALID_ARGUMENT;
5249 player->sound.volume = volume;
5251 ret = __mmplayer_gst_set_volume_property(player, "volume");
5258 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5260 mmplayer_t *player = (mmplayer_t *)hplayer;
5264 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5265 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5267 *volume = player->sound.volume;
5269 LOGD("current vol = %f", *volume);
5272 return MM_ERROR_NONE;
5276 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5278 int ret = MM_ERROR_NONE;
5279 mmplayer_t *player = (mmplayer_t *)hplayer;
5282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5284 LOGD("mute = %d", mute);
5286 player->sound.mute = mute;
5288 ret = __mmplayer_gst_set_volume_property(player, "mute");
5295 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5297 mmplayer_t *player = (mmplayer_t *)hplayer;
5301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5302 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5304 *mute = player->sound.mute;
5306 LOGD("current mute = %d", *mute);
5310 return MM_ERROR_NONE;
5314 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5316 mmplayer_t *player = (mmplayer_t *)hplayer;
5320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5322 player->audio_stream_changed_cb = callback;
5323 player->audio_stream_changed_cb_user_param = user_param;
5324 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5328 return MM_ERROR_NONE;
5332 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5334 mmplayer_t *player = (mmplayer_t *)hplayer;
5338 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5340 player->audio_decoded_cb = callback;
5341 player->audio_decoded_cb_user_param = user_param;
5342 player->audio_extract_opt = opt;
5343 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5347 return MM_ERROR_NONE;
5351 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5353 mmplayer_t *player = (mmplayer_t *)hplayer;
5357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5359 if (callback && !player->bufmgr)
5360 player->bufmgr = tbm_bufmgr_init(-1);
5362 player->set_mode.video_export = (callback) ? true : false;
5363 player->video_decoded_cb = callback;
5364 player->video_decoded_cb_user_param = user_param;
5366 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5370 return MM_ERROR_NONE;
5374 _mmplayer_start(MMHandleType hplayer)
5376 mmplayer_t *player = (mmplayer_t *)hplayer;
5377 gint ret = MM_ERROR_NONE;
5381 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5383 /* check current state */
5384 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5386 /* start pipeline */
5387 ret = _mmplayer_gst_start(player);
5388 if (ret != MM_ERROR_NONE)
5389 LOGE("failed to start player.");
5391 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5392 LOGD("force playing start even during buffering");
5393 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5401 /* NOTE: post "not supported codec message" to application
5402 * when one codec is not found during AUTOPLUGGING in MSL.
5403 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5404 * And, if any codec is not found, don't send message here.
5405 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5408 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5410 MMMessageParamType msg_param;
5411 memset(&msg_param, 0, sizeof(MMMessageParamType));
5412 gboolean post_msg_direct = FALSE;
5416 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5418 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5419 player->not_supported_codec, player->can_support_codec);
5421 if (player->not_found_demuxer) {
5422 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5423 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5425 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5426 MMPLAYER_FREEIF(msg_param.data);
5428 return MM_ERROR_NONE;
5431 if (player->not_supported_codec) {
5432 if (player->can_support_codec) {
5433 // There is one codec to play
5434 post_msg_direct = TRUE;
5436 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5437 post_msg_direct = TRUE;
5440 if (post_msg_direct) {
5441 MMMessageParamType msg_param;
5442 memset(&msg_param, 0, sizeof(MMMessageParamType));
5444 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5445 LOGW("not found AUDIO codec, posting error code to application.");
5447 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5448 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5449 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5450 LOGW("not found VIDEO codec, posting error code to application.");
5452 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5453 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5456 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5458 MMPLAYER_FREEIF(msg_param.data);
5460 return MM_ERROR_NONE;
5462 // no any supported codec case
5463 LOGW("not found any codec, posting error code to application.");
5465 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5466 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5467 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5469 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5470 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5473 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5475 MMPLAYER_FREEIF(msg_param.data);
5481 return MM_ERROR_NONE;
5485 __mmplayer_check_pipeline(mmplayer_t *player)
5487 GstState element_state = GST_STATE_VOID_PENDING;
5488 GstState element_pending_state = GST_STATE_VOID_PENDING;
5490 int ret = MM_ERROR_NONE;
5492 if (!player->gapless.reconfigure)
5495 LOGW("pipeline is under construction.");
5497 MMPLAYER_PLAYBACK_LOCK(player);
5498 MMPLAYER_PLAYBACK_UNLOCK(player);
5500 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5502 /* wait for state transition */
5503 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5504 if (ret == GST_STATE_CHANGE_FAILURE)
5505 LOGE("failed to change pipeline state within %d sec", timeout);
5508 /* NOTE : it should be able to call 'stop' anytime*/
5510 _mmplayer_stop(MMHandleType hplayer)
5512 mmplayer_t *player = (mmplayer_t *)hplayer;
5513 int ret = MM_ERROR_NONE;
5517 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5519 /* check current state */
5520 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5522 /* check pipline building state */
5523 __mmplayer_check_pipeline(player);
5524 __mmplayer_reset_gapless_state(player);
5526 /* NOTE : application should not wait for EOS after calling STOP */
5527 _mmplayer_cancel_eos_timer(player);
5530 player->seek_state = MMPLAYER_SEEK_NONE;
5533 ret = _mmplayer_gst_stop(player);
5535 if (ret != MM_ERROR_NONE)
5536 LOGE("failed to stop player.");
5544 _mmplayer_pause(MMHandleType hplayer)
5546 mmplayer_t *player = (mmplayer_t *)hplayer;
5547 gint64 pos_nsec = 0;
5548 gboolean async = FALSE;
5549 gint ret = MM_ERROR_NONE;
5553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5555 /* check current state */
5556 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5558 /* check pipline building state */
5559 __mmplayer_check_pipeline(player);
5561 switch (MMPLAYER_CURRENT_STATE(player)) {
5562 case MM_PLAYER_STATE_READY:
5564 /* check prepare async or not.
5565 * In the case of streaming playback, it's recommned to avoid blocking wait.
5567 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5568 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5570 /* Changing back sync of rtspsrc to async */
5571 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5572 LOGD("async prepare working mode for rtsp");
5578 case MM_PLAYER_STATE_PLAYING:
5580 /* NOTE : store current point to overcome some bad operation
5581 *(returning zero when getting current position in paused state) of some
5584 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5585 LOGW("getting current position failed in paused");
5587 player->last_position = pos_nsec;
5589 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5590 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5591 This causes problem is position calculation during normal pause resume scenarios also.
5592 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5593 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5594 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5595 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5601 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5602 LOGD("doing async pause in case of ms buff src");
5606 /* pause pipeline */
5607 ret = _mmplayer_gst_pause(player, async);
5609 if (ret != MM_ERROR_NONE)
5610 LOGE("failed to pause player. ret : 0x%x", ret);
5612 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5613 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5614 LOGE("failed to update display_rotation");
5622 /* in case of streaming, pause could take long time.*/
5624 _mmplayer_abort_pause(MMHandleType hplayer)
5626 mmplayer_t *player = (mmplayer_t *)hplayer;
5627 int ret = MM_ERROR_NONE;
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5633 player->pipeline->mainbin,
5634 MM_ERROR_PLAYER_NOT_INITIALIZED);
5636 LOGD("set the pipeline state to READY");
5638 /* set state to READY */
5639 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5640 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5641 if (ret != MM_ERROR_NONE) {
5642 LOGE("fail to change state to READY");
5643 return MM_ERROR_PLAYER_INTERNAL;
5646 LOGD("succeeded in changing state to READY");
5651 _mmplayer_resume(MMHandleType hplayer)
5653 mmplayer_t *player = (mmplayer_t *)hplayer;
5654 int ret = MM_ERROR_NONE;
5655 gboolean async = FALSE;
5659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5661 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5662 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5663 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5667 /* Changing back sync mode rtspsrc to async */
5668 LOGD("async resume for rtsp case");
5672 /* check current state */
5673 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5675 ret = _mmplayer_gst_resume(player, async);
5676 if (ret != MM_ERROR_NONE)
5677 LOGE("failed to resume player.");
5679 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5680 LOGD("force resume even during buffering");
5681 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5690 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5692 mmplayer_t *player = (mmplayer_t *)hplayer;
5693 gint64 pos_nsec = 0;
5694 int ret = MM_ERROR_NONE;
5696 signed long long start = 0, stop = 0;
5697 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5700 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5701 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5703 /* The sound of video is not supported under 0.0 and over 2.0. */
5704 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5705 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5708 _mmplayer_set_mute(hplayer, mute);
5710 if (player->playback_rate == rate)
5711 return MM_ERROR_NONE;
5713 /* If the position is reached at start potion during fast backward, EOS is posted.
5714 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5716 player->playback_rate = rate;
5718 current_state = MMPLAYER_CURRENT_STATE(player);
5720 if (current_state != MM_PLAYER_STATE_PAUSED)
5721 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5723 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5725 if ((current_state == MM_PLAYER_STATE_PAUSED)
5726 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5727 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5728 pos_nsec = player->last_position;
5733 stop = GST_CLOCK_TIME_NONE;
5735 start = GST_CLOCK_TIME_NONE;
5739 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5740 player->playback_rate,
5742 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5743 GST_SEEK_TYPE_SET, start,
5744 GST_SEEK_TYPE_SET, stop)) {
5745 LOGE("failed to set speed playback");
5746 return MM_ERROR_PLAYER_SEEK;
5749 LOGD("succeeded to set speed playback as %0.1f", rate);
5753 return MM_ERROR_NONE;;
5757 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5759 mmplayer_t *player = (mmplayer_t *)hplayer;
5760 int ret = MM_ERROR_NONE;
5764 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5766 /* check pipline building state */
5767 __mmplayer_check_pipeline(player);
5769 ret = _mmplayer_gst_set_position(player, position, FALSE);
5777 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5779 mmplayer_t *player = (mmplayer_t *)hplayer;
5780 int ret = MM_ERROR_NONE;
5782 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5783 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5785 if (g_strrstr(player->type, "video/mpegts"))
5786 __mmplayer_update_duration_value(player);
5788 *duration = player->duration;
5793 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5795 mmplayer_t *player = (mmplayer_t *)hplayer;
5796 int ret = MM_ERROR_NONE;
5798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5800 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5806 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5808 mmplayer_t *player = (mmplayer_t *)hplayer;
5809 int ret = MM_ERROR_NONE;
5813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5815 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5823 __mmplayer_is_midi_type(gchar *str_caps)
5825 if ((g_strrstr(str_caps, "audio/midi")) ||
5826 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5827 (g_strrstr(str_caps, "application/x-smaf")) ||
5828 (g_strrstr(str_caps, "audio/x-imelody")) ||
5829 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5830 (g_strrstr(str_caps, "audio/xmf")) ||
5831 (g_strrstr(str_caps, "audio/mxmf"))) {
5840 __mmplayer_is_only_mp3_type(gchar *str_caps)
5842 if (g_strrstr(str_caps, "application/x-id3") ||
5843 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5849 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5851 GstStructure *caps_structure = NULL;
5852 gint samplerate = 0;
5856 MMPLAYER_RETURN_IF_FAIL(player && caps);
5858 caps_structure = gst_caps_get_structure(caps, 0);
5860 /* set stream information */
5861 gst_structure_get_int(caps_structure, "rate", &samplerate);
5862 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5864 gst_structure_get_int(caps_structure, "channels", &channels);
5865 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5867 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5871 __mmplayer_update_content_type_info(mmplayer_t *player)
5874 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5876 if (__mmplayer_is_midi_type(player->type)) {
5877 player->bypass_audio_effect = TRUE;
5881 if (!player->streamer) {
5882 LOGD("no need to check streaming type");
5886 if (g_strrstr(player->type, "application/x-hls")) {
5887 /* If it can't know exact type when it parses uri because of redirection case,
5888 * it will be fixed by typefinder or when doing autoplugging.
5890 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5891 player->streamer->is_adaptive_streaming = TRUE;
5892 } else if (g_strrstr(player->type, "application/dash+xml")) {
5893 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5894 player->streamer->is_adaptive_streaming = TRUE;
5897 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5898 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5899 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5901 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5902 if (player->streamer->is_adaptive_streaming)
5903 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5905 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5909 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5914 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5915 GstCaps *caps, gpointer data)
5917 mmplayer_t *player = (mmplayer_t *)data;
5922 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5924 /* store type string */
5925 MMPLAYER_FREEIF(player->type);
5926 player->type = gst_caps_to_string(caps);
5928 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5929 player, player->type, probability, gst_caps_get_size(caps));
5931 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5932 (g_strrstr(player->type, "audio/x-raw-int"))) {
5933 LOGE("not support media format");
5935 if (player->msg_posted == FALSE) {
5936 MMMessageParamType msg_param;
5937 memset(&msg_param, 0, sizeof(MMMessageParamType));
5939 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5940 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5942 /* don't post more if one was sent already */
5943 player->msg_posted = TRUE;
5948 __mmplayer_update_content_type_info(player);
5950 pad = gst_element_get_static_pad(tf, "src");
5952 LOGE("fail to get typefind src pad.");
5956 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5957 gboolean async = FALSE;
5958 LOGE("failed to autoplug %s", player->type);
5960 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5962 if (async && player->msg_posted == FALSE)
5963 __mmplayer_handle_missed_plugin(player);
5967 gst_object_unref(GST_OBJECT(pad));
5975 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5977 GstElement *decodebin = NULL;
5981 /* create decodebin */
5982 decodebin = gst_element_factory_make("decodebin", NULL);
5985 LOGE("fail to create decodebin");
5989 /* raw pad handling signal */
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5991 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5993 /* no-more-pad pad handling signal */
5994 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5995 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5997 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5998 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6000 /* This signal is emitted when a pad for which there is no further possible
6001 decoding is added to the decodebin.*/
6002 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6003 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6005 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6006 before looking for any elements that can handle that stream.*/
6007 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6008 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6010 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6011 before looking for any elements that can handle that stream.*/
6012 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6013 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6015 /* This signal is emitted once decodebin has finished decoding all the data.*/
6016 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6017 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6019 /* This signal is emitted when a element is added to the bin.*/
6020 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6021 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6028 __mmplayer_gst_make_queue2(mmplayer_t *player)
6030 GstElement *queue2 = NULL;
6031 gint64 dur_bytes = 0L;
6032 mmplayer_gst_element_t *mainbin = NULL;
6033 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6036 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6038 mainbin = player->pipeline->mainbin;
6040 queue2 = gst_element_factory_make("queue2", "queue2");
6042 LOGE("failed to create buffering queue element");
6046 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6047 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6049 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6051 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6052 * skip the pull mode(file or ring buffering) setting. */
6053 if (dur_bytes > 0) {
6054 if (!g_strrstr(player->type, "video/mpegts")) {
6055 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6056 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6062 _mm_player_streaming_set_queue2(player->streamer,
6066 (guint64)dur_bytes); /* no meaning at the moment */
6072 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6074 mmplayer_gst_element_t *mainbin = NULL;
6075 GstElement *decodebin = NULL;
6076 GstElement *queue2 = NULL;
6077 GstPad *sinkpad = NULL;
6078 GstPad *qsrcpad = NULL;
6081 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6083 mainbin = player->pipeline->mainbin;
6085 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6087 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6088 LOGW("need to check: muxed buffer is not null");
6091 queue2 = __mmplayer_gst_make_queue2(player);
6093 LOGE("failed to make queue2");
6097 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6098 LOGE("failed to add buffering queue");
6102 sinkpad = gst_element_get_static_pad(queue2, "sink");
6103 qsrcpad = gst_element_get_static_pad(queue2, "src");
6105 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6106 LOGE("failed to link [%s:%s]-[%s:%s]",
6107 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6111 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6112 LOGE("failed to sync queue2 state with parent");
6116 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6117 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6121 gst_object_unref(GST_OBJECT(sinkpad));
6125 /* create decodebin */
6126 decodebin = _mmplayer_gst_make_decodebin(player);
6128 LOGE("failed to make decodebin");
6132 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6133 LOGE("failed to add decodebin");
6137 /* to force caps on the decodebin element and avoid reparsing stuff by
6138 * typefind. It also avoids a deadlock in the way typefind activates pads in
6139 * the state change */
6140 g_object_set(decodebin, "sink-caps", caps, NULL);
6142 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6144 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6145 LOGE("failed to link [%s:%s]-[%s:%s]",
6146 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6150 gst_object_unref(GST_OBJECT(sinkpad));
6152 gst_object_unref(GST_OBJECT(qsrcpad));
6155 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6156 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6158 /* set decodebin property about buffer in streaming playback. *
6159 * in case of HLS/DASH, it does not need to have big buffer *
6160 * because it is kind of adaptive streaming. */
6161 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6162 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6163 gint high_percent = 0;
6165 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6166 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6168 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6170 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6172 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6173 "high-percent", high_percent,
6174 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6175 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6176 "max-size-buffers", 0, NULL); // disable or automatic
6179 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6180 LOGE("failed to sync decodebin state with parent");
6191 gst_object_unref(GST_OBJECT(sinkpad));
6194 gst_object_unref(GST_OBJECT(qsrcpad));
6197 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6198 * You need to explicitly set elements to the NULL state before
6199 * dropping the final reference, to allow them to clean up.
6201 gst_element_set_state(queue2, GST_STATE_NULL);
6203 /* And, it still has a parent "player".
6204 * You need to let the parent manage the object instead of unreffing the object directly.
6206 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6207 gst_object_unref(queue2);
6212 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6213 * You need to explicitly set elements to the NULL state before
6214 * dropping the final reference, to allow them to clean up.
6216 gst_element_set_state(decodebin, GST_STATE_NULL);
6218 /* And, it still has a parent "player".
6219 * You need to let the parent manage the object instead of unreffing the object directly.
6222 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6223 gst_object_unref(decodebin);
6231 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6235 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6236 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6238 LOGD("class : %s, mime : %s", factory_class, mime);
6240 /* add missing plugin */
6241 /* NOTE : msl should check missing plugin for image mime type.
6242 * Some motion jpeg clips can have playable audio track.
6243 * So, msl have to play audio after displaying popup written video format not supported.
6245 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6246 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6247 LOGD("not found demuxer");
6248 player->not_found_demuxer = TRUE;
6249 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6255 if (!g_strrstr(factory_class, "Demuxer")) {
6256 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6257 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6258 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6260 /* check that clip have multi tracks or not */
6261 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6262 LOGD("video plugin is already linked");
6264 LOGW("add VIDEO to missing plugin");
6265 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6266 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6268 } else if (g_str_has_prefix(mime, "audio")) {
6269 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6270 LOGD("audio plugin is already linked");
6272 LOGW("add AUDIO to missing plugin");
6273 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6274 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6282 return MM_ERROR_NONE;
6286 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6288 mmplayer_t *player = (mmplayer_t *)data;
6292 MMPLAYER_RETURN_IF_FAIL(player);
6294 /* remove fakesink. */
6295 if (!_mmplayer_gst_remove_fakesink(player,
6296 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6297 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6298 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6299 * source element are not same. To overcome this situation, this function will called
6300 * several places and several times. Therefore, this is not an error case.
6305 LOGD("[handle: %p] pipeline has completely constructed", player);
6307 if ((player->ini.async_start) &&
6308 (player->msg_posted == FALSE) &&
6309 (player->cmd >= MMPLAYER_COMMAND_START))
6310 __mmplayer_handle_missed_plugin(player);
6312 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6316 __mmplayer_check_profile(void)
6319 static int profile_tv = -1;
6321 if (__builtin_expect(profile_tv != -1, 1))
6324 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6325 switch (*profileName) {
6340 __mmplayer_get_next_uri(mmplayer_t *player)
6342 mmplayer_parse_profile_t profile;
6344 guint num_of_list = 0;
6347 num_of_list = g_list_length(player->uri_info.uri_list);
6348 uri_idx = player->uri_info.uri_idx;
6350 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6351 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6352 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6354 LOGW("next uri does not exist");
6358 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6359 LOGE("failed to parse profile");
6363 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6364 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6365 LOGW("uri type is not supported(%d)", profile.uri_type);
6369 LOGD("success to find next uri %d", uri_idx);
6373 if (uri_idx == num_of_list) {
6374 LOGE("failed to find next uri");
6378 player->uri_info.uri_idx = uri_idx;
6379 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6381 if (mm_attrs_commit_all(player->attrs)) {
6382 LOGE("failed to commit");
6386 SECURE_LOGD("next playback uri: %s", uri);
6391 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6393 #define REPEAT_COUNT_INFINITE -1
6394 #define REPEAT_COUNT_MIN 2
6395 #define ORIGINAL_URI_ONLY 1
6397 MMHandleType attrs = 0;
6401 guint num_of_uri = 0;
6402 int profile_tv = -1;
6406 LOGD("checking for gapless play option");
6408 if (player->pipeline->textbin) {
6409 LOGE("subtitle path is enabled. gapless play is not supported.");
6413 attrs = MMPLAYER_GET_ATTRS(player);
6415 LOGE("fail to get attributes.");
6419 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6421 /* gapless playback is not supported in case of video at TV profile. */
6422 profile_tv = __mmplayer_check_profile();
6423 if (profile_tv && video) {
6424 LOGW("not support video gapless playback");
6428 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6429 LOGE("failed to get play count");
6431 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6432 LOGE("failed to get gapless mode");
6434 /* check repeat count in case of audio */
6436 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6437 LOGW("gapless is disabled");
6441 num_of_uri = g_list_length(player->uri_info.uri_list);
6443 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6445 if (num_of_uri == ORIGINAL_URI_ONLY) {
6446 /* audio looping path */
6447 if (count >= REPEAT_COUNT_MIN) {
6448 /* decrease play count */
6449 /* we succeeded to rewind. update play count and then wait for next EOS */
6451 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6452 /* commit attribute */
6453 if (mm_attrs_commit_all(attrs))
6454 LOGE("failed to commit attribute");
6456 } else if (count != REPEAT_COUNT_INFINITE) {
6457 LOGD("there is no next uri and no repeat");
6460 LOGD("looping cnt %d", count);
6462 /* gapless playback path */
6463 if (!__mmplayer_get_next_uri(player)) {
6464 LOGE("failed to get next uri");
6471 LOGE("unable to play gapless path. EOS will be posted soon");
6476 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6478 mmplayer_selector_t *selector = &player->selector[type];
6479 mmplayer_gst_element_t *sinkbin = NULL;
6480 main_element_id_e selectorId = MMPLAYER_M_NUM;
6481 main_element_id_e sinkId = MMPLAYER_M_NUM;
6482 GstPad *srcpad = NULL;
6483 GstPad *sinkpad = NULL;
6484 gboolean send_notice = FALSE;
6487 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6489 LOGD("type %d", type);
6492 case MM_PLAYER_TRACK_TYPE_AUDIO:
6493 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6494 sinkId = MMPLAYER_A_BIN;
6495 sinkbin = player->pipeline->audiobin;
6497 case MM_PLAYER_TRACK_TYPE_VIDEO:
6498 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6499 sinkId = MMPLAYER_V_BIN;
6500 sinkbin = player->pipeline->videobin;
6503 case MM_PLAYER_TRACK_TYPE_TEXT:
6504 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6505 sinkId = MMPLAYER_T_BIN;
6506 sinkbin = player->pipeline->textbin;
6509 LOGE("requested type is not supportable");
6514 if (player->pipeline->mainbin[selectorId].gst) {
6517 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6519 if (selector->event_probe_id != 0)
6520 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6521 selector->event_probe_id = 0;
6523 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6524 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6526 if (srcpad && sinkpad) {
6527 /* after getting drained signal there is no data flows, so no need to do pad_block */
6528 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6529 gst_pad_unlink(srcpad, sinkpad);
6531 /* send custom event to sink pad to handle it at video sink */
6533 LOGD("send custom event to sinkpad");
6534 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6535 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6536 gst_pad_send_event(sinkpad, event);
6540 gst_object_unref(sinkpad);
6543 gst_object_unref(srcpad);
6546 LOGD("selector release");
6548 /* release and unref requests pad from the selector */
6549 for (n = 0; n < selector->channels->len; n++) {
6550 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6551 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6553 g_ptr_array_set_size(selector->channels, 0);
6555 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6556 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6558 player->pipeline->mainbin[selectorId].gst = NULL;
6566 __mmplayer_deactivate_old_path(mmplayer_t *player)
6569 MMPLAYER_RETURN_IF_FAIL(player);
6571 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6572 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6573 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6574 LOGE("deactivate selector error");
6578 _mmplayer_track_destroy(player);
6579 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6581 if (player->streamer) {
6582 _mm_player_streaming_initialize(player->streamer, FALSE);
6583 _mm_player_streaming_destroy(player->streamer);
6584 player->streamer = NULL;
6587 MMPLAYER_PLAYBACK_LOCK(player);
6588 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6595 if (!player->msg_posted) {
6596 MMMessageParamType msg = {0,};
6599 msg.code = MM_ERROR_PLAYER_INTERNAL;
6600 LOGE("gapless_uri_play> deactivate error");
6602 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6603 player->msg_posted = TRUE;
6609 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6611 int result = MM_ERROR_NONE;
6612 mmplayer_t *player = (mmplayer_t *)hplayer;
6615 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6617 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6618 if (mm_attrs_commit_all(player->attrs)) {
6619 LOGE("failed to commit the original uri.");
6620 result = MM_ERROR_PLAYER_INTERNAL;
6622 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6623 LOGE("failed to add the original uri in the uri list.");
6631 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6633 mmplayer_t *player = (mmplayer_t *)hplayer;
6634 guint num_of_list = 0;
6638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6639 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6641 if (player->pipeline && player->pipeline->textbin) {
6642 LOGE("subtitle path is enabled.");
6643 return MM_ERROR_PLAYER_INVALID_STATE;
6646 num_of_list = g_list_length(player->uri_info.uri_list);
6648 if (is_first_path) {
6649 if (num_of_list == 0) {
6650 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6651 SECURE_LOGD("add original path : %s", uri);
6653 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6654 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6656 SECURE_LOGD("change original path : %s", uri);
6659 MMHandleType attrs = 0;
6660 attrs = MMPLAYER_GET_ATTRS(player);
6662 if (num_of_list == 0) {
6663 char *original_uri = NULL;
6666 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6668 if (!original_uri) {
6669 LOGE("there is no original uri.");
6670 return MM_ERROR_PLAYER_INVALID_STATE;
6673 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6674 player->uri_info.uri_idx = 0;
6676 SECURE_LOGD("add original path at first : %s", original_uri);
6680 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6681 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6685 return MM_ERROR_NONE;
6689 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6691 mmplayer_t *player = (mmplayer_t *)hplayer;
6692 char *next_uri = NULL;
6693 guint num_of_list = 0;
6696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6698 num_of_list = g_list_length(player->uri_info.uri_list);
6700 if (num_of_list > 0) {
6701 gint uri_idx = player->uri_info.uri_idx;
6703 if (uri_idx < num_of_list-1)
6708 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6709 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6711 *uri = g_strdup(next_uri);
6715 return MM_ERROR_NONE;
6719 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6720 GstCaps *caps, gpointer data)
6722 mmplayer_t *player = (mmplayer_t *)data;
6723 const gchar *klass = NULL;
6724 const gchar *mime = NULL;
6725 gchar *caps_str = NULL;
6727 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6728 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6729 caps_str = gst_caps_to_string(caps);
6731 LOGW("unknown type of caps : %s from %s",
6732 caps_str, GST_ELEMENT_NAME(elem));
6734 MMPLAYER_FREEIF(caps_str);
6736 /* There is no available codec. */
6737 __mmplayer_check_not_supported_codec(player, klass, mime);
6741 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6742 GstCaps *caps, gpointer data)
6744 mmplayer_t *player = (mmplayer_t *)data;
6745 const char *mime = NULL;
6746 gboolean ret = TRUE;
6748 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6749 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6751 if (g_str_has_prefix(mime, "audio")) {
6752 GstStructure *caps_structure = NULL;
6753 gint samplerate = 0;
6755 gchar *caps_str = NULL;
6757 caps_structure = gst_caps_get_structure(caps, 0);
6758 gst_structure_get_int(caps_structure, "rate", &samplerate);
6759 gst_structure_get_int(caps_structure, "channels", &channels);
6761 if ((channels > 0 && samplerate == 0)) {
6762 LOGD("exclude audio...");
6766 caps_str = gst_caps_to_string(caps);
6767 /* set it directly because not sent by TAG */
6768 if (g_strrstr(caps_str, "mobile-xmf"))
6769 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6770 MMPLAYER_FREEIF(caps_str);
6771 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6772 MMMessageParamType msg_param;
6773 memset(&msg_param, 0, sizeof(MMMessageParamType));
6774 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6775 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6776 LOGD("video file is not supported on this device");
6778 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6779 LOGD("already video linked");
6782 LOGD("found new stream");
6789 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6791 gboolean ret = TRUE;
6792 GDBusConnection *conn = NULL;
6794 GVariant *result = NULL;
6795 const gchar *dbus_device_type = NULL;
6796 const gchar *dbus_ret = NULL;
6799 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6801 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6807 result = g_dbus_connection_call_sync(conn,
6808 "org.pulseaudio.Server",
6809 "/org/pulseaudio/StreamManager",
6810 "org.pulseaudio.StreamManager",
6811 "GetCurrentMediaRoutingPath",
6812 g_variant_new("(s)", "out"),
6813 G_VARIANT_TYPE("(ss)"),
6814 G_DBUS_CALL_FLAGS_NONE,
6818 if (!result || err) {
6819 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6825 /* device type is listed in stream-map.json at mmfw-sysconf */
6826 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6828 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6829 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6834 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6835 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6836 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6837 LOGD("audio offload is supportable");
6843 LOGD("audio offload is not supportable");
6847 g_variant_unref(result);
6848 g_object_unref(conn);
6853 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6855 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6856 gint64 position = 0;
6858 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6859 player->pipeline && player->pipeline->mainbin);
6861 MMPLAYER_CMD_LOCK(player);
6862 current_state = MMPLAYER_CURRENT_STATE(player);
6864 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6865 LOGW("getting current position failed in paused");
6867 _mmplayer_unrealize((MMHandleType)player);
6868 _mmplayer_realize((MMHandleType)player);
6870 _mmplayer_set_position((MMHandleType)player, position);
6872 /* async not to be blocked in streaming case */
6873 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6874 if (mm_attrs_commit_all(player->attrs))
6875 LOGE("failed to commit");
6877 _mmplayer_pause((MMHandleType)player);
6879 if (current_state == MM_PLAYER_STATE_PLAYING)
6880 _mmplayer_start((MMHandleType)player);
6881 MMPLAYER_CMD_UNLOCK(player);
6883 LOGD("rebuilding audio pipeline is completed.");
6886 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6888 mmplayer_t *player = (mmplayer_t *)user_data;
6889 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6890 gboolean is_supportable = FALSE;
6892 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6893 LOGW("failed to get device type");
6895 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6897 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6898 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6899 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6900 LOGD("ignore this dev connected info");
6904 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6905 if (player->build_audio_offload == is_supportable) {
6906 LOGD("keep current pipeline without re-building");
6910 /* rebuild pipeline */
6911 LOGD("re-build pipeline - offload: %d", is_supportable);
6912 player->build_audio_offload = FALSE;
6913 __mmplayer_rebuild_audio_pipeline(player);
6919 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6921 unsigned int id = 0;
6923 if (player->audio_device_cb_id != 0) {
6924 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6928 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6929 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6930 LOGD("added device connected cb (%u)", id);
6931 player->audio_device_cb_id = id;
6933 LOGW("failed to add device connected cb");
6941 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6943 gboolean ret = FALSE;
6944 GstElementFactory *factory = NULL;
6947 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6949 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6950 if (!__mmplayer_is_only_mp3_type(player->type))
6953 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6954 LOGD("there is no audio offload sink");
6958 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6959 LOGW("there is no audio device type to support offload");
6963 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6965 LOGW("there is no installed audio offload sink element");
6968 gst_object_unref(factory);
6970 if (!__mmplayer_add_audio_device_connected_cb(player))
6973 if (!__mmplayer_is_audio_offload_device_type(player))
6976 LOGD("audio offload can be built");
6984 static GstAutoplugSelectResult
6985 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6987 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6989 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6990 int audio_offload = 0;
6992 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6993 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6995 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6996 LOGD("expose audio path to build offload output path");
6997 player->build_audio_offload = TRUE;
6998 /* update codec info */
6999 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7000 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7001 player->audiodec_linked = 1;
7003 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7007 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7009 LOGD("audio codec type: %d", codec_type);
7010 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7011 /* sw codec will be skipped */
7012 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7013 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7014 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7015 ret = GST_AUTOPLUG_SELECT_SKIP;
7019 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7020 /* hw codec will be skipped */
7021 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7022 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7023 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7024 ret = GST_AUTOPLUG_SELECT_SKIP;
7029 /* set stream information */
7030 if (!player->audiodec_linked)
7031 __mmplayer_set_audio_attrs(player, caps);
7033 /* update codec info */
7034 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7035 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7036 player->audiodec_linked = 1;
7038 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7040 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7042 LOGD("video codec type: %d", codec_type);
7043 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7044 /* sw codec is skipped */
7045 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7046 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7047 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7048 ret = GST_AUTOPLUG_SELECT_SKIP;
7052 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7053 /* hw codec is skipped */
7054 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7055 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7056 ret = GST_AUTOPLUG_SELECT_SKIP;
7061 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7062 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7064 /* mark video decoder for acquire */
7065 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7066 LOGW("video decoder resource is already acquired, skip it.");
7067 ret = GST_AUTOPLUG_SELECT_SKIP;
7071 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7072 LOGE("failed to acquire video decoder resource");
7073 ret = GST_AUTOPLUG_SELECT_SKIP;
7076 player->interrupted_by_resource = FALSE;
7079 /* update codec info */
7080 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7081 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7082 player->videodec_linked = 1;
7090 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7091 GstCaps *caps, GstElementFactory *factory, gpointer data)
7093 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7094 mmplayer_t *player = (mmplayer_t *)data;
7096 gchar *factory_name = NULL;
7097 gchar *caps_str = NULL;
7098 const gchar *klass = NULL;
7101 factory_name = GST_OBJECT_NAME(factory);
7102 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7103 caps_str = gst_caps_to_string(caps);
7105 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7107 /* store type string */
7108 if (player->type == NULL) {
7109 player->type = gst_caps_to_string(caps);
7110 __mmplayer_update_content_type_info(player);
7113 /* filtering exclude keyword */
7114 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7115 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7116 LOGW("skipping [%s] by exculde keyword [%s]",
7117 factory_name, player->ini.exclude_element_keyword[idx]);
7119 result = GST_AUTOPLUG_SELECT_SKIP;
7124 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7125 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7126 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7127 factory_name, player->ini.unsupported_codec_keyword[idx]);
7128 result = GST_AUTOPLUG_SELECT_SKIP;
7133 /* exclude webm format */
7134 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7135 * because webm format is not supportable.
7136 * If webm is disabled in "autoplug-continue", there is no state change
7137 * failure or error because the decodebin will expose the pad directly.
7138 * It make MSL invoke _prepare_async_callback.
7139 * So, we need to disable webm format in "autoplug-select" */
7140 if (caps_str && strstr(caps_str, "webm")) {
7141 LOGW("webm is not supported");
7142 result = GST_AUTOPLUG_SELECT_SKIP;
7146 /* check factory class for filtering */
7147 /* NOTE : msl don't need to use image plugins.
7148 * So, those plugins should be skipped for error handling.
7150 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7151 LOGD("skipping [%s] by not required", factory_name);
7152 result = GST_AUTOPLUG_SELECT_SKIP;
7156 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7157 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7158 // TO CHECK : subtitle if needed, add subparse exception.
7159 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7160 result = GST_AUTOPLUG_SELECT_SKIP;
7164 if (g_strrstr(factory_name, "mpegpsdemux")) {
7165 LOGD("skipping PS container - not support");
7166 result = GST_AUTOPLUG_SELECT_SKIP;
7170 if (g_strrstr(factory_name, "mssdemux"))
7171 player->smooth_streaming = TRUE;
7173 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7174 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7177 GstStructure *str = NULL;
7178 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7180 /* don't make video because of not required */
7181 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7182 (!player->set_mode.video_export)) {
7183 LOGD("no need video decoding, expose pad");
7184 result = GST_AUTOPLUG_SELECT_EXPOSE;
7188 /* get w/h for omx state-tune */
7189 /* FIXME: deprecated? */
7190 str = gst_caps_get_structure(caps, 0);
7191 gst_structure_get_int(str, "width", &width);
7194 if (player->v_stream_caps) {
7195 gst_caps_unref(player->v_stream_caps);
7196 player->v_stream_caps = NULL;
7199 player->v_stream_caps = gst_caps_copy(caps);
7200 LOGD("take caps for video state tune");
7201 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7205 if (g_strrstr(klass, "Codec/Decoder")) {
7206 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7207 if (result != GST_AUTOPLUG_SELECT_TRY) {
7208 LOGW("skip add decoder");
7214 MMPLAYER_FREEIF(caps_str);
7220 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7223 //mmplayer_t *player = (mmplayer_t *)data;
7224 GstCaps *caps = NULL;
7226 LOGD("[Decodebin2] pad-removed signal");
7228 caps = gst_pad_query_caps(new_pad, NULL);
7230 LOGW("query caps is NULL");
7234 gchar *caps_str = NULL;
7235 caps_str = gst_caps_to_string(caps);
7237 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7239 MMPLAYER_FREEIF(caps_str);
7240 gst_caps_unref(caps);
7244 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7246 mmplayer_t *player = (mmplayer_t *)data;
7247 GstIterator *iter = NULL;
7248 GValue item = { 0, };
7250 gboolean done = FALSE;
7251 gboolean is_all_drained = TRUE;
7254 MMPLAYER_RETURN_IF_FAIL(player);
7256 LOGD("__mmplayer_gst_decode_drained");
7258 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7259 LOGW("Fail to get cmd lock");
7263 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7264 !__mmplayer_verify_gapless_play_path(player)) {
7265 LOGD("decoding is finished.");
7266 __mmplayer_reset_gapless_state(player);
7267 MMPLAYER_CMD_UNLOCK(player);
7271 player->gapless.reconfigure = TRUE;
7273 /* check decodebin src pads whether they received EOS or not */
7274 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7277 switch (gst_iterator_next(iter, &item)) {
7278 case GST_ITERATOR_OK:
7279 pad = g_value_get_object(&item);
7280 if (pad && !GST_PAD_IS_EOS(pad)) {
7281 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7282 is_all_drained = FALSE;
7285 g_value_reset(&item);
7287 case GST_ITERATOR_RESYNC:
7288 gst_iterator_resync(iter);
7290 case GST_ITERATOR_ERROR:
7291 case GST_ITERATOR_DONE:
7296 g_value_unset(&item);
7297 gst_iterator_free(iter);
7299 if (!is_all_drained) {
7300 LOGD("Wait util the all pads get EOS.");
7301 MMPLAYER_CMD_UNLOCK(player);
7306 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7307 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7309 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7310 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7311 __mmplayer_deactivate_old_path(player);
7312 MMPLAYER_CMD_UNLOCK(player);
7318 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7320 mmplayer_t *player = (mmplayer_t *)data;
7321 const gchar *klass = NULL;
7322 gchar *factory_name = NULL;
7324 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7325 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7327 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7329 if (__mmplayer_add_dump_buffer_probe(player, element))
7330 LOGD("add buffer probe");
7332 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7333 gchar *selected = NULL;
7334 selected = g_strdup(GST_ELEMENT_NAME(element));
7335 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7338 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7339 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7340 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7342 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7343 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7345 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7346 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7347 "max-video-width", player->adaptive_info.limit.width,
7348 "max-video-height", player->adaptive_info.limit.height, NULL);
7350 } else if (g_strrstr(klass, "Demuxer")) {
7351 //LOGD("plugged element is demuxer. take it");
7352 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7353 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7356 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7357 int surface_type = 0;
7359 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7362 // to support trust-zone only
7363 if (g_strrstr(factory_name, "asfdemux")) {
7364 LOGD("set file-location %s", player->profile.uri);
7365 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7366 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7367 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7368 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7369 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7370 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7371 (__mmplayer_is_only_mp3_type(player->type))) {
7372 LOGD("[mpegaudioparse] set streaming pull mode.");
7373 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7375 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7376 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7379 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7380 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7381 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7383 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7384 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7386 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7387 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7388 (MMPLAYER_IS_DASH_STREAMING(player))) {
7389 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7390 _mm_player_streaming_set_multiqueue(player->streamer, element);
7391 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7400 __mmplayer_release_misc(mmplayer_t *player)
7403 bool cur_mode = player->set_mode.rich_audio;
7406 MMPLAYER_RETURN_IF_FAIL(player);
7408 player->video_decoded_cb = NULL;
7409 player->video_decoded_cb_user_param = NULL;
7410 player->video_stream_prerolled = false;
7412 player->audio_decoded_cb = NULL;
7413 player->audio_decoded_cb_user_param = NULL;
7414 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7416 player->audio_stream_changed_cb = NULL;
7417 player->audio_stream_changed_cb_user_param = NULL;
7419 player->sent_bos = FALSE;
7420 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7422 player->seek_state = MMPLAYER_SEEK_NONE;
7424 player->total_bitrate = 0;
7425 player->total_maximum_bitrate = 0;
7427 player->not_found_demuxer = 0;
7429 player->last_position = 0;
7430 player->duration = 0;
7431 player->http_content_size = 0;
7432 player->not_supported_codec = MISSING_PLUGIN_NONE;
7433 player->can_support_codec = FOUND_PLUGIN_NONE;
7434 player->pending_seek.is_pending = false;
7435 player->pending_seek.pos = 0;
7436 player->msg_posted = FALSE;
7437 player->has_many_types = FALSE;
7438 player->is_subtitle_force_drop = FALSE;
7439 player->play_subtitle = FALSE;
7440 player->adjust_subtitle_pos = 0;
7441 player->has_closed_caption = FALSE;
7442 player->set_mode.video_export = false;
7443 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7444 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7446 player->set_mode.rich_audio = cur_mode;
7448 if (player->audio_device_cb_id > 0 &&
7449 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7450 LOGW("failed to remove audio device_connected_callback");
7451 player->audio_device_cb_id = 0;
7453 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7454 player->bitrate[i] = 0;
7455 player->maximum_bitrate[i] = 0;
7458 /* free memory related to audio effect */
7459 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7461 if (player->adaptive_info.var_list) {
7462 g_list_free_full(player->adaptive_info.var_list, g_free);
7463 player->adaptive_info.var_list = NULL;
7466 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7467 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7468 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7470 /* Reset video360 settings to their defaults in case if the pipeline is to be
7473 player->video360_metadata.is_spherical = -1;
7474 player->is_openal_plugin_used = FALSE;
7476 player->is_content_spherical = FALSE;
7477 player->is_video360_enabled = TRUE;
7478 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7479 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7480 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7481 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7482 player->video360_zoom = 1.0f;
7483 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7484 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7486 player->sound.rg_enable = false;
7488 __mmplayer_initialize_video_roi(player);
7493 __mmplayer_release_misc_post(mmplayer_t *player)
7495 char *original_uri = NULL;
7498 /* player->pipeline is already released before. */
7500 MMPLAYER_RETURN_IF_FAIL(player);
7502 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7504 /* clean found audio decoders */
7505 if (player->audio_decoders) {
7506 GList *a_dec = player->audio_decoders;
7507 for (; a_dec; a_dec = g_list_next(a_dec)) {
7508 gchar *name = a_dec->data;
7509 MMPLAYER_FREEIF(name);
7511 g_list_free(player->audio_decoders);
7512 player->audio_decoders = NULL;
7515 /* clean the uri list except original uri */
7516 if (player->uri_info.uri_list) {
7517 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7519 if (player->attrs) {
7520 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7521 LOGD("restore original uri = %s", original_uri);
7523 if (mm_attrs_commit_all(player->attrs))
7524 LOGE("failed to commit the original uri.");
7527 GList *uri_list = player->uri_info.uri_list;
7528 for (; uri_list; uri_list = g_list_next(uri_list)) {
7529 gchar *uri = uri_list->data;
7530 MMPLAYER_FREEIF(uri);
7532 g_list_free(player->uri_info.uri_list);
7533 player->uri_info.uri_list = NULL;
7536 /* clear the audio stream buffer list */
7537 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7539 /* clear the video stream bo list */
7540 __mmplayer_video_stream_destroy_bo_list(player);
7541 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7543 if (player->profile.input_mem.buf) {
7544 free(player->profile.input_mem.buf);
7545 player->profile.input_mem.buf = NULL;
7547 player->profile.input_mem.len = 0;
7548 player->profile.input_mem.offset = 0;
7550 player->uri_info.uri_idx = 0;
7555 __mmplayer_check_subtitle(mmplayer_t *player)
7557 MMHandleType attrs = 0;
7558 char *subtitle_uri = NULL;
7562 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7564 /* get subtitle attribute */
7565 attrs = MMPLAYER_GET_ATTRS(player);
7569 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7570 if (!subtitle_uri || !strlen(subtitle_uri))
7573 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7574 player->is_external_subtitle_present = TRUE;
7582 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7584 MMPLAYER_RETURN_IF_FAIL(player);
7586 if (player->eos_timer) {
7587 LOGD("cancel eos timer");
7588 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7589 player->eos_timer = 0;
7596 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7600 MMPLAYER_RETURN_IF_FAIL(player);
7601 MMPLAYER_RETURN_IF_FAIL(sink);
7603 player->sink_elements = g_list_append(player->sink_elements, sink);
7609 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7613 MMPLAYER_RETURN_IF_FAIL(player);
7614 MMPLAYER_RETURN_IF_FAIL(sink);
7616 player->sink_elements = g_list_remove(player->sink_elements, sink);
7622 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7623 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7625 mmplayer_signal_item_t *item = NULL;
7628 MMPLAYER_RETURN_IF_FAIL(player);
7630 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7631 LOGE("invalid signal type [%d]", type);
7635 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7637 LOGE("cannot connect signal [%s]", signal);
7642 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7643 player->signals[type] = g_list_append(player->signals[type], item);
7649 /* NOTE : be careful with calling this api. please refer to below glib comment
7650 * glib comment : Note that there is a bug in GObject that makes this function much
7651 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7652 * will no longer be called, but, the signal handler is not currently disconnected.
7653 * If the instance is itself being freed at the same time than this doesn't matter,
7654 * since the signal will automatically be removed, but if instance persists,
7655 * then the signal handler will leak. You should not remove the signal yourself
7656 * because in a future versions of GObject, the handler will automatically be
7659 * It's possible to work around this problem in a way that will continue to work
7660 * with future versions of GObject by checking that the signal handler is still
7661 * connected before disconnected it:
7663 * if (g_signal_handler_is_connected(instance, id))
7664 * g_signal_handler_disconnect(instance, id);
7667 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7669 GList *sig_list = NULL;
7670 mmplayer_signal_item_t *item = NULL;
7674 MMPLAYER_RETURN_IF_FAIL(player);
7676 LOGD("release signals type : %d", type);
7678 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7679 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7680 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7681 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7682 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7683 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7687 sig_list = player->signals[type];
7689 for (; sig_list; sig_list = sig_list->next) {
7690 item = sig_list->data;
7692 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7693 if (g_signal_handler_is_connected(item->obj, item->sig))
7694 g_signal_handler_disconnect(item->obj, item->sig);
7697 MMPLAYER_FREEIF(item);
7700 g_list_free(player->signals[type]);
7701 player->signals[type] = NULL;
7709 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7711 mmplayer_t *player = 0;
7712 int prev_display_surface_type = 0;
7713 void *prev_display_overlay = NULL;
7717 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7718 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7720 player = MM_PLAYER_CAST(handle);
7722 /* check video sinkbin is created */
7723 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7724 LOGE("Videosink is already created");
7725 return MM_ERROR_NONE;
7728 LOGD("videosink element is not yet ready");
7730 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7731 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7733 return MM_ERROR_INVALID_ARGUMENT;
7736 /* load previous attributes */
7737 if (player->attrs) {
7738 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7739 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7740 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7741 if (prev_display_surface_type == surface_type) {
7742 LOGD("incoming display surface type is same as previous one, do nothing..");
7744 return MM_ERROR_NONE;
7747 LOGE("failed to load attributes");
7749 return MM_ERROR_PLAYER_INTERNAL;
7752 /* videobin is not created yet, so we just set attributes related to display surface */
7753 LOGD("store display attribute for given surface type(%d)", surface_type);
7754 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7755 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7756 if (mm_attrs_commit_all(player->attrs)) {
7757 LOGE("failed to commit attribute");
7759 return MM_ERROR_PLAYER_INTERNAL;
7763 return MM_ERROR_NONE;
7766 /* Note : if silent is true, then subtitle would not be displayed. :*/
7768 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7770 mmplayer_t *player = (mmplayer_t *)hplayer;
7774 /* check player handle */
7775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7777 player->set_mode.subtitle_off = silent;
7779 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7783 return MM_ERROR_NONE;
7787 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7789 mmplayer_gst_element_t *mainbin = NULL;
7790 mmplayer_gst_element_t *textbin = NULL;
7791 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7792 GstState current_state = GST_STATE_VOID_PENDING;
7793 GstState element_state = GST_STATE_VOID_PENDING;
7794 GstState element_pending_state = GST_STATE_VOID_PENDING;
7796 GstEvent *event = NULL;
7797 int result = MM_ERROR_NONE;
7799 GstClock *curr_clock = NULL;
7800 GstClockTime base_time, start_time, curr_time;
7805 /* check player handle */
7806 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7808 player->pipeline->mainbin &&
7809 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7811 mainbin = player->pipeline->mainbin;
7812 textbin = player->pipeline->textbin;
7814 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7816 // sync clock with current pipeline
7817 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7818 curr_time = gst_clock_get_time(curr_clock);
7820 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7821 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7823 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7824 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7826 if (current_state > GST_STATE_READY) {
7827 // sync state with current pipeline
7828 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7829 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7830 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7832 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7833 if (GST_STATE_CHANGE_FAILURE == ret) {
7834 LOGE("fail to state change.");
7835 result = MM_ERROR_PLAYER_INTERNAL;
7839 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7840 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7843 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7844 gst_object_unref(curr_clock);
7847 // seek to current position
7848 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7849 result = MM_ERROR_PLAYER_INVALID_STATE;
7850 LOGE("gst_element_query_position failed, invalid state");
7854 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7855 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);
7857 _mmplayer_gst_send_event_to_sink(player, event);
7859 result = MM_ERROR_PLAYER_INTERNAL;
7860 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7864 /* sync state with current pipeline */
7865 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7866 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7867 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7869 return MM_ERROR_NONE;
7872 /* release text pipeline resource */
7873 player->textsink_linked = 0;
7875 /* release signal */
7876 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7878 /* release textbin with it's childs */
7879 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7880 MMPLAYER_FREEIF(player->pipeline->textbin);
7881 player->pipeline->textbin = NULL;
7883 /* release subtitle elem */
7884 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7885 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7891 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7893 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7894 GstState current_state = GST_STATE_VOID_PENDING;
7896 MMHandleType attrs = 0;
7897 mmplayer_gst_element_t *mainbin = NULL;
7898 mmplayer_gst_element_t *textbin = NULL;
7900 gchar *subtitle_uri = NULL;
7901 int result = MM_ERROR_NONE;
7902 const gchar *charset = NULL;
7906 /* check player handle */
7907 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7909 player->pipeline->mainbin &&
7910 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7911 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7913 mainbin = player->pipeline->mainbin;
7914 textbin = player->pipeline->textbin;
7916 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7917 if (current_state < GST_STATE_READY) {
7918 result = MM_ERROR_PLAYER_INVALID_STATE;
7919 LOGE("Pipeline is not in proper state");
7923 attrs = MMPLAYER_GET_ATTRS(player);
7925 LOGE("cannot get content attribute");
7926 result = MM_ERROR_PLAYER_INTERNAL;
7930 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7931 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7932 LOGE("subtitle uri is not proper filepath");
7933 result = MM_ERROR_PLAYER_INVALID_URI;
7937 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7938 LOGE("failed to get storage info of subtitle path");
7939 result = MM_ERROR_PLAYER_INVALID_URI;
7943 LOGD("old subtitle file path is [%s]", subtitle_uri);
7944 LOGD("new subtitle file path is [%s]", filepath);
7946 if (!strcmp(filepath, subtitle_uri)) {
7947 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7950 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7951 if (mm_attrs_commit_all(player->attrs)) {
7952 LOGE("failed to commit.");
7957 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7958 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7959 player->subtitle_language_list = NULL;
7960 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7962 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7963 if (ret != GST_STATE_CHANGE_SUCCESS) {
7964 LOGE("failed to change state of textbin to READY");
7965 result = MM_ERROR_PLAYER_INTERNAL;
7969 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7970 if (ret != GST_STATE_CHANGE_SUCCESS) {
7971 LOGE("failed to change state of subparse to READY");
7972 result = MM_ERROR_PLAYER_INTERNAL;
7976 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7977 if (ret != GST_STATE_CHANGE_SUCCESS) {
7978 LOGE("failed to change state of filesrc to READY");
7979 result = MM_ERROR_PLAYER_INTERNAL;
7983 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7985 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7987 charset = _mmplayer_get_charset(filepath);
7989 LOGD("detected charset is %s", charset);
7990 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7993 result = _mmplayer_sync_subtitle_pipeline(player);
8000 /* API to switch between external subtitles */
8002 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8004 int result = MM_ERROR_NONE;
8005 mmplayer_t *player = (mmplayer_t *)hplayer;
8010 /* check player handle */
8011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8013 /* filepath can be null in idle state */
8015 /* check file path */
8016 if ((path = strstr(filepath, "file://")))
8017 result = _mmplayer_exist_file_path(path + 7);
8019 result = _mmplayer_exist_file_path(filepath);
8021 if (result != MM_ERROR_NONE) {
8022 LOGE("invalid subtitle path 0x%X", result);
8023 return result; /* file not found or permission denied */
8027 if (!player->pipeline) {
8029 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8030 if (mm_attrs_commit_all(player->attrs)) {
8031 LOGE("failed to commit"); /* subtitle path will not be created */
8032 return MM_ERROR_PLAYER_INTERNAL;
8035 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8036 /* check filepath */
8037 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8039 if (!__mmplayer_check_subtitle(player)) {
8040 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8041 if (mm_attrs_commit_all(player->attrs)) {
8042 LOGE("failed to commit");
8043 return MM_ERROR_PLAYER_INTERNAL;
8046 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8047 LOGE("fail to create text pipeline");
8048 return MM_ERROR_PLAYER_INTERNAL;
8051 result = _mmplayer_sync_subtitle_pipeline(player);
8053 result = __mmplayer_change_external_subtitle_language(player, filepath);
8056 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8057 player->is_external_subtitle_added_now = TRUE;
8059 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8060 if (!player->subtitle_language_list) {
8061 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8062 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8063 LOGW("subtitle language list is not updated yet");
8065 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8073 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8075 int result = MM_ERROR_NONE;
8076 gchar *change_pad_name = NULL;
8077 GstPad *sinkpad = NULL;
8078 mmplayer_gst_element_t *mainbin = NULL;
8079 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8080 GstCaps *caps = NULL;
8081 gint total_track_num = 0;
8085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8086 MM_ERROR_PLAYER_NOT_INITIALIZED);
8088 LOGD("Change Track(%d) to %d", type, index);
8090 mainbin = player->pipeline->mainbin;
8092 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8093 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8094 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8095 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8097 /* Changing Video Track is not supported. */
8098 LOGE("Track Type Error");
8102 if (mainbin[elem_idx].gst == NULL) {
8103 result = MM_ERROR_PLAYER_NO_OP;
8104 LOGD("Req track doesn't exist");
8108 total_track_num = player->selector[type].total_track_num;
8109 if (total_track_num <= 0) {
8110 result = MM_ERROR_PLAYER_NO_OP;
8111 LOGD("Language list is not available");
8115 if ((index < 0) || (index >= total_track_num)) {
8116 result = MM_ERROR_INVALID_ARGUMENT;
8117 LOGD("Not a proper index : %d", index);
8121 /*To get the new pad from the selector*/
8122 change_pad_name = g_strdup_printf("sink_%u", index);
8123 if (change_pad_name == NULL) {
8124 result = MM_ERROR_PLAYER_INTERNAL;
8125 LOGD("Pad does not exists");
8129 LOGD("new active pad name: %s", change_pad_name);
8131 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8132 if (sinkpad == NULL) {
8133 LOGD("sinkpad is NULL");
8134 result = MM_ERROR_PLAYER_INTERNAL;
8138 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8139 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8141 caps = gst_pad_get_current_caps(sinkpad);
8142 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8145 gst_object_unref(sinkpad);
8147 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8148 __mmplayer_set_audio_attrs(player, caps);
8151 MMPLAYER_FREEIF(change_pad_name);
8156 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8158 int result = MM_ERROR_NONE;
8159 mmplayer_t *player = NULL;
8160 mmplayer_gst_element_t *mainbin = NULL;
8162 gint current_active_index = 0;
8164 GstState current_state = GST_STATE_VOID_PENDING;
8165 GstEvent *event = NULL;
8170 player = (mmplayer_t *)hplayer;
8171 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8173 if (!player->pipeline) {
8174 LOGE("Track %d pre setting -> %d", type, index);
8176 player->selector[type].active_pad_index = index;
8180 mainbin = player->pipeline->mainbin;
8182 current_active_index = player->selector[type].active_pad_index;
8184 /*If index is same as running index no need to change the pad*/
8185 if (current_active_index == index)
8188 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8189 result = MM_ERROR_PLAYER_INVALID_STATE;
8193 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8194 if (current_state < GST_STATE_PAUSED) {
8195 result = MM_ERROR_PLAYER_INVALID_STATE;
8196 LOGW("Pipeline not in porper state");
8200 result = __mmplayer_change_selector_pad(player, type, index);
8201 if (result != MM_ERROR_NONE) {
8202 LOGE("change selector pad error");
8206 player->selector[type].active_pad_index = index;
8208 if (current_state == GST_STATE_PLAYING) {
8209 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8210 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8211 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8213 _mmplayer_gst_send_event_to_sink(player, event);
8215 result = MM_ERROR_PLAYER_INTERNAL;
8225 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8227 mmplayer_t *player = (mmplayer_t *)hplayer;
8231 /* check player handle */
8232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8234 *silent = player->set_mode.subtitle_off;
8236 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8240 return MM_ERROR_NONE;
8244 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8246 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8247 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8249 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8250 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8254 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8255 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8256 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8257 mmplayer_dump_t *dump_s;
8258 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8259 if (dump_s == NULL) {
8260 LOGE("malloc fail");
8264 dump_s->dump_element_file = NULL;
8265 dump_s->dump_pad = NULL;
8266 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8268 if (dump_s->dump_pad) {
8269 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8270 snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN * 2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
8271 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8272 dump_s->probe_handle_id = gst_pad_add_probe(dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL);
8273 /* add list for removed buffer probe and close FILE */
8274 player->dump_list = g_list_append(player->dump_list, dump_s);
8275 LOGD("%s sink pad added buffer probe for dump", factory_name);
8278 MMPLAYER_FREEIF(dump_s);
8279 LOGE("failed to get %s sink pad added", factory_name);
8286 static GstPadProbeReturn
8287 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8289 FILE *dump_data = (FILE *)u_data;
8291 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8292 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8294 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8296 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8298 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8300 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8302 gst_buffer_unmap(buffer, &probe_info);
8304 return GST_PAD_PROBE_OK;
8308 __mmplayer_release_dump_list(GList *dump_list)
8310 GList *d_list = dump_list;
8315 for (; d_list; d_list = g_list_next(d_list)) {
8316 mmplayer_dump_t *dump_s = d_list->data;
8317 if (dump_s->dump_pad) {
8318 if (dump_s->probe_handle_id)
8319 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8320 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8322 if (dump_s->dump_element_file) {
8323 fclose(dump_s->dump_element_file);
8324 dump_s->dump_element_file = NULL;
8326 MMPLAYER_FREEIF(dump_s);
8328 g_list_free(dump_list);
8333 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8335 mmplayer_t *player = (mmplayer_t *)hplayer;
8339 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8340 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8342 *exist = (bool)player->has_closed_caption;
8346 return MM_ERROR_NONE;
8350 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8354 // LOGD("unref internal gst buffer %p", buffer);
8355 gst_buffer_unref((GstBuffer *)buffer);
8362 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8364 mmplayer_t *player = (mmplayer_t *)hplayer;
8368 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8369 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8371 if (MMPLAYER_IS_STREAMING(player))
8372 *timeout = (int)player->ini.live_state_change_timeout;
8374 *timeout = (int)player->ini.localplayback_state_change_timeout;
8376 LOGD("timeout = %d", *timeout);
8379 return MM_ERROR_NONE;
8383 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8387 MMPLAYER_RETURN_IF_FAIL(player);
8389 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8391 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8392 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8393 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8394 player->storage_info[i].id = -1;
8395 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8397 if (path_type != MMPLAYER_PATH_MAX)
8406 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8408 int ret = MM_ERROR_NONE;
8409 mmplayer_t *player = (mmplayer_t *)hplayer;
8410 MMMessageParamType msg_param = {0, };
8413 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8415 LOGW("state changed storage %d:%d", id, state);
8417 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8418 return MM_ERROR_NONE;
8420 /* FIXME: text path should be handled seperately. */
8421 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8422 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8423 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8424 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8425 LOGW("external storage is removed");
8427 if (player->msg_posted == FALSE) {
8428 memset(&msg_param, 0, sizeof(MMMessageParamType));
8429 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8430 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8431 player->msg_posted = TRUE;
8434 /* unrealize the player */
8435 ret = _mmplayer_unrealize(hplayer);
8436 if (ret != MM_ERROR_NONE)
8437 LOGE("failed to unrealize");
8445 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8447 int ret = MM_ERROR_NONE;
8448 mmplayer_t *player = (mmplayer_t *)hplayer;
8449 int idx = 0, total = 0;
8450 gchar *result = NULL, *tmp = NULL;
8453 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8454 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8456 total = *num = g_list_length(player->adaptive_info.var_list);
8458 LOGW("There is no stream variant info.");
8462 result = g_strdup("");
8463 for (idx = 0 ; idx < total ; idx++) {
8464 stream_variant_t *v_data = NULL;
8465 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8468 gchar data[64] = {0};
8469 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8471 tmp = g_strconcat(result, data, NULL);
8475 LOGW("There is no variant data in %d", idx);
8480 *var_info = (char *)result;
8482 LOGD("variant info %d:%s", *num, *var_info);
8488 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8490 int ret = MM_ERROR_NONE;
8491 mmplayer_t *player = (mmplayer_t *)hplayer;
8494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8496 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8498 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8499 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8500 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8502 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8503 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8504 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8505 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8507 /* FIXME: seek to current position for applying new variant limitation */
8516 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8518 int ret = MM_ERROR_NONE;
8519 mmplayer_t *player = (mmplayer_t *)hplayer;
8522 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8523 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8525 *bandwidth = player->adaptive_info.limit.bandwidth;
8526 *width = player->adaptive_info.limit.width;
8527 *height = player->adaptive_info.limit.height;
8529 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8536 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8538 int ret = MM_ERROR_NONE;
8539 mmplayer_t *player = (mmplayer_t *)hplayer;
8542 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8543 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8544 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8546 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8548 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8549 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8550 else /* live case */
8551 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8553 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8560 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8562 #define IDX_FIRST_SW_CODEC 0
8563 mmplayer_t *player = (mmplayer_t *)hplayer;
8564 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8565 MMHandleType attrs = 0;
8568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8570 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8571 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8572 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8574 switch (stream_type) {
8575 case MM_PLAYER_STREAM_TYPE_AUDIO:
8576 /* to support audio codec selection, codec info have to be added in ini file as below.
8577 audio codec element hw = xxxx
8578 audio codec element sw = avdec */
8579 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8580 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8581 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8582 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8583 LOGE("There is no audio codec info for codec_type %d", codec_type);
8584 return MM_ERROR_PLAYER_NO_OP;
8587 case MM_PLAYER_STREAM_TYPE_VIDEO:
8588 /* to support video codec selection, codec info have to be added in ini file as below.
8589 video codec element hw = omx
8590 video codec element sw = avdec */
8591 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8592 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8593 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8594 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8595 LOGE("There is no video codec info for codec_type %d", codec_type);
8596 return MM_ERROR_PLAYER_NO_OP;
8600 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8601 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8605 LOGD("update %s codec_type to %d", attr_name, codec_type);
8607 attrs = MMPLAYER_GET_ATTRS(player);
8608 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8610 if (mm_attrs_commit_all(player->attrs)) {
8611 LOGE("failed to commit codec_type attributes");
8612 return MM_ERROR_PLAYER_INTERNAL;
8616 return MM_ERROR_NONE;
8620 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8622 mmplayer_t *player = (mmplayer_t *)hplayer;
8623 GstElement *rg_vol_element = NULL;
8627 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8629 player->sound.rg_enable = enabled;
8631 /* just hold rgvolume enable value if pipeline is not ready */
8632 if (!player->pipeline || !player->pipeline->audiobin) {
8633 LOGD("pipeline is not ready. holding rgvolume enable value");
8634 return MM_ERROR_NONE;
8637 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8639 if (!rg_vol_element) {
8640 LOGD("rgvolume element is not created");
8641 return MM_ERROR_PLAYER_INTERNAL;
8645 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8647 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8651 return MM_ERROR_NONE;
8655 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8657 mmplayer_t *player = (mmplayer_t *)hplayer;
8658 GstElement *rg_vol_element = NULL;
8659 gboolean enable = FALSE;
8663 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8664 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8666 /* just hold enable_rg value if pipeline is not ready */
8667 if (!player->pipeline || !player->pipeline->audiobin) {
8668 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8669 *enabled = player->sound.rg_enable;
8670 return MM_ERROR_NONE;
8673 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8675 if (!rg_vol_element) {
8676 LOGD("rgvolume element is not created");
8677 return MM_ERROR_PLAYER_INTERNAL;
8680 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8681 *enabled = (bool)enable;
8685 return MM_ERROR_NONE;
8689 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8691 mmplayer_t *player = (mmplayer_t *)hplayer;
8692 MMHandleType attrs = 0;
8693 void *handle = NULL;
8694 int ret = MM_ERROR_NONE;
8698 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8700 attrs = MMPLAYER_GET_ATTRS(player);
8701 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8703 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8705 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8706 return MM_ERROR_PLAYER_INTERNAL;
8709 player->video_roi.scale_x = scale_x;
8710 player->video_roi.scale_y = scale_y;
8711 player->video_roi.scale_width = scale_width;
8712 player->video_roi.scale_height = scale_height;
8714 /* check video sinkbin is created */
8715 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8716 return MM_ERROR_NONE;
8718 if (!gst_video_overlay_set_video_roi_area(
8719 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8720 scale_x, scale_y, scale_width, scale_height))
8721 ret = MM_ERROR_PLAYER_INTERNAL;
8723 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8724 scale_x, scale_y, scale_width, scale_height);
8732 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8734 mmplayer_t *player = (mmplayer_t *)hplayer;
8735 int ret = MM_ERROR_NONE;
8739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8740 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8742 *scale_x = player->video_roi.scale_x;
8743 *scale_y = player->video_roi.scale_y;
8744 *scale_width = player->video_roi.scale_width;
8745 *scale_height = player->video_roi.scale_height;
8747 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8748 *scale_x, *scale_y, *scale_width, *scale_height);
8754 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8756 mmplayer_t* player = (mmplayer_t*)hplayer;
8760 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8762 player->client_pid = pid;
8764 LOGD("client pid[%d] %p", pid, player);
8768 return MM_ERROR_NONE;
8772 __mmplayer_update_duration_value(mmplayer_t *player)
8774 gboolean ret = FALSE;
8775 gint64 dur_nsec = 0;
8776 LOGD("try to update duration");
8778 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8779 player->duration = dur_nsec;
8780 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8784 if (player->duration < 0) {
8785 LOGW("duration is Non-Initialized !!!");
8786 player->duration = 0;
8789 /* update streaming service type */
8790 player->streaming_type = _mmplayer_get_stream_service_type(player);
8792 /* check duration is OK */
8793 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8794 /* FIXIT : find another way to get duration here. */
8795 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8801 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8803 /* update audio params
8804 NOTE : We need original audio params and it can be only obtained from src pad of audio
8805 decoder. Below code only valid when we are not using 'resampler' just before
8806 'audioconverter'. */
8807 GstCaps *caps_a = NULL;
8809 gint samplerate = 0, channels = 0;
8810 GstStructure *p = NULL;
8811 GstElement *aconv = NULL;
8813 LOGD("try to update audio attrs");
8815 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8817 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8818 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8819 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8820 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8822 LOGE("there is no audio converter");
8826 pad = gst_element_get_static_pad(aconv, "sink");
8829 LOGW("failed to get pad from audio converter");
8833 caps_a = gst_pad_get_current_caps(pad);
8835 LOGW("not ready to get audio caps");
8836 gst_object_unref(pad);
8840 p = gst_caps_get_structure(caps_a, 0);
8842 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8844 gst_structure_get_int(p, "rate", &samplerate);
8845 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8847 gst_structure_get_int(p, "channels", &channels);
8848 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8850 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8852 gst_caps_unref(caps_a);
8853 gst_object_unref(pad);
8859 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8861 LOGD("try to update video attrs");
8863 GstCaps *caps_v = NULL;
8867 GstStructure *p = NULL;
8869 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8870 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8872 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8874 LOGD("no videosink sink pad");
8878 caps_v = gst_pad_get_current_caps(pad);
8879 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8880 if (!caps_v && player->v_stream_caps) {
8881 caps_v = player->v_stream_caps;
8882 gst_caps_ref(caps_v);
8886 LOGD("no negitiated caps from videosink");
8887 gst_object_unref(pad);
8891 p = gst_caps_get_structure(caps_v, 0);
8892 gst_structure_get_int(p, "width", &width);
8893 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8895 gst_structure_get_int(p, "height", &height);
8896 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8898 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8900 SECURE_LOGD("width : %d height : %d", width, height);
8902 gst_caps_unref(caps_v);
8903 gst_object_unref(pad);
8906 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8907 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8914 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8916 gboolean ret = FALSE;
8917 guint64 data_size = 0;
8921 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8922 if (!player->duration)
8925 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8926 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8927 if (stat(path, &sb) == 0)
8928 data_size = (guint64)sb.st_size;
8930 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8931 data_size = player->http_content_size;
8934 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8937 guint64 bitrate = 0;
8938 guint64 msec_dur = 0;
8940 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8942 bitrate = data_size * 8 * 1000 / msec_dur;
8943 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8944 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8948 LOGD("player duration is less than 0");
8952 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8953 if (player->total_bitrate) {
8954 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8963 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8965 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8966 data->uri_type = uri_type;
8970 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8972 int ret = MM_ERROR_PLAYER_INVALID_URI;
8974 char *buffer = NULL;
8975 char *seperator = strchr(path, ',');
8976 char ext[100] = {0,}, size[100] = {0,};
8979 if ((buffer = strstr(path, "ext="))) {
8980 buffer += strlen("ext=");
8982 if (strlen(buffer)) {
8983 strncpy(ext, buffer, 99);
8985 if ((seperator = strchr(ext, ','))
8986 || (seperator = strchr(ext, ' '))
8987 || (seperator = strchr(ext, '\0'))) {
8988 seperator[0] = '\0';
8993 if ((buffer = strstr(path, "size="))) {
8994 buffer += strlen("size=");
8996 if (strlen(buffer) > 0) {
8997 strncpy(size, buffer, 99);
8999 if ((seperator = strchr(size, ','))
9000 || (seperator = strchr(size, ' '))
9001 || (seperator = strchr(size, '\0'))) {
9002 seperator[0] = '\0';
9005 mem_size = atoi(size);
9010 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9012 if (mem_size && param) {
9013 if (data->input_mem.buf)
9014 free(data->input_mem.buf);
9015 data->input_mem.buf = malloc(mem_size);
9017 if (data->input_mem.buf) {
9018 memcpy(data->input_mem.buf, param, mem_size);
9019 data->input_mem.len = mem_size;
9020 ret = MM_ERROR_NONE;
9022 LOGE("failed to alloc mem %d", mem_size);
9023 ret = MM_ERROR_PLAYER_INTERNAL;
9026 data->input_mem.offset = 0;
9027 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9034 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9036 gchar *location = NULL;
9039 int ret = MM_ERROR_NONE;
9041 if ((path = strstr(uri, "file://"))) {
9042 location = g_filename_from_uri(uri, NULL, &err);
9043 if (!location || (err != NULL)) {
9044 LOGE("Invalid URI '%s' for filesrc: %s", path,
9045 (err != NULL) ? err->message : "unknown error");
9049 MMPLAYER_FREEIF(location);
9051 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9052 return MM_ERROR_PLAYER_INVALID_URI;
9054 LOGD("path from uri: %s", location);
9057 path = (location != NULL) ? (location) : ((char *)uri);
9060 ret = _mmplayer_exist_file_path(path);
9062 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9063 if (ret == MM_ERROR_NONE) {
9064 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9065 if (_mmplayer_is_sdp_file(path)) {
9066 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9067 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9069 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9071 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9072 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9074 LOGE("invalid uri, could not play..");
9075 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9078 MMPLAYER_FREEIF(location);
9083 static mmplayer_video_decoded_data_info_t *
9084 __mmplayer_create_stream_from_pad(GstPad *pad)
9086 GstCaps *caps = NULL;
9087 GstStructure *structure = NULL;
9088 unsigned int fourcc = 0;
9089 const gchar *string_format = NULL;
9090 mmplayer_video_decoded_data_info_t *stream = NULL;
9092 MMPixelFormatType format;
9095 caps = gst_pad_get_current_caps(pad);
9097 LOGE("Caps is NULL.");
9101 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9102 structure = gst_caps_get_structure(caps, 0);
9103 gst_structure_get_int(structure, "width", &width);
9104 gst_structure_get_int(structure, "height", &height);
9105 string_format = gst_structure_get_string(structure, "format");
9108 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9109 format = _mmplayer_get_pixtype(fourcc);
9110 gst_video_info_from_caps(&info, caps);
9111 gst_caps_unref(caps);
9114 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9115 LOGE("Wrong condition!!");
9119 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9121 LOGE("failed to alloc mem for video data");
9125 stream->width = width;
9126 stream->height = height;
9127 stream->format = format;
9128 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9134 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9136 unsigned int pitch = 0;
9137 unsigned int size = 0;
9139 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9142 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9143 bo = gst_tizen_memory_get_bos(mem, index);
9145 stream->bo[index] = tbm_bo_ref(bo);
9147 LOGE("failed to get bo for index %d", index);
9150 for (index = 0; index < stream->plane_num; index++) {
9151 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9152 stream->stride[index] = pitch;
9154 stream->elevation[index] = size / pitch;
9156 stream->elevation[index] = stream->height;
9161 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9163 if (stream->format == MM_PIXEL_FORMAT_I420) {
9164 int ret = TBM_SURFACE_ERROR_NONE;
9165 tbm_surface_h surface;
9166 tbm_surface_info_s info;
9168 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9170 ret = tbm_surface_get_info(surface, &info);
9171 if (ret != TBM_SURFACE_ERROR_NONE) {
9172 tbm_surface_destroy(surface);
9176 tbm_surface_destroy(surface);
9177 stream->stride[0] = info.planes[0].stride;
9178 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9179 stream->stride[1] = info.planes[1].stride;
9180 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9181 stream->stride[2] = info.planes[2].stride;
9182 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9183 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9184 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9185 stream->stride[0] = stream->width * 4;
9186 stream->elevation[0] = stream->height;
9187 stream->bo_size = stream->stride[0] * stream->height;
9189 LOGE("Not support format %d", stream->format);
9197 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9199 tbm_bo_handle thandle;
9201 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9202 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9203 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9207 unsigned char *src = NULL;
9208 unsigned char *dest = NULL;
9209 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9211 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9213 LOGE("fail to gst_memory_map");
9217 if (!mapinfo.data) {
9218 LOGE("data pointer is wrong");
9222 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9223 if (!stream->bo[0]) {
9224 LOGE("Fail to tbm_bo_alloc!!");
9228 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9230 LOGE("thandle pointer is wrong");
9234 if (stream->format == MM_PIXEL_FORMAT_I420) {
9235 src_stride[0] = GST_ROUND_UP_4(stream->width);
9236 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9237 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9238 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9241 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9242 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9244 for (i = 0; i < 3; i++) {
9245 src = mapinfo.data + src_offset[i];
9246 dest = thandle.ptr + dest_offset[i];
9251 for (j = 0; j < stream->height >> k; j++) {
9252 memcpy(dest, src, stream->width>>k);
9253 src += src_stride[i];
9254 dest += stream->stride[i];
9257 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9258 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9260 LOGE("Not support format %d", stream->format);
9264 tbm_bo_unmap(stream->bo[0]);
9265 gst_memory_unmap(mem, &mapinfo);
9271 tbm_bo_unmap(stream->bo[0]);
9274 gst_memory_unmap(mem, &mapinfo);
9280 __mmplayer_set_pause_state(mmplayer_t *player)
9282 if (player->sent_bos)
9285 /* rtsp case, get content attrs by GstMessage */
9286 if (MMPLAYER_IS_RTSP_STREAMING(player))
9289 /* it's first time to update all content attrs. */
9290 _mmplayer_update_content_attrs(player, ATTR_ALL);
9294 __mmplayer_set_playing_state(mmplayer_t *player)
9296 gchar *audio_codec = NULL;
9298 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9299 /* initialize because auto resume is done well. */
9300 player->resumed_by_rewind = FALSE;
9301 player->playback_rate = 1.0;
9304 if (player->sent_bos)
9307 /* try to get content metadata */
9309 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9310 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9311 * legacy mmfw-player api
9313 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9315 if ((player->cmd == MMPLAYER_COMMAND_START)
9316 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9317 __mmplayer_handle_missed_plugin(player);
9320 /* check audio codec field is set or not
9321 * we can get it from typefinder or codec's caps.
9323 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9325 /* The codec format can't be sent for audio only case like amr, mid etc.
9326 * Because, parser don't make related TAG.
9327 * So, if it's not set yet, fill it with found data.
9330 if (g_strrstr(player->type, "audio/midi"))
9331 audio_codec = "MIDI";
9332 else if (g_strrstr(player->type, "audio/x-amr"))
9333 audio_codec = "AMR";
9334 else if (g_strrstr(player->type, "audio/mpeg")
9335 && !g_strrstr(player->type, "mpegversion=(int)1"))
9336 audio_codec = "AAC";
9338 audio_codec = "unknown";
9340 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9342 if (mm_attrs_commit_all(player->attrs))
9343 LOGE("failed to update attributes");
9345 LOGD("set audio codec type with caps");