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;
609 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
610 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
613 LOGE("invalid mmplayer resource type %d", type);
614 return MM_ERROR_PLAYER_INTERNAL;
617 if (player->hw_resource[type] != NULL) {
618 LOGD("[%d type] resource was already acquired", type);
619 return MM_ERROR_NONE;
622 LOGD("mark for acquire [%d type] resource", type);
623 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
624 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
625 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
627 return MM_ERROR_PLAYER_INTERNAL;
630 rm_ret = mm_resource_manager_commit(player->resource_manager);
631 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
632 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
633 return MM_ERROR_PLAYER_INTERNAL;
637 return MM_ERROR_NONE;
640 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
642 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
646 if (player->hw_resource[type] == NULL) {
647 LOGD("there is no acquired [%d type] resource", type);
648 return MM_ERROR_NONE;
651 LOGD("mark for release [%d type] resource", type);
652 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
653 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
654 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
655 return MM_ERROR_PLAYER_INTERNAL;
658 player->hw_resource[type] = NULL;
660 rm_ret = mm_resource_manager_commit(player->resource_manager);
661 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
662 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
663 return MM_ERROR_PLAYER_INTERNAL;
667 return MM_ERROR_NONE;
671 __mmplayer_initialize_gapless_play(mmplayer_t *player)
677 player->smooth_streaming = FALSE;
678 player->videodec_linked = 0;
679 player->audiodec_linked = 0;
680 player->textsink_linked = 0;
681 player->is_external_subtitle_present = FALSE;
682 player->is_external_subtitle_added_now = FALSE;
683 player->not_supported_codec = MISSING_PLUGIN_NONE;
684 player->can_support_codec = FOUND_PLUGIN_NONE;
685 player->pending_seek.is_pending = false;
686 player->pending_seek.pos = 0;
687 player->msg_posted = FALSE;
688 player->has_many_types = FALSE;
689 player->no_more_pad = FALSE;
690 player->not_found_demuxer = 0;
691 player->seek_state = MMPLAYER_SEEK_NONE;
692 player->is_subtitle_force_drop = FALSE;
693 player->play_subtitle = FALSE;
694 player->adjust_subtitle_pos = 0;
696 player->total_bitrate = 0;
697 player->total_maximum_bitrate = 0;
699 _mmplayer_track_initialize(player);
700 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
702 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
703 player->bitrate[i] = 0;
704 player->maximum_bitrate[i] = 0;
707 if (player->v_stream_caps) {
708 gst_caps_unref(player->v_stream_caps);
709 player->v_stream_caps = NULL;
712 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
714 /* clean found audio decoders */
715 if (player->audio_decoders) {
716 GList *a_dec = player->audio_decoders;
717 for (; a_dec; a_dec = g_list_next(a_dec)) {
718 gchar *name = a_dec->data;
719 MMPLAYER_FREEIF(name);
721 g_list_free(player->audio_decoders);
722 player->audio_decoders = NULL;
725 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
731 __mmplayer_gapless_play_thread(gpointer data)
733 mmplayer_t *player = (mmplayer_t *)data;
734 mmplayer_gst_element_t *mainbin = NULL;
736 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
738 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
739 while (!player->gapless_play_thread_exit) {
740 LOGD("gapless play thread started. waiting for signal.");
741 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
743 LOGD("reconfigure pipeline for gapless play.");
745 if (player->gapless_play_thread_exit) {
746 if (player->gapless.reconfigure) {
747 player->gapless.reconfigure = false;
748 MMPLAYER_PLAYBACK_UNLOCK(player);
750 LOGD("exiting gapless play thread");
754 mainbin = player->pipeline->mainbin;
756 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
757 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
758 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
759 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
760 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
762 /* Initialize Player values */
763 __mmplayer_initialize_gapless_play(player);
765 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
767 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
773 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
775 GSource *source = NULL;
779 source = g_main_context_find_source_by_id(context, source_id);
780 if (source != NULL) {
781 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
782 g_source_destroy(source);
789 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
791 mmplayer_t *player = (mmplayer_t *)hplayer;
792 GstMessage *msg = NULL;
793 GQueue *queue = NULL;
796 MMPLAYER_RETURN_IF_FAIL(player);
798 /* disconnecting bus watch */
799 if (player->bus_watcher)
800 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
801 player->bus_watcher = 0;
803 /* destroy the gst bus msg thread */
804 if (player->bus_msg_thread) {
805 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
806 player->bus_msg_thread_exit = TRUE;
807 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
808 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
810 LOGD("gst bus msg thread exit.");
811 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
812 player->bus_msg_thread = NULL;
814 g_mutex_clear(&player->bus_msg_thread_mutex);
815 g_cond_clear(&player->bus_msg_thread_cond);
818 g_mutex_lock(&player->bus_msg_q_lock);
819 queue = player->bus_msg_q;
820 while (!g_queue_is_empty(queue)) {
821 msg = (GstMessage *)g_queue_pop_head(queue);
826 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
827 gst_message_unref(msg);
829 g_mutex_unlock(&player->bus_msg_q_lock);
835 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
837 GstElement *parent = NULL;
839 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
840 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
843 MMPLAYER_FSINK_LOCK(player);
845 /* get parent of fakesink */
846 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
848 LOGD("fakesink already removed");
852 gst_element_set_locked_state(fakesink->gst, TRUE);
854 /* setting the state to NULL never returns async
855 * so no need to wait for completion of state transiton
857 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
858 LOGE("fakesink state change failure!");
859 /* FIXIT : should I return here? or try to proceed to next? */
862 /* remove fakesink from it's parent */
863 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
864 LOGE("failed to remove fakesink");
866 gst_object_unref(parent);
871 gst_object_unref(parent);
873 LOGD("state-holder removed");
875 gst_element_set_locked_state(fakesink->gst, FALSE);
877 MMPLAYER_FSINK_UNLOCK(player);
882 gst_element_set_locked_state(fakesink->gst, FALSE);
884 MMPLAYER_FSINK_UNLOCK(player);
888 static GstPadProbeReturn
889 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
891 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
892 return GST_PAD_PROBE_OK;
896 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
898 gint64 stop_running_time = 0;
899 gint64 position_running_time = 0;
903 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
904 if ((player->gapless.update_segment[idx] == TRUE) ||
905 !(player->selector[idx].event_probe_id)) {
906 /* LOGW("[%d] skip", idx); */
910 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
912 gst_segment_to_running_time(&player->gapless.segment[idx],
913 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
914 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
916 gst_segment_to_running_time(&player->gapless.segment[idx],
917 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
919 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
921 gst_segment_to_running_time(&player->gapless.segment[idx],
922 GST_FORMAT_TIME, player->duration);
925 position_running_time =
926 gst_segment_to_running_time(&player->gapless.segment[idx],
927 GST_FORMAT_TIME, player->gapless.segment[idx].position);
929 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
930 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
932 GST_TIME_ARGS(stop_running_time),
933 GST_TIME_ARGS(position_running_time),
934 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
935 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
937 position_running_time = MAX(position_running_time, stop_running_time);
938 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
939 GST_FORMAT_TIME, player->gapless.segment[idx].start);
940 position_running_time = MAX(0, position_running_time);
941 position = MAX(position, position_running_time);
945 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
946 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
947 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
949 player->gapless.start_time[stream_type] += position;
955 static GstPadProbeReturn
956 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
958 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
959 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
960 mmplayer_t *player = (mmplayer_t *)data;
961 GstCaps *caps = NULL;
962 GstStructure *str = NULL;
963 const gchar *name = NULL;
964 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
965 gboolean caps_ret = TRUE;
967 if (GST_EVENT_IS_DOWNSTREAM(event) &&
968 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
969 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
970 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
971 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
973 } else if (GST_EVENT_IS_UPSTREAM(event) &&
974 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
978 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
982 if (strstr(name, "audio")) {
983 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
984 } else if (strstr(name, "video")) {
985 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
987 /* text track is not supportable */
988 LOGE("invalid name %s", name);
992 switch (GST_EVENT_TYPE(event)) {
995 /* in case of gapless, drop eos event not to send it to sink */
996 if (player->gapless.reconfigure && !player->msg_posted) {
997 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
998 ret = GST_PAD_PROBE_DROP;
1002 case GST_EVENT_STREAM_START:
1004 __mmplayer_gst_selector_update_start_time(player, stream_type);
1007 case GST_EVENT_FLUSH_STOP:
1009 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1010 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1011 player->gapless.start_time[stream_type] = 0;
1014 case GST_EVENT_SEGMENT:
1019 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1020 gst_event_copy_segment(event, &segment);
1022 if (segment.format != GST_FORMAT_TIME)
1025 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1026 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1027 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1028 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1029 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1030 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1032 /* keep the all the segment ev to cover the seeking */
1033 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1034 player->gapless.update_segment[stream_type] = TRUE;
1036 if (!player->gapless.running)
1039 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1041 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1043 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1044 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1045 gst_event_unref(event);
1046 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1052 gdouble proportion = 0.0;
1053 GstClockTimeDiff diff = 0;
1054 GstClockTime timestamp = 0;
1055 gint64 running_time_diff = -1;
1056 GstQOSType type = 0;
1057 GstEvent *tmpev = NULL;
1059 running_time_diff = player->gapless.segment[stream_type].base;
1061 if (running_time_diff <= 0) /* don't need to adjust */
1064 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1065 gst_event_unref(event);
1067 if (timestamp < running_time_diff) {
1068 LOGW("QOS event from previous group");
1069 ret = GST_PAD_PROBE_DROP;
1073 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1074 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1075 stream_type, GST_TIME_ARGS(timestamp),
1076 GST_TIME_ARGS(running_time_diff),
1077 GST_TIME_ARGS(timestamp - running_time_diff));
1079 timestamp -= running_time_diff;
1081 /* That case is invalid for QoS events */
1082 if (diff < 0 && -diff > timestamp) {
1083 LOGW("QOS event from previous group");
1084 ret = GST_PAD_PROBE_DROP;
1088 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1089 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1099 gst_caps_unref(caps);
1103 /* create fakesink for audio or video path witout audiobin or videobin */
1105 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1107 GstElement *pipeline = NULL;
1108 GstElement *fakesink = NULL;
1109 GstPad *sinkpad = NULL;
1112 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1114 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1117 fakesink = gst_element_factory_make("fakesink", NULL);
1118 if (fakesink == NULL) {
1119 LOGE("failed to create fakesink");
1123 /* store it as it's sink element */
1124 __mmplayer_add_sink(player, fakesink);
1126 gst_bin_add(GST_BIN(pipeline), fakesink);
1129 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1131 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1133 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1134 LOGE("failed to link fakesink");
1135 gst_object_unref(GST_OBJECT(fakesink));
1139 if (strstr(name, "video")) {
1140 if (player->v_stream_caps) {
1141 gst_caps_unref(player->v_stream_caps);
1142 player->v_stream_caps = NULL;
1144 if (player->ini.set_dump_element_flag)
1145 __mmplayer_add_dump_buffer_probe(player, fakesink);
1148 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1149 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1153 gst_object_unref(GST_OBJECT(sinkpad));
1160 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1162 GstElement *pipeline = NULL;
1163 GstElement *selector = NULL;
1164 GstPad *srcpad = NULL;
1167 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1169 selector = gst_element_factory_make("input-selector", NULL);
1171 LOGE("failed to create input-selector");
1174 g_object_set(selector, "sync-streams", TRUE, NULL);
1176 player->pipeline->mainbin[elem_idx].id = elem_idx;
1177 player->pipeline->mainbin[elem_idx].gst = selector;
1179 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1181 srcpad = gst_element_get_static_pad(selector, "src");
1183 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1184 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1185 __mmplayer_gst_selector_blocked, NULL, NULL);
1186 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1187 __mmplayer_gst_selector_event_probe, player, NULL);
1189 gst_element_set_state(selector, GST_STATE_PAUSED);
1191 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1192 gst_bin_add(GST_BIN(pipeline), selector);
1194 gst_object_unref(GST_OBJECT(srcpad));
1201 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1203 mmplayer_t *player = (mmplayer_t *)data;
1204 GstElement *selector = NULL;
1205 GstCaps *caps = NULL;
1206 GstStructure *str = NULL;
1207 const gchar *name = NULL;
1208 GstPad *sinkpad = NULL;
1209 gboolean first_track = FALSE;
1210 gboolean caps_ret = TRUE;
1212 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1213 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1216 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1217 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1219 LOGD("pad-added signal handling");
1221 /* get mimetype from caps */
1222 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1226 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1227 /* LOGD("detected mimetype : %s", name); */
1229 if (strstr(name, "video")) {
1231 gchar *caps_str = NULL;
1233 caps_str = gst_caps_to_string(caps);
1234 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1235 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1236 player->set_mode.video_zc = true;
1238 MMPLAYER_FREEIF(caps_str);
1240 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1241 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1243 LOGD("surface type : %d", stype);
1245 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1246 __mmplayer_gst_create_sinkbin(elem, pad, player);
1250 /* in case of exporting video frame, it requires the 360 video filter.
1251 * it will be handled in _no_more_pads(). */
1252 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1253 __mmplayer_gst_make_fakesink(player, pad, name);
1257 LOGD("video selector is required");
1258 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1259 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1260 } else if (strstr(name, "audio")) {
1261 gint samplerate = 0;
1264 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1265 if (player->build_audio_offload)
1266 player->no_more_pad = TRUE; /* remove state holder */
1267 __mmplayer_gst_create_sinkbin(elem, pad, player);
1271 gst_structure_get_int(str, "rate", &samplerate);
1272 gst_structure_get_int(str, "channels", &channels);
1274 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1275 __mmplayer_gst_make_fakesink(player, pad, name);
1279 LOGD("audio selector is required");
1280 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1281 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1283 } else if (strstr(name, "text")) {
1284 LOGD("text selector is required");
1285 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1286 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1288 LOGE("invalid caps info");
1292 /* check selector and create it */
1293 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1294 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1299 LOGD("input-selector is already created.");
1303 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1305 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1307 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1308 LOGE("failed to link selector");
1309 gst_object_unref(GST_OBJECT(selector));
1314 LOGD("this track will be activated");
1315 g_object_set(selector, "active-pad", sinkpad, NULL);
1318 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1324 gst_caps_unref(caps);
1327 gst_object_unref(GST_OBJECT(sinkpad));
1335 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1337 GstPad *srcpad = NULL;
1340 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1342 LOGD("type %d", type);
1345 LOGD("there is no %d track", type);
1349 srcpad = gst_element_get_static_pad(selector, "src");
1351 LOGE("failed to get srcpad from selector");
1355 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1357 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1359 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1360 if (player->selector[type].block_id) {
1361 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1362 player->selector[type].block_id = 0;
1366 gst_object_unref(GST_OBJECT(srcpad));
1375 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1377 MMHandleType attrs = 0;
1378 gint active_index = 0;
1381 MMPLAYER_RETURN_IF_FAIL(player);
1383 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1385 /* change track to active pad */
1386 active_index = player->selector[type].active_pad_index;
1387 if ((active_index != DEFAULT_TRACK) &&
1388 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1389 LOGW("failed to change %d type track to %d", type, active_index);
1390 player->selector[type].active_pad_index = DEFAULT_TRACK;
1394 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1395 attrs = MMPLAYER_GET_ATTRS(player);
1397 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1398 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1400 if (mm_attrs_commit_all(attrs))
1401 LOGW("failed to commit attrs.");
1403 LOGW("cannot get content attribute");
1412 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1415 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1417 if (!audio_selector) {
1418 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1420 /* in case the source is changed, output can be changed. */
1421 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1422 LOGD("remove previous audiobin if it exist");
1424 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1425 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1427 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1428 MMPLAYER_FREEIF(player->pipeline->audiobin);
1431 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1432 __mmplayer_pipeline_complete(NULL, player);
1437 /* apply the audio track information */
1438 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1440 /* create audio sink path */
1441 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1442 LOGE("failed to create audio sink path");
1451 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1454 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1456 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1457 LOGD("text path is not supproted");
1461 /* apply the text track information */
1462 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1464 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1465 player->has_closed_caption = TRUE;
1467 /* create text decode path */
1468 player->no_more_pad = TRUE;
1470 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1471 LOGE("failed to create text sink path");
1480 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1482 gint64 dur_bytes = 0L;
1485 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1486 player->pipeline->mainbin && player->streamer, FALSE);
1488 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1489 LOGE("fail to get duration.");
1491 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1492 * use file information was already set on Q2 when it was created. */
1493 _mm_player_streaming_set_queue2(player->streamer,
1494 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1495 TRUE, /* use_buffering */
1496 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1497 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1504 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1506 mmplayer_t *player = NULL;
1507 GstElement *video_selector = NULL;
1508 GstElement *audio_selector = NULL;
1509 GstElement *text_selector = NULL;
1512 player = (mmplayer_t *)data;
1514 LOGD("no-more-pad signal handling");
1516 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1517 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1518 LOGW("player is shutting down");
1522 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1523 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1524 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1525 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1526 LOGE("failed to set queue2 buffering");
1531 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1532 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1533 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1535 if (!video_selector && !audio_selector && !text_selector) {
1536 LOGW("there is no selector");
1537 player->no_more_pad = TRUE;
1541 /* create video path followed by video-select */
1542 if (video_selector && !audio_selector && !text_selector)
1543 player->no_more_pad = TRUE;
1545 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1548 /* create audio path followed by audio-select */
1549 if (audio_selector && !text_selector)
1550 player->no_more_pad = TRUE;
1552 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1555 /* create text path followed by text-select */
1556 __mmplayer_create_text_sink_path(player, text_selector);
1559 if (player->gapless.reconfigure) {
1560 player->gapless.reconfigure = FALSE;
1561 MMPLAYER_PLAYBACK_UNLOCK(player);
1568 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1570 gboolean ret = FALSE;
1571 GstElement *pipeline = NULL;
1572 GstPad *sinkpad = NULL;
1575 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1576 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1578 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1580 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1582 LOGE("failed to get pad from sinkbin");
1588 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1589 LOGE("failed to link sinkbin for reusing");
1590 goto EXIT; /* exit either pass or fail */
1594 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1595 LOGE("failed to set state(READY) to sinkbin");
1600 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1601 LOGE("failed to add sinkbin to pipeline");
1606 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1607 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1612 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1613 LOGE("failed to set state(PAUSED) to sinkbin");
1622 gst_object_unref(GST_OBJECT(sinkpad));
1630 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1632 mmplayer_t *player = NULL;
1633 GstCaps *caps = NULL;
1634 gchar *caps_str = NULL;
1635 GstStructure *str = NULL;
1636 const gchar *name = NULL;
1637 GstElement *sinkbin = NULL;
1638 gboolean reusing = FALSE;
1639 gboolean caps_ret = TRUE;
1640 gchar *sink_pad_name = "sink";
1643 player = (mmplayer_t *)data;
1646 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1647 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1649 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1653 caps_str = gst_caps_to_string(caps);
1655 /* LOGD("detected mimetype : %s", name); */
1656 if (strstr(name, "audio")) {
1657 if (player->pipeline->audiobin == NULL) {
1658 const gchar *audio_format = gst_structure_get_string(str, "format");
1660 LOGD("original audio format %s", audio_format);
1661 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1664 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1665 LOGE("failed to create audiobin. continuing without audio");
1669 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1670 LOGD("creating audiobin success");
1673 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1674 LOGD("reusing audiobin");
1675 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1677 } else if (strstr(name, "video")) {
1678 /* 1. zero copy is updated at _decode_pad_added()
1679 * 2. NULL surface type is handled in _decode_pad_added() */
1680 LOGD("zero copy %d", player->set_mode.video_zc);
1681 if (player->pipeline->videobin == NULL) {
1682 int surface_type = 0;
1683 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1684 LOGD("display_surface_type (%d)", surface_type);
1686 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1687 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1688 LOGE("failed to acquire video overlay resource");
1692 player->interrupted_by_resource = FALSE;
1694 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1695 LOGE("failed to create videobin. continuing without video");
1699 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1700 LOGD("creating videosink bin success");
1703 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1704 LOGD("re-using videobin");
1705 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1707 } else if (strstr(name, "text")) {
1708 if (player->pipeline->textbin == NULL) {
1709 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1710 LOGE("failed to create text sink bin. continuing without text");
1714 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1715 player->textsink_linked = 1;
1716 LOGD("creating textsink bin success");
1718 if (!player->textsink_linked) {
1719 LOGD("re-using textbin");
1721 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1722 player->textsink_linked = 1;
1724 /* linked textbin exist which means that the external subtitle path exist already */
1725 LOGW("ignoring internal subtutle since external subtitle is available");
1728 sink_pad_name = "text_sink";
1730 LOGW("unknown mime type %s, ignoring it", name);
1734 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1737 LOGD("[handle: %p] success to create and link sink bin", player);
1739 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1740 * streaming task. if the task blocked, then buffer will not flow to the next element
1741 *(autoplugging element). so this is special hack for streaming. please try to remove it
1743 /* dec stream count. we can remove fakesink if it's zero */
1744 if (player->num_dynamic_pad)
1745 player->num_dynamic_pad--;
1747 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1749 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1750 __mmplayer_pipeline_complete(NULL, player);
1754 MMPLAYER_FREEIF(caps_str);
1757 gst_caps_unref(caps);
1763 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1765 int required_angle = 0; /* Angle required for straight view */
1766 int rotation_angle = 0;
1768 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1769 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1771 /* Counter clockwise */
1772 switch (orientation) {
1777 required_angle = 270;
1780 required_angle = 180;
1783 required_angle = 90;
1787 rotation_angle = display_angle + required_angle;
1788 if (rotation_angle >= 360)
1789 rotation_angle -= 360;
1791 /* chech if supported or not */
1792 if (rotation_angle % 90) {
1793 LOGD("not supported rotation angle = %d", rotation_angle);
1797 switch (rotation_angle) {
1799 *value = MM_DISPLAY_ROTATION_NONE;
1802 *value = MM_DISPLAY_ROTATION_90;
1805 *value = MM_DISPLAY_ROTATION_180;
1808 *value = MM_DISPLAY_ROTATION_270;
1812 LOGD("setting rotation property value : %d", *value);
1818 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1820 /* check video sinkbin is created */
1821 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1823 player->pipeline->videobin &&
1824 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1825 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1826 MM_ERROR_PLAYER_NOT_INITIALIZED);
1828 return MM_ERROR_NONE;
1832 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1834 int display_rotation = 0;
1835 gchar *org_orient = NULL;
1836 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1839 LOGE("cannot get content attribute");
1840 return MM_ERROR_PLAYER_INTERNAL;
1843 if (display_angle) {
1844 /* update user roation */
1845 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1847 /* Counter clockwise */
1848 switch (display_rotation) {
1849 case MM_DISPLAY_ROTATION_NONE:
1852 case MM_DISPLAY_ROTATION_90:
1853 *display_angle = 90;
1855 case MM_DISPLAY_ROTATION_180:
1856 *display_angle = 180;
1858 case MM_DISPLAY_ROTATION_270:
1859 *display_angle = 270;
1862 LOGW("wrong angle type : %d", display_rotation);
1865 LOGD("check user angle: %d", *display_angle);
1869 /* Counter clockwise */
1870 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1873 if (!strcmp(org_orient, "rotate-90"))
1875 else if (!strcmp(org_orient, "rotate-180"))
1877 else if (!strcmp(org_orient, "rotate-270"))
1880 LOGD("original rotation is %s", org_orient);
1882 LOGD("content_video_orientation get fail");
1885 LOGD("check orientation: %d", *orientation);
1888 return MM_ERROR_NONE;
1892 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1894 int rotation_value = 0;
1895 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1896 int display_angle = 0;
1899 /* check video sinkbin is created */
1900 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1903 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1905 /* get rotation value to set */
1906 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1907 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1908 LOGD("set video param : rotate %d", rotation_value);
1912 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1914 MMHandleType attrs = 0;
1918 /* check video sinkbin is created */
1919 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1922 attrs = MMPLAYER_GET_ATTRS(player);
1923 MMPLAYER_RETURN_IF_FAIL(attrs);
1925 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1926 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1927 LOGD("set video param : visible %d", visible);
1931 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1933 MMHandleType attrs = 0;
1934 int display_method = 0;
1937 /* check video sinkbin is created */
1938 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1941 attrs = MMPLAYER_GET_ATTRS(player);
1942 MMPLAYER_RETURN_IF_FAIL(attrs);
1944 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1945 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1946 LOGD("set video param : method %d", display_method);
1950 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1952 MMHandleType attrs = 0;
1953 void *handle = NULL;
1956 /* check video sinkbin is created */
1957 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1958 LOGW("There is no video sink");
1962 attrs = MMPLAYER_GET_ATTRS(player);
1963 MMPLAYER_RETURN_IF_FAIL(attrs);
1964 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1966 gst_video_overlay_set_video_roi_area(
1967 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1968 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1969 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1970 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1975 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1977 MMHandleType attrs = 0;
1978 void *handle = NULL;
1982 int win_roi_width = 0;
1983 int win_roi_height = 0;
1986 /* check video sinkbin is created */
1987 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1988 LOGW("There is no video sink");
1992 attrs = MMPLAYER_GET_ATTRS(player);
1993 MMPLAYER_RETURN_IF_FAIL(attrs);
1995 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1998 /* It should be set after setting window */
1999 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
2000 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
2001 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
2002 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2004 /* After setting window handle, set display roi area */
2005 gst_video_overlay_set_display_roi_area(
2006 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2007 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2008 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2009 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2014 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2016 MMHandleType attrs = 0;
2017 void *handle = NULL;
2019 /* check video sinkbin is created */
2020 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2023 attrs = MMPLAYER_GET_ATTRS(player);
2024 MMPLAYER_RETURN_IF_FAIL(attrs);
2026 /* common case if using overlay surface */
2027 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2030 /* default is using wl_surface_id */
2031 unsigned int wl_surface_id = 0;
2032 wl_surface_id = *(int *)handle;
2033 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2034 gst_video_overlay_set_wl_window_wl_surface_id(
2035 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2038 /* FIXIT : is it error case? */
2039 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2044 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2046 gboolean update_all_param = FALSE;
2049 /* check video sinkbin is created */
2050 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2051 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2053 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2054 LOGE("can not find tizenwlsink");
2055 return MM_ERROR_PLAYER_INTERNAL;
2058 LOGD("param_name : %s", param_name);
2059 if (!g_strcmp0(param_name, "update_all_param"))
2060 update_all_param = TRUE;
2062 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2063 __mmplayer_video_param_set_display_overlay(player);
2064 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2065 __mmplayer_video_param_set_display_method(player);
2066 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2067 __mmplayer_video_param_set_display_visible(player);
2068 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2069 __mmplayer_video_param_set_display_rotation(player);
2070 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2071 __mmplayer_video_param_set_roi_area(player);
2072 if (update_all_param)
2073 __mmplayer_video_param_set_video_roi_area(player);
2075 return MM_ERROR_NONE;
2079 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2081 MMHandleType attrs = 0;
2082 int surface_type = 0;
2083 int ret = MM_ERROR_NONE;
2087 /* check video sinkbin is created */
2088 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2089 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2091 attrs = MMPLAYER_GET_ATTRS(player);
2093 LOGE("cannot get content attribute");
2094 return MM_ERROR_PLAYER_INTERNAL;
2096 LOGD("param_name : %s", param_name);
2098 /* update display surface */
2099 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2100 LOGD("check display surface type attribute: %d", surface_type);
2102 /* configuring display */
2103 switch (surface_type) {
2104 case MM_DISPLAY_SURFACE_OVERLAY:
2106 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2107 if (ret != MM_ERROR_NONE)
2115 return MM_ERROR_NONE;
2119 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2121 gboolean disable_overlay = FALSE;
2122 mmplayer_t *player = (mmplayer_t *)hplayer;
2125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2126 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2127 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2128 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2130 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2131 LOGW("Display control is not supported");
2132 return MM_ERROR_PLAYER_INTERNAL;
2135 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2137 if (audio_only == (bool)disable_overlay) {
2138 LOGE("It's the same with current setting: (%d)", audio_only);
2139 return MM_ERROR_NONE;
2143 LOGE("disable overlay");
2144 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2146 /* release overlay resource */
2147 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2148 LOGE("failed to release overlay resource");
2152 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2153 LOGE("failed to acquire video overlay resource");
2156 player->interrupted_by_resource = FALSE;
2158 LOGD("enable overlay");
2159 __mmplayer_video_param_set_display_overlay(player);
2160 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2165 return MM_ERROR_NONE;
2169 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2171 mmplayer_t *player = (mmplayer_t *)hplayer;
2172 gboolean disable_overlay = FALSE;
2176 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2177 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2178 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2179 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2180 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2182 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2183 LOGW("Display control is not supported");
2184 return MM_ERROR_PLAYER_INTERNAL;
2187 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2189 *paudio_only = (bool)disable_overlay;
2191 LOGD("audio_only : %d", *paudio_only);
2195 return MM_ERROR_NONE;
2199 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2201 GList *bucket = element_bucket;
2202 mmplayer_gst_element_t *element = NULL;
2203 mmplayer_gst_element_t *prv_element = NULL;
2204 GstElement *tee_element = NULL;
2205 gint successful_link_count = 0;
2209 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2211 prv_element = (mmplayer_gst_element_t *)bucket->data;
2212 bucket = bucket->next;
2214 for (; bucket; bucket = bucket->next) {
2215 element = (mmplayer_gst_element_t *)bucket->data;
2217 if (element && element->gst) {
2218 if (prv_element && prv_element->gst) {
2219 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2221 prv_element->gst = tee_element;
2223 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2224 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2225 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2229 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2230 LOGD("linking [%s] to [%s] success",
2231 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2232 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2233 successful_link_count++;
2234 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2235 LOGD("keep audio-tee element for next audio pipeline branch");
2236 tee_element = prv_element->gst;
2239 LOGD("linking [%s] to [%s] failed",
2240 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2241 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2247 prv_element = element;
2252 return successful_link_count;
2256 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2258 GList *bucket = element_bucket;
2259 mmplayer_gst_element_t *element = NULL;
2260 int successful_add_count = 0;
2264 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2265 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2267 for (; bucket; bucket = bucket->next) {
2268 element = (mmplayer_gst_element_t *)bucket->data;
2270 if (element && element->gst) {
2271 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2272 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2273 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2274 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2277 successful_add_count++;
2283 return successful_add_count;
2287 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2289 mmplayer_t *player = (mmplayer_t *)data;
2290 GstCaps *caps = NULL;
2291 GstStructure *str = NULL;
2293 gboolean caps_ret = TRUE;
2297 MMPLAYER_RETURN_IF_FAIL(pad);
2298 MMPLAYER_RETURN_IF_FAIL(unused);
2299 MMPLAYER_RETURN_IF_FAIL(data);
2301 caps = gst_pad_get_current_caps(pad);
2305 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2309 LOGD("name = %s", name);
2311 if (strstr(name, "audio")) {
2312 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2314 if (player->audio_stream_changed_cb) {
2315 LOGE("call the audio stream changed cb");
2316 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2318 } else if (strstr(name, "video")) {
2319 if ((name = gst_structure_get_string(str, "format")))
2320 player->set_mode.video_zc = name[0] == 'S';
2322 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2323 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2325 LOGW("invalid caps info");
2330 gst_caps_unref(caps);
2338 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2343 MMPLAYER_RETURN_IF_FAIL(player);
2345 if (player->audio_stream_buff_list) {
2346 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2347 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2350 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2351 __mmplayer_audio_stream_send_data(player, tmp);
2353 MMPLAYER_FREEIF(tmp->pcm_data);
2354 MMPLAYER_FREEIF(tmp);
2357 g_list_free(player->audio_stream_buff_list);
2358 player->audio_stream_buff_list = NULL;
2365 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2367 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2370 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2372 audio_stream.bitrate = a_buffer->bitrate;
2373 audio_stream.channel = a_buffer->channel;
2374 audio_stream.depth = a_buffer->depth;
2375 audio_stream.is_little_endian = a_buffer->is_little_endian;
2376 audio_stream.channel_mask = a_buffer->channel_mask;
2377 audio_stream.data_size = a_buffer->data_size;
2378 audio_stream.data = a_buffer->pcm_data;
2379 audio_stream.pcm_format = a_buffer->pcm_format;
2381 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2382 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2388 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2390 mmplayer_t *player = (mmplayer_t *)data;
2391 const gchar *pcm_format = NULL;
2395 gint endianness = 0;
2396 guint64 channel_mask = 0;
2397 void *a_data = NULL;
2399 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2400 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2404 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2406 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2407 a_data = mapinfo.data;
2408 a_size = mapinfo.size;
2410 GstCaps *caps = gst_pad_get_current_caps(pad);
2411 GstStructure *structure = gst_caps_get_structure(caps, 0);
2413 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2414 pcm_format = gst_structure_get_string(structure, "format");
2415 gst_structure_get_int(structure, "rate", &rate);
2416 gst_structure_get_int(structure, "channels", &channel);
2417 gst_structure_get_int(structure, "depth", &depth);
2418 gst_structure_get_int(structure, "endianness", &endianness);
2419 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2420 gst_caps_unref(GST_CAPS(caps));
2422 /* In case of the sync is false, use buffer list. *
2423 * The num of buffer list depends on the num of audio channels */
2424 if (player->audio_stream_buff_list) {
2425 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2426 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2428 if (channel_mask == tmp->channel_mask) {
2429 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2430 if (tmp->data_size + a_size < tmp->buff_size) {
2431 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2432 tmp->data_size += a_size;
2434 /* send data to client */
2435 __mmplayer_audio_stream_send_data(player, tmp);
2437 if (a_size > tmp->buff_size) {
2438 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2439 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2440 if (tmp->pcm_data == NULL) {
2441 LOGE("failed to realloc data.");
2444 tmp->buff_size = a_size;
2446 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2447 memcpy(tmp->pcm_data, a_data, a_size);
2448 tmp->data_size = a_size;
2453 LOGE("data is empty in list.");
2459 /* create new audio stream data for newly found audio channel */
2460 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2461 if (a_buffer == NULL) {
2462 LOGE("failed to alloc data.");
2465 a_buffer->bitrate = rate;
2466 a_buffer->channel = channel;
2467 a_buffer->depth = depth;
2468 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2469 a_buffer->channel_mask = channel_mask;
2470 a_buffer->data_size = a_size;
2471 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2473 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2474 /* If sync is FALSE, use buffer list to reduce the IPC. */
2475 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2476 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2477 if (a_buffer->pcm_data == NULL) {
2478 LOGE("failed to alloc data.");
2479 MMPLAYER_FREEIF(a_buffer);
2482 memcpy(a_buffer->pcm_data, a_data, a_size);
2483 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2484 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2486 /* If sync is TRUE, send data directly. */
2487 a_buffer->pcm_data = a_data;
2488 __mmplayer_audio_stream_send_data(player, a_buffer);
2489 MMPLAYER_FREEIF(a_buffer);
2493 gst_buffer_unmap(buffer, &mapinfo);
2498 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2500 mmplayer_t *player = (mmplayer_t *)data;
2501 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2502 GstPad *sinkpad = NULL;
2503 GstElement *queue = NULL, *sink = NULL;
2506 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2508 queue = gst_element_factory_make("queue", NULL);
2509 if (queue == NULL) {
2510 LOGD("fail make queue");
2514 sink = gst_element_factory_make("fakesink", NULL);
2516 LOGD("fail make fakesink");
2520 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2522 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2523 LOGW("failed to link queue & sink");
2527 sinkpad = gst_element_get_static_pad(queue, "sink");
2529 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2530 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2534 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2536 gst_object_unref(sinkpad);
2537 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2538 g_object_set(sink, "sync", TRUE, NULL);
2539 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2541 /* keep the first sink reference only */
2542 if (!audiobin[MMPLAYER_A_SINK].gst) {
2543 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2544 audiobin[MMPLAYER_A_SINK].gst = sink;
2547 gst_element_set_state(sink, GST_STATE_PAUSED);
2548 gst_element_set_state(queue, GST_STATE_PAUSED);
2550 _mmplayer_add_signal_connection(player,
2552 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2554 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2557 __mmplayer_add_sink(player, sink);
2563 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2565 gst_object_unref(GST_OBJECT(queue));
2569 gst_object_unref(GST_OBJECT(sink));
2573 gst_object_unref(GST_OBJECT(sinkpad));
2581 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2583 #define MAX_PROPS_LEN 128
2584 mmplayer_gst_element_t *audiobin = NULL;
2585 gint latency_mode = 0;
2586 gchar *stream_type = NULL;
2587 gchar *latency = NULL;
2589 gchar stream_props[MAX_PROPS_LEN] = {0,};
2590 GstStructure *props = NULL;
2593 * It should be set after player creation through attribute.
2594 * But, it can not be changed during playing.
2597 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2599 audiobin = player->pipeline->audiobin;
2601 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2602 if (player->sound.mute) {
2603 LOGD("mute enabled");
2604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2607 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2608 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2611 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2613 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2614 stream_type, stream_id, player->client_pid);
2616 props = gst_structure_from_string(stream_props, NULL);
2617 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2618 LOGI("props result[%s].", stream_props);
2619 gst_structure_free(props);
2621 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2623 switch (latency_mode) {
2624 case AUDIO_LATENCY_MODE_LOW:
2625 latency = g_strndup("low", 3);
2627 case AUDIO_LATENCY_MODE_MID:
2628 latency = g_strndup("mid", 3);
2630 case AUDIO_LATENCY_MODE_HIGH:
2631 latency = g_strndup("high", 4);
2635 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2637 LOGD("audiosink property - latency=%s", latency);
2639 MMPLAYER_FREEIF(latency);
2645 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2647 mmplayer_gst_element_t *audiobin = NULL;
2650 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2652 audiobin = player->pipeline->audiobin;
2654 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2655 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2658 if (player->video360_yaw_radians <= M_PI &&
2659 player->video360_yaw_radians >= -M_PI &&
2660 player->video360_pitch_radians <= M_PI_2 &&
2661 player->video360_pitch_radians >= -M_PI_2) {
2662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2663 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2664 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2665 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2667 "source-orientation-y", player->video360_metadata.init_view_heading,
2668 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2675 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2677 mmplayer_gst_element_t *audiobin = NULL;
2678 GstPad *sink_pad = NULL;
2679 GstCaps *acaps = NULL;
2681 int pitch_control = 0;
2682 double pitch_value = 1.0;
2685 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2686 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2688 audiobin = player->pipeline->audiobin;
2690 LOGD("make element for normal audio playback");
2692 /* audio bin structure for playback. {} means optional.
2693 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2695 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2696 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2699 /* for pitch control */
2700 mm_attrs_multiple_get(player->attrs, NULL,
2701 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2702 MM_PLAYER_PITCH_VALUE, &pitch_value,
2705 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2706 if (pitch_control && (player->videodec_linked == 0)) {
2707 GstElementFactory *factory;
2709 factory = gst_element_factory_find("pitch");
2711 gst_object_unref(factory);
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2720 LOGW("there is no pitch element");
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2727 /* replaygain volume */
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2729 if (player->sound.rg_enable)
2730 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2735 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2737 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2738 /* currently, only openalsink uses volume element */
2739 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2740 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2742 if (player->sound.mute) {
2743 LOGD("mute enabled");
2744 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2748 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2750 /* audio effect element. if audio effect is enabled */
2751 if ((strcmp(player->ini.audioeffect_element, ""))
2753 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2754 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2756 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2758 if ((!player->bypass_audio_effect)
2759 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2760 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2761 if (!_mmplayer_audio_effect_custom_apply(player))
2762 LOGI("apply audio effect(custom) setting success");
2766 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2767 && (player->set_mode.rich_audio)) {
2768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2772 /* create audio sink */
2773 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2774 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2775 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2777 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2778 if (player->is_360_feature_enabled &&
2779 player->is_content_spherical &&
2781 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2782 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2783 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2785 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2787 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2789 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2790 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2791 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2792 gst_caps_unref(acaps);
2794 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2796 player->is_openal_plugin_used = TRUE;
2798 if (player->is_360_feature_enabled && player->is_content_spherical)
2799 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2800 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2803 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2804 (player->videodec_linked && player->ini.use_system_clock)) {
2805 LOGD("system clock will be used.");
2806 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2809 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2810 __mmplayer_gst_set_pulsesink_property(player);
2811 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2812 __mmplayer_gst_set_openalsink_property(player);
2815 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2816 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2818 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2819 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2820 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2821 gst_object_unref(GST_OBJECT(sink_pad));
2823 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2826 return MM_ERROR_NONE;
2828 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2830 return MM_ERROR_PLAYER_INTERNAL;
2834 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2836 mmplayer_gst_element_t *audiobin = NULL;
2837 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2839 gchar *dst_format = NULL;
2841 int dst_samplerate = 0;
2842 int dst_channels = 0;
2843 GstCaps *caps = NULL;
2844 char *caps_str = NULL;
2847 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2848 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2850 audiobin = player->pipeline->audiobin;
2852 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2854 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2856 [case 1] extract interleave audio pcm without playback
2857 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2858 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2860 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2862 [case 2] deinterleave for each channel without playback
2863 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2864 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2866 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2867 - fakesink (sync or not)
2870 [case 3] [case 1(sync only)] + playback
2871 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2873 * src - ... - tee - queue1 - playback path
2874 - queue2 - [case1 pipeline with sync]
2876 [case 4] [case 2(sync only)] + playback
2877 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2879 * src - ... - tee - queue1 - playback path
2880 - queue2 - [case2 pipeline with sync]
2884 /* 1. create tee and playback path
2885 'tee' should be added at first to copy the decoded stream
2887 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2888 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2889 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2891 /* tee - path 1 : for playback path */
2892 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2893 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2895 /* tee - path 2 : for extract path */
2896 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2897 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2900 /* if there is tee, 'tee - path 2' is linked here */
2902 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2905 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2907 /* 2. decide the extract pcm format */
2908 mm_attrs_multiple_get(player->attrs, NULL,
2909 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2910 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2911 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2914 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2915 dst_format, dst_len, dst_samplerate, dst_channels);
2917 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2918 mm_attrs_multiple_get(player->attrs, NULL,
2919 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2920 "content_audio_samplerate", &dst_samplerate,
2921 "content_audio_channels", &dst_channels,
2924 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2925 dst_format, dst_len, dst_samplerate, dst_channels);
2927 /* If there is no enough information, set it to platform default value. */
2928 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2929 LOGD("set platform default format");
2930 dst_format = DEFAULT_PCM_OUT_FORMAT;
2932 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2933 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2936 /* 3. create capsfilter */
2937 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2938 caps = gst_caps_new_simple("audio/x-raw",
2939 "format", G_TYPE_STRING, dst_format,
2940 "rate", G_TYPE_INT, dst_samplerate,
2941 "channels", G_TYPE_INT, dst_channels,
2944 caps_str = gst_caps_to_string(caps);
2945 LOGD("new caps : %s", caps_str);
2947 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2950 gst_caps_unref(caps);
2951 MMPLAYER_FREEIF(caps_str);
2953 /* 4-1. create deinterleave to extract pcm for each channel */
2954 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2955 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2956 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2958 /* audiosink will be added after getting signal for each channel */
2959 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2960 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2962 /* 4-2. create fakesink to extract interlevaed pcm */
2963 LOGD("add audio fakesink for interleaved audio");
2964 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2965 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2966 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2967 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2969 _mmplayer_add_signal_connection(player,
2970 G_OBJECT(audiobin[extract_sink_id].gst),
2971 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2973 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2976 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2980 return MM_ERROR_NONE;
2982 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2984 return MM_ERROR_PLAYER_INTERNAL;
2988 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2990 int ret = MM_ERROR_NONE;
2991 mmplayer_gst_element_t *audiobin = NULL;
2992 GList *element_bucket = NULL;
2995 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2996 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2998 audiobin = player->pipeline->audiobin;
3000 if (player->build_audio_offload) { /* skip all the audio filters */
3001 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3003 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3004 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3005 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3007 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3011 /* FIXME: need to mention the supportable condition at API reference */
3012 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3013 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3015 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3017 if (ret != MM_ERROR_NONE)
3020 LOGD("success to make audio bin element");
3021 *bucket = element_bucket;
3024 return MM_ERROR_NONE;
3027 LOGE("failed to make audio bin element");
3028 g_list_free(element_bucket);
3032 return MM_ERROR_PLAYER_INTERNAL;
3036 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3038 mmplayer_gst_element_t *first_element = NULL;
3039 mmplayer_gst_element_t *audiobin = NULL;
3041 GstPad *ghostpad = NULL;
3042 GList *element_bucket = NULL;
3046 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3049 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3051 LOGE("failed to allocate memory for audiobin");
3052 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3056 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3057 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3058 if (!audiobin[MMPLAYER_A_BIN].gst) {
3059 LOGE("failed to create audiobin");
3064 player->pipeline->audiobin = audiobin;
3066 /* create audio filters and audiosink */
3067 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3070 /* adding created elements to bin */
3071 LOGD("adding created elements to bin");
3072 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3075 /* linking elements in the bucket by added order. */
3076 LOGD("Linking elements in the bucket by added order.");
3077 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3080 /* get first element's sinkpad for creating ghostpad */
3081 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3082 if (!first_element) {
3083 LOGE("failed to get first elem");
3087 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3089 LOGE("failed to get pad from first element of audiobin");
3093 ghostpad = gst_ghost_pad_new("sink", pad);
3095 LOGE("failed to create ghostpad");
3099 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3100 LOGE("failed to add ghostpad to audiobin");
3104 gst_object_unref(pad);
3106 g_list_free(element_bucket);
3109 return MM_ERROR_NONE;
3112 LOGD("ERROR : releasing audiobin");
3115 gst_object_unref(GST_OBJECT(pad));
3118 gst_object_unref(GST_OBJECT(ghostpad));
3121 g_list_free(element_bucket);
3123 /* release element which are not added to bin */
3124 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3125 /* NOTE : skip bin */
3126 if (audiobin[i].gst) {
3127 GstObject *parent = NULL;
3128 parent = gst_element_get_parent(audiobin[i].gst);
3131 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3132 audiobin[i].gst = NULL;
3134 gst_object_unref(GST_OBJECT(parent));
3138 /* release audiobin with it's childs */
3139 if (audiobin[MMPLAYER_A_BIN].gst)
3140 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3142 MMPLAYER_FREEIF(audiobin);
3144 player->pipeline->audiobin = NULL;
3146 return MM_ERROR_PLAYER_INTERNAL;
3150 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3152 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3156 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3158 int ret = MM_ERROR_NONE;
3160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3161 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3163 MMPLAYER_VIDEO_BO_LOCK(player);
3165 if (player->video_bo_list) {
3166 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3167 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3168 if (tmp && tmp->bo == bo) {
3170 LOGD("release bo %p", bo);
3171 tbm_bo_unref(tmp->bo);
3172 MMPLAYER_VIDEO_BO_UNLOCK(player);
3173 MMPLAYER_VIDEO_BO_SIGNAL(player);
3178 /* hw codec is running or the list was reset for DRC. */
3179 LOGW("there is no bo list.");
3181 MMPLAYER_VIDEO_BO_UNLOCK(player);
3183 LOGW("failed to find bo %p", bo);
3188 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3193 MMPLAYER_RETURN_IF_FAIL(player);
3195 MMPLAYER_VIDEO_BO_LOCK(player);
3196 if (player->video_bo_list) {
3197 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3198 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3199 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3202 tbm_bo_unref(tmp->bo);
3206 g_list_free(player->video_bo_list);
3207 player->video_bo_list = NULL;
3209 player->video_bo_size = 0;
3210 MMPLAYER_VIDEO_BO_UNLOCK(player);
3217 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3220 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3221 gboolean ret = TRUE;
3223 /* check DRC, if it is, destroy the prev bo list to create again */
3224 if (player->video_bo_size != size) {
3225 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3226 __mmplayer_video_stream_destroy_bo_list(player);
3227 player->video_bo_size = size;
3230 MMPLAYER_VIDEO_BO_LOCK(player);
3232 if ((!player->video_bo_list) ||
3233 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3235 /* create bo list */
3237 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3239 if (player->video_bo_list) {
3240 /* if bo list did not created all, try it again. */
3241 idx = g_list_length(player->video_bo_list);
3242 LOGD("bo list exist(len: %d)", idx);
3245 for (; idx < player->ini.num_of_video_bo; idx++) {
3246 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3248 LOGE("Fail to alloc bo_info.");
3251 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3253 LOGE("Fail to tbm_bo_alloc.");
3254 MMPLAYER_FREEIF(bo_info);
3257 bo_info->used = FALSE;
3258 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3261 /* update video num buffers */
3262 LOGD("video_num_buffers : %d", idx);
3263 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3264 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3267 MMPLAYER_VIDEO_BO_UNLOCK(player);
3273 /* get bo from list*/
3274 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3275 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3276 if (tmp && (tmp->used == FALSE)) {
3277 LOGD("found bo %p to use", tmp->bo);
3279 MMPLAYER_VIDEO_BO_UNLOCK(player);
3280 return tbm_bo_ref(tmp->bo);
3284 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3285 MMPLAYER_VIDEO_BO_UNLOCK(player);
3289 if (player->ini.video_bo_timeout <= 0) {
3290 MMPLAYER_VIDEO_BO_WAIT(player);
3292 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3293 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3300 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3302 mmplayer_t *player = (mmplayer_t *)data;
3304 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3306 /* send prerolled pkt */
3307 player->video_stream_prerolled = false;
3309 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3311 /* not to send prerolled pkt again */
3312 player->video_stream_prerolled = true;
3316 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3318 mmplayer_t *player = (mmplayer_t *)data;
3319 mmplayer_video_decoded_data_info_t *stream = NULL;
3320 GstMemory *mem = NULL;
3323 MMPLAYER_RETURN_IF_FAIL(player);
3324 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3326 if (player->video_stream_prerolled) {
3327 player->video_stream_prerolled = false;
3328 LOGD("skip the prerolled pkt not to send it again");
3332 /* clear stream data structure */
3333 stream = __mmplayer_create_stream_from_pad(pad);
3335 LOGE("failed to alloc stream");
3339 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3341 /* set size and timestamp */
3342 mem = gst_buffer_peek_memory(buffer, 0);
3343 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3344 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3346 /* check zero-copy */
3347 if (player->set_mode.video_zc &&
3348 player->set_mode.video_export &&
3349 gst_is_tizen_memory(mem)) {
3350 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3351 stream->internal_buffer = gst_buffer_ref(buffer);
3352 } else { /* sw codec */
3353 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3356 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3360 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3361 LOGE("failed to send video decoded data.");
3368 LOGE("release video stream resource.");
3369 if (gst_is_tizen_memory(mem)) {
3371 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3373 tbm_bo_unref(stream->bo[i]);
3376 /* unref gst buffer */
3377 if (stream->internal_buffer)
3378 gst_buffer_unref(stream->internal_buffer);
3381 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3383 MMPLAYER_FREEIF(stream);
3388 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3390 mmplayer_gst_element_t *videobin = NULL;
3393 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3395 videobin = player->pipeline->videobin;
3397 /* Set spatial media metadata and/or user settings to the element.
3399 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3400 "projection-type", player->video360_metadata.projection_type, NULL);
3402 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3403 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3405 if (player->video360_metadata.full_pano_width_pixels &&
3406 player->video360_metadata.full_pano_height_pixels &&
3407 player->video360_metadata.cropped_area_image_width &&
3408 player->video360_metadata.cropped_area_image_height) {
3409 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3410 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3411 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3412 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3413 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3414 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3415 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3419 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3420 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3421 "horizontal-fov", player->video360_horizontal_fov,
3422 "vertical-fov", player->video360_vertical_fov, NULL);
3425 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3426 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3427 "zoom", 1.0f / player->video360_zoom, NULL);
3430 if (player->video360_yaw_radians <= M_PI &&
3431 player->video360_yaw_radians >= -M_PI &&
3432 player->video360_pitch_radians <= M_PI_2 &&
3433 player->video360_pitch_radians >= -M_PI_2) {
3434 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3435 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3436 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3437 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3438 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3439 "pose-yaw", player->video360_metadata.init_view_heading,
3440 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3443 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3444 "passthrough", !player->is_video360_enabled, NULL);
3451 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3453 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3454 GList *element_bucket = NULL;
3457 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3459 /* create video360 filter */
3460 if (player->is_360_feature_enabled && player->is_content_spherical) {
3461 LOGD("create video360 element");
3462 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3463 __mmplayer_gst_set_video360_property(player);
3467 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3468 LOGD("skip creating the videoconv and rotator");
3469 return MM_ERROR_NONE;
3472 /* in case of sw codec & overlay surface type, except 360 playback.
3473 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3474 LOGD("create video converter: %s", video_csc);
3475 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3478 *bucket = element_bucket;
3480 return MM_ERROR_NONE;
3482 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3483 g_list_free(element_bucket);
3487 return MM_ERROR_PLAYER_INTERNAL;
3491 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3493 gchar *factory_name = NULL;
3495 switch (surface_type) {
3496 case MM_DISPLAY_SURFACE_OVERLAY:
3497 if (strlen(player->ini.videosink_element_overlay) > 0)
3498 factory_name = player->ini.videosink_element_overlay;
3500 case MM_DISPLAY_SURFACE_REMOTE:
3501 case MM_DISPLAY_SURFACE_NULL:
3502 if (strlen(player->ini.videosink_element_fake) > 0)
3503 factory_name = player->ini.videosink_element_fake;
3506 LOGE("unidentified surface type");
3510 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3511 return factory_name;
3515 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3517 gchar *factory_name = NULL;
3518 mmplayer_gst_element_t *videobin = NULL;
3523 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3525 videobin = player->pipeline->videobin;
3526 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3528 attrs = MMPLAYER_GET_ATTRS(player);
3530 LOGE("cannot get content attribute");
3531 return MM_ERROR_PLAYER_INTERNAL;
3534 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3535 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3536 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3538 /* support shard memory with S/W codec on HawkP */
3539 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3540 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3541 "use-tbm", use_tbm, NULL);
3545 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3546 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3549 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3551 LOGD("disable last-sample");
3552 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3555 if (player->set_mode.video_export) {
3557 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3558 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3559 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3561 _mmplayer_add_signal_connection(player,
3562 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3563 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3565 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3568 _mmplayer_add_signal_connection(player,
3569 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3570 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3572 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3576 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3577 return MM_ERROR_PLAYER_INTERNAL;
3579 if (videobin[MMPLAYER_V_SINK].gst) {
3580 GstPad *sink_pad = NULL;
3581 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3583 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3584 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3585 gst_object_unref(GST_OBJECT(sink_pad));
3587 LOGE("failed to get sink pad from videosink");
3591 return MM_ERROR_NONE;
3596 * - video overlay surface(arm/x86) : tizenwlsink
3599 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3602 GList *element_bucket = NULL;
3603 mmplayer_gst_element_t *first_element = NULL;
3604 mmplayer_gst_element_t *videobin = NULL;
3605 gchar *videosink_factory_name = NULL;
3608 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3611 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3613 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3615 player->pipeline->videobin = videobin;
3618 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3619 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3620 if (!videobin[MMPLAYER_V_BIN].gst) {
3621 LOGE("failed to create videobin");
3625 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3628 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3629 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3631 /* additional setting for sink plug-in */
3632 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3633 LOGE("failed to set video property");
3637 /* store it as it's sink element */
3638 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3640 /* adding created elements to bin */
3641 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3642 LOGE("failed to add elements");
3646 /* Linking elements in the bucket by added order */
3647 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3648 LOGE("failed to link elements");
3652 /* get first element's sinkpad for creating ghostpad */
3653 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3654 if (!first_element) {
3655 LOGE("failed to get first element from bucket");
3659 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3661 LOGE("failed to get pad from first element");
3665 /* create ghostpad */
3666 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3667 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3668 LOGE("failed to add ghostpad to videobin");
3671 gst_object_unref(pad);
3673 /* done. free allocated variables */
3674 g_list_free(element_bucket);
3678 return MM_ERROR_NONE;
3681 LOGE("ERROR : releasing videobin");
3682 g_list_free(element_bucket);
3685 gst_object_unref(GST_OBJECT(pad));
3687 /* release videobin with it's childs */
3688 if (videobin[MMPLAYER_V_BIN].gst)
3689 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3691 MMPLAYER_FREEIF(videobin);
3692 player->pipeline->videobin = NULL;
3694 return MM_ERROR_PLAYER_INTERNAL;
3698 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3700 GList *element_bucket = NULL;
3701 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3703 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3704 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3705 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3706 "signal-handoffs", FALSE,
3709 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3710 _mmplayer_add_signal_connection(player,
3711 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3712 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3714 G_CALLBACK(__mmplayer_update_subtitle),
3717 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3718 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3720 if (!player->play_subtitle) {
3721 LOGD("add textbin sink as sink element of whole pipeline.");
3722 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3725 /* adding created elements to bin */
3726 LOGD("adding created elements to bin");
3727 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3728 LOGE("failed to add elements");
3732 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3733 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3734 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3736 /* linking elements in the bucket by added order. */
3737 LOGD("Linking elements in the bucket by added order.");
3738 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3739 LOGE("failed to link elements");
3743 /* done. free allocated variables */
3744 g_list_free(element_bucket);
3746 if (textbin[MMPLAYER_T_QUEUE].gst) {
3748 GstPad *ghostpad = NULL;
3750 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3752 LOGE("failed to get sink pad of text queue");
3756 ghostpad = gst_ghost_pad_new("text_sink", pad);
3757 gst_object_unref(pad);
3760 LOGE("failed to create ghostpad of textbin");
3764 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3765 LOGE("failed to add ghostpad to textbin");
3766 gst_object_unref(ghostpad);
3771 return MM_ERROR_NONE;
3774 g_list_free(element_bucket);
3776 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3777 LOGE("remove textbin sink from sink list");
3778 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3781 /* release element at __mmplayer_gst_create_text_sink_bin */
3782 return MM_ERROR_PLAYER_INTERNAL;
3786 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3788 mmplayer_gst_element_t *textbin = NULL;
3789 GList *element_bucket = NULL;
3790 int surface_type = 0;
3795 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3798 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3800 LOGE("failed to allocate memory for textbin");
3801 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3805 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3806 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3807 if (!textbin[MMPLAYER_T_BIN].gst) {
3808 LOGE("failed to create textbin");
3813 player->pipeline->textbin = textbin;
3816 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3817 LOGD("surface type for subtitle : %d", surface_type);
3818 switch (surface_type) {
3819 case MM_DISPLAY_SURFACE_OVERLAY:
3820 case MM_DISPLAY_SURFACE_NULL:
3821 case MM_DISPLAY_SURFACE_REMOTE:
3822 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3823 LOGE("failed to make plain text elements");
3834 return MM_ERROR_NONE;
3838 LOGD("ERROR : releasing textbin");
3840 g_list_free(element_bucket);
3842 /* release signal */
3843 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3845 /* release element which are not added to bin */
3846 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3847 /* NOTE : skip bin */
3848 if (textbin[i].gst) {
3849 GstObject *parent = NULL;
3850 parent = gst_element_get_parent(textbin[i].gst);
3853 gst_object_unref(GST_OBJECT(textbin[i].gst));
3854 textbin[i].gst = NULL;
3856 gst_object_unref(GST_OBJECT(parent));
3861 /* release textbin with it's childs */
3862 if (textbin[MMPLAYER_T_BIN].gst)
3863 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3865 MMPLAYER_FREEIF(player->pipeline->textbin);
3866 player->pipeline->textbin = NULL;
3869 return MM_ERROR_PLAYER_INTERNAL;
3873 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3875 mmplayer_gst_element_t *mainbin = NULL;
3876 mmplayer_gst_element_t *textbin = NULL;
3877 MMHandleType attrs = 0;
3878 GstElement *subsrc = NULL;
3879 GstElement *subparse = NULL;
3880 gchar *subtitle_uri = NULL;
3881 const gchar *charset = NULL;
3887 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3889 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3891 mainbin = player->pipeline->mainbin;
3893 attrs = MMPLAYER_GET_ATTRS(player);
3895 LOGE("cannot get content attribute");
3896 return MM_ERROR_PLAYER_INTERNAL;
3899 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3900 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3901 LOGE("subtitle uri is not proper filepath.");
3902 return MM_ERROR_PLAYER_INVALID_URI;
3905 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3906 LOGE("failed to get storage info of subtitle path");
3907 return MM_ERROR_PLAYER_INVALID_URI;
3910 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3912 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3913 player->subtitle_language_list = NULL;
3914 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3916 /* create the subtitle source */
3917 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3919 LOGE("failed to create filesrc element");
3922 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3924 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3925 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3927 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3928 LOGW("failed to add queue");
3929 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3930 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3931 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3936 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3938 LOGE("failed to create subparse element");
3942 charset = _mmplayer_get_charset(subtitle_uri);
3944 LOGD("detected charset is %s", charset);
3945 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3948 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3949 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3951 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3952 LOGW("failed to add subparse");
3953 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3954 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3955 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3959 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3960 LOGW("failed to link subsrc and subparse");
3964 player->play_subtitle = TRUE;
3965 player->adjust_subtitle_pos = 0;
3967 LOGD("play subtitle using subtitle file");
3969 if (player->pipeline->textbin == NULL) {
3970 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3971 LOGE("failed to create text sink bin. continuing without text");
3975 textbin = player->pipeline->textbin;
3977 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3978 LOGW("failed to add textbin");
3980 /* release signal */
3981 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3983 /* release textbin with it's childs */
3984 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3985 MMPLAYER_FREEIF(player->pipeline->textbin);
3986 player->pipeline->textbin = textbin = NULL;
3990 LOGD("link text input selector and textbin ghost pad");
3992 player->textsink_linked = 1;
3993 player->external_text_idx = 0;
3994 LOGI("textsink is linked");
3996 textbin = player->pipeline->textbin;
3997 LOGD("text bin has been created. reuse it.");
3998 player->external_text_idx = 1;
4001 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4002 LOGW("failed to link subparse and textbin");
4006 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4008 LOGE("failed to get sink pad from textsink to probe data");
4012 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4013 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4015 gst_object_unref(pad);
4018 /* create dot. for debugging */
4019 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4022 return MM_ERROR_NONE;
4025 /* release text pipeline resource */
4026 player->textsink_linked = 0;
4028 /* release signal */
4029 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4031 if (player->pipeline->textbin) {
4032 LOGE("remove textbin");
4034 /* release textbin with it's childs */
4035 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4036 MMPLAYER_FREEIF(player->pipeline->textbin);
4037 player->pipeline->textbin = NULL;
4041 /* release subtitle elem */
4042 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4043 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4045 return MM_ERROR_PLAYER_INTERNAL;
4049 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4051 mmplayer_t *player = (mmplayer_t *)data;
4052 MMMessageParamType msg = {0, };
4053 GstClockTime duration = 0;
4054 gpointer text = NULL;
4055 guint text_size = 0;
4056 gboolean ret = TRUE;
4057 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4061 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4062 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4064 if (player->is_subtitle_force_drop) {
4065 LOGW("subtitle is dropped forcedly.");
4069 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4070 text = mapinfo.data;
4071 text_size = mapinfo.size;
4073 if (player->set_mode.subtitle_off) {
4074 LOGD("subtitle is OFF.");
4078 if (!text || (text_size == 0)) {
4079 LOGD("There is no subtitle to be displayed.");
4083 msg.data = (void *)text;
4085 duration = GST_BUFFER_DURATION(buffer);
4087 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4088 if (player->duration > GST_BUFFER_PTS(buffer))
4089 duration = player->duration - GST_BUFFER_PTS(buffer);
4092 LOGI("subtitle duration is invalid, subtitle duration change "
4093 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4095 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4097 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4099 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4100 gst_buffer_unmap(buffer, &mapinfo);
4107 static GstPadProbeReturn
4108 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4110 mmplayer_t *player = (mmplayer_t *)u_data;
4111 GstClockTime cur_timestamp = 0;
4112 gint64 adjusted_timestamp = 0;
4113 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4115 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4117 if (player->set_mode.subtitle_off) {
4118 LOGD("subtitle is OFF.");
4122 if (player->adjust_subtitle_pos == 0) {
4123 LOGD("nothing to do");
4127 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4128 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4130 if (adjusted_timestamp < 0) {
4131 LOGD("adjusted_timestamp under zero");
4136 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4137 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4138 GST_TIME_ARGS(cur_timestamp),
4139 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4141 return GST_PAD_PROBE_OK;
4145 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4149 /* check player and subtitlebin are created */
4150 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4151 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4153 if (position == 0) {
4154 LOGD("nothing to do");
4156 return MM_ERROR_NONE;
4159 /* check current postion */
4160 player->adjust_subtitle_pos = position;
4162 LOGD("save adjust_subtitle_pos in player");
4166 return MM_ERROR_NONE;
4170 * This function is to create audio or video pipeline for playing.
4172 * @param player [in] handle of player
4174 * @return This function returns zero on success.
4179 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4181 int ret = MM_ERROR_NONE;
4182 mmplayer_gst_element_t *mainbin = NULL;
4183 MMHandleType attrs = 0;
4186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4188 /* get profile attribute */
4189 attrs = MMPLAYER_GET_ATTRS(player);
4191 LOGE("failed to get content attribute");
4195 /* create pipeline handles */
4196 if (player->pipeline) {
4197 LOGE("pipeline should be released before create new one");
4201 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4202 if (player->pipeline == NULL)
4205 /* create mainbin */
4206 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4207 if (mainbin == NULL)
4210 /* create pipeline */
4211 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4212 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4213 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4214 LOGE("failed to create pipeline");
4219 player->pipeline->mainbin = mainbin;
4221 /* create the source and decoder elements */
4222 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4223 ret = _mmplayer_gst_build_es_pipeline(player);
4225 ret = _mmplayer_gst_build_pipeline(player);
4227 if (ret != MM_ERROR_NONE) {
4228 LOGE("failed to create some elements");
4232 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4233 if (__mmplayer_check_subtitle(player)
4234 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4235 LOGE("failed to create text pipeline");
4238 ret = _mmplayer_gst_add_bus_watch(player);
4239 if (ret != MM_ERROR_NONE) {
4240 LOGE("failed to add bus watch");
4245 return MM_ERROR_NONE;
4248 __mmplayer_gst_destroy_pipeline(player);
4249 return MM_ERROR_PLAYER_INTERNAL;
4253 __mmplayer_reset_gapless_state(mmplayer_t *player)
4256 MMPLAYER_RETURN_IF_FAIL(player
4258 && player->pipeline->audiobin
4259 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4261 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4268 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4271 int ret = MM_ERROR_NONE;
4275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4277 /* cleanup stuffs */
4278 MMPLAYER_FREEIF(player->type);
4279 player->no_more_pad = FALSE;
4280 player->num_dynamic_pad = 0;
4281 player->demux_pad_index = 0;
4283 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4284 player->subtitle_language_list = NULL;
4285 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4287 __mmplayer_reset_gapless_state(player);
4289 if (player->streamer) {
4290 _mm_player_streaming_initialize(player->streamer, FALSE);
4291 _mm_player_streaming_destroy(player->streamer);
4292 player->streamer = NULL;
4295 /* cleanup unlinked mime type */
4296 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4297 MMPLAYER_FREEIF(player->unlinked_video_mime);
4298 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4300 /* cleanup running stuffs */
4301 _mmplayer_cancel_eos_timer(player);
4303 /* cleanup gst stuffs */
4304 if (player->pipeline) {
4305 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4306 GstTagList *tag_list = player->pipeline->tag_list;
4308 /* first we need to disconnect all signal hander */
4309 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4312 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4313 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4314 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4315 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4316 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4317 gst_object_unref(bus);
4319 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4320 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4321 if (ret != MM_ERROR_NONE) {
4322 LOGE("fail to change state to NULL");
4323 return MM_ERROR_PLAYER_INTERNAL;
4326 LOGW("succeeded in changing state to NULL");
4328 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4331 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4332 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4334 /* free avsysaudiosink
4335 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4336 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4338 MMPLAYER_FREEIF(audiobin);
4339 MMPLAYER_FREEIF(videobin);
4340 MMPLAYER_FREEIF(textbin);
4341 MMPLAYER_FREEIF(mainbin);
4345 gst_tag_list_unref(tag_list);
4347 MMPLAYER_FREEIF(player->pipeline);
4349 MMPLAYER_FREEIF(player->album_art);
4351 if (player->v_stream_caps) {
4352 gst_caps_unref(player->v_stream_caps);
4353 player->v_stream_caps = NULL;
4356 if (player->a_stream_caps) {
4357 gst_caps_unref(player->a_stream_caps);
4358 player->a_stream_caps = NULL;
4361 if (player->s_stream_caps) {
4362 gst_caps_unref(player->s_stream_caps);
4363 player->s_stream_caps = NULL;
4365 _mmplayer_track_destroy(player);
4367 if (player->sink_elements)
4368 g_list_free(player->sink_elements);
4369 player->sink_elements = NULL;
4371 if (player->bufmgr) {
4372 tbm_bufmgr_deinit(player->bufmgr);
4373 player->bufmgr = NULL;
4376 LOGW("finished destroy pipeline");
4384 __mmplayer_gst_realize(mmplayer_t *player)
4387 int ret = MM_ERROR_NONE;
4391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4393 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4395 ret = __mmplayer_gst_create_pipeline(player);
4397 LOGE("failed to create pipeline");
4401 /* set pipeline state to READY */
4402 /* NOTE : state change to READY must be performed sync. */
4403 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4404 ret = _mmplayer_gst_set_state(player,
4405 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4407 if (ret != MM_ERROR_NONE) {
4408 /* return error if failed to set state */
4409 LOGE("failed to set READY state");
4413 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4415 /* create dot before error-return. for debugging */
4416 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4424 __mmplayer_gst_unrealize(mmplayer_t *player)
4426 int ret = MM_ERROR_NONE;
4430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4432 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4433 MMPLAYER_PRINT_STATE(player);
4435 /* release miscellaneous information */
4436 __mmplayer_release_misc(player);
4438 /* destroy pipeline */
4439 ret = __mmplayer_gst_destroy_pipeline(player);
4440 if (ret != MM_ERROR_NONE) {
4441 LOGE("failed to destory pipeline");
4445 /* release miscellaneous information.
4446 these info needs to be released after pipeline is destroyed. */
4447 __mmplayer_release_misc_post(player);
4449 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4457 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4462 LOGW("set_message_callback is called with invalid player handle");
4463 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4466 player->msg_cb = callback;
4467 player->msg_cb_param = user_param;
4469 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4473 return MM_ERROR_NONE;
4477 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4479 int ret = MM_ERROR_NONE;
4484 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4485 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4486 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4488 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4490 if (strstr(uri, "es_buff://")) {
4491 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4492 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4493 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4494 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4496 tmp = g_ascii_strdown(uri, strlen(uri));
4497 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4498 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4500 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4502 } else if (strstr(uri, "mms://")) {
4503 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4504 } else if ((path = strstr(uri, "mem://"))) {
4505 ret = __mmplayer_set_mem_uri(data, path, param);
4507 ret = __mmplayer_set_file_uri(data, uri);
4510 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4511 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4512 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4513 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4515 /* dump parse result */
4516 SECURE_LOGW("incoming uri : %s", uri);
4517 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4518 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4526 __mmplayer_can_do_interrupt(mmplayer_t *player)
4528 if (!player || !player->pipeline || !player->attrs) {
4529 LOGW("not initialized");
4533 if (player->audio_decoded_cb) {
4534 LOGW("not support in pcm extraction mode");
4538 /* check if seeking */
4539 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4540 MMMessageParamType msg_param;
4541 memset(&msg_param, 0, sizeof(MMMessageParamType));
4542 msg_param.code = MM_ERROR_PLAYER_SEEK;
4543 player->seek_state = MMPLAYER_SEEK_NONE;
4544 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4548 /* check other thread */
4549 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4550 LOGW("locked already, cmd state : %d", player->cmd);
4552 /* check application command */
4553 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4554 LOGW("playing.. should wait cmd lock then, will be interrupted");
4556 /* lock will be released at mrp_resource_release_cb() */
4557 MMPLAYER_CMD_LOCK(player);
4560 LOGW("nothing to do");
4563 LOGW("can interrupt immediately");
4567 FAILED: /* with CMD UNLOCKED */
4570 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4575 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4578 mmplayer_t *player = NULL;
4579 MMMessageParamType msg = {0, };
4581 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4586 LOGE("user_data is null");
4589 player = (mmplayer_t *)user_data;
4591 if (!__mmplayer_can_do_interrupt(player)) {
4592 LOGW("no need to interrupt, so leave");
4593 /* FIXME: there is no way to avoid releasing resource. */
4597 player->interrupted_by_resource = TRUE;
4599 /* get last play position */
4600 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4601 msg.union_type = MM_MSG_UNION_TIME;
4602 msg.time.elapsed = pos;
4603 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4605 LOGW("failed to get play position.");
4608 LOGD("video resource conflict so, resource will be freed by unrealizing");
4609 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4610 LOGE("failed to unrealize");
4612 /* lock is called in __mmplayer_can_do_interrupt() */
4613 MMPLAYER_CMD_UNLOCK(player);
4615 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4616 player->hw_resource[res_idx] = NULL;
4620 return TRUE; /* release all the resources */
4624 __mmplayer_initialize_video_roi(mmplayer_t *player)
4626 player->video_roi.scale_x = 0.0;
4627 player->video_roi.scale_y = 0.0;
4628 player->video_roi.scale_width = 1.0;
4629 player->video_roi.scale_height = 1.0;
4633 _mmplayer_create_player(MMHandleType handle)
4635 int ret = MM_ERROR_PLAYER_INTERNAL;
4636 bool enabled = false;
4638 mmplayer_t *player = MM_PLAYER_CAST(handle);
4642 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4644 /* initialize player state */
4645 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4646 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4647 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4648 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4650 /* check current state */
4651 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4653 /* construct attributes */
4654 player->attrs = _mmplayer_construct_attribute(handle);
4656 if (!player->attrs) {
4657 LOGE("Failed to construct attributes");
4661 /* initialize gstreamer with configured parameter */
4662 if (!__mmplayer_init_gstreamer(player)) {
4663 LOGE("Initializing gstreamer failed");
4664 _mmplayer_deconstruct_attribute(handle);
4668 /* create lock. note that g_tread_init() has already called in gst_init() */
4669 g_mutex_init(&player->fsink_lock);
4671 /* create update tag lock */
4672 g_mutex_init(&player->update_tag_lock);
4674 /* create gapless play mutex */
4675 g_mutex_init(&player->gapless_play_thread_mutex);
4677 /* create gapless play cond */
4678 g_cond_init(&player->gapless_play_thread_cond);
4680 /* create gapless play thread */
4681 player->gapless_play_thread =
4682 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4683 if (!player->gapless_play_thread) {
4684 LOGE("failed to create gapless play thread");
4685 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4686 g_mutex_clear(&player->gapless_play_thread_mutex);
4687 g_cond_clear(&player->gapless_play_thread_cond);
4691 player->bus_msg_q = g_queue_new();
4692 if (!player->bus_msg_q) {
4693 LOGE("failed to create queue for bus_msg");
4694 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4698 ret = _mmplayer_initialize_video_capture(player);
4699 if (ret != MM_ERROR_NONE) {
4700 LOGE("failed to initialize video capture");
4704 /* initialize resource manager */
4705 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4706 __resource_release_cb, player, &player->resource_manager)
4707 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4708 LOGE("failed to initialize resource manager");
4709 ret = MM_ERROR_PLAYER_INTERNAL;
4713 /* create video bo lock and cond */
4714 g_mutex_init(&player->video_bo_mutex);
4715 g_cond_init(&player->video_bo_cond);
4717 /* create subtitle info lock and cond */
4718 g_mutex_init(&player->subtitle_info_mutex);
4719 g_cond_init(&player->subtitle_info_cond);
4721 player->streaming_type = STREAMING_SERVICE_NONE;
4723 /* give default value of audio effect setting */
4724 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4725 player->sound.rg_enable = false;
4726 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4728 player->play_subtitle = FALSE;
4729 player->has_closed_caption = FALSE;
4730 player->pending_resume = FALSE;
4731 if (player->ini.dump_element_keyword[0][0] == '\0')
4732 player->ini.set_dump_element_flag = FALSE;
4734 player->ini.set_dump_element_flag = TRUE;
4736 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4737 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4738 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4740 /* Set video360 settings to their defaults for just-created player.
4743 player->is_360_feature_enabled = FALSE;
4744 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4745 LOGI("spherical feature info: %d", enabled);
4747 player->is_360_feature_enabled = TRUE;
4749 LOGE("failed to get spherical feature info");
4752 player->is_content_spherical = FALSE;
4753 player->is_video360_enabled = TRUE;
4754 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4755 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4756 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4757 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4758 player->video360_zoom = 1.0f;
4759 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4760 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4762 __mmplayer_initialize_video_roi(player);
4764 /* set player state to null */
4765 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4766 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4770 return MM_ERROR_NONE;
4774 g_mutex_clear(&player->fsink_lock);
4775 /* free update tag lock */
4776 g_mutex_clear(&player->update_tag_lock);
4777 g_queue_free(player->bus_msg_q);
4778 player->bus_msg_q = NULL;
4779 /* free gapless play thread */
4780 if (player->gapless_play_thread) {
4781 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4782 player->gapless_play_thread_exit = TRUE;
4783 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4784 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4786 g_thread_join(player->gapless_play_thread);
4787 player->gapless_play_thread = NULL;
4789 g_mutex_clear(&player->gapless_play_thread_mutex);
4790 g_cond_clear(&player->gapless_play_thread_cond);
4793 /* release attributes */
4794 _mmplayer_deconstruct_attribute(handle);
4802 __mmplayer_init_gstreamer(mmplayer_t *player)
4804 static gboolean initialized = FALSE;
4805 static const int max_argc = 50;
4807 gchar **argv = NULL;
4808 gchar **argv2 = NULL;
4814 LOGD("gstreamer already initialized.");
4819 argc = malloc(sizeof(int));
4820 argv = malloc(sizeof(gchar *) * max_argc);
4821 argv2 = malloc(sizeof(gchar *) * max_argc);
4823 if (!argc || !argv || !argv2)
4826 memset(argv, 0, sizeof(gchar *) * max_argc);
4827 memset(argv2, 0, sizeof(gchar *) * max_argc);
4831 argv[0] = g_strdup("mmplayer");
4834 for (i = 0; i < 5; i++) {
4835 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4836 if (strlen(player->ini.gst_param[i]) > 0) {
4837 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4842 /* we would not do fork for scanning plugins */
4843 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4846 /* check disable registry scan */
4847 if (player->ini.skip_rescan) {
4848 argv[*argc] = g_strdup("--gst-disable-registry-update");
4852 /* check disable segtrap */
4853 if (player->ini.disable_segtrap) {
4854 argv[*argc] = g_strdup("--gst-disable-segtrap");
4858 LOGD("initializing gstreamer with following parameter");
4859 LOGD("argc : %d", *argc);
4862 for (i = 0; i < arg_count; i++) {
4864 LOGD("argv[%d] : %s", i, argv2[i]);
4867 /* initializing gstreamer */
4868 if (!gst_init_check(argc, &argv, &err)) {
4869 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4876 for (i = 0; i < arg_count; i++) {
4877 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4878 MMPLAYER_FREEIF(argv2[i]);
4881 MMPLAYER_FREEIF(argv);
4882 MMPLAYER_FREEIF(argv2);
4883 MMPLAYER_FREEIF(argc);
4893 for (i = 0; i < arg_count; i++) {
4894 LOGD("free[%d] : %s", i, argv2[i]);
4895 MMPLAYER_FREEIF(argv2[i]);
4898 MMPLAYER_FREEIF(argv);
4899 MMPLAYER_FREEIF(argv2);
4900 MMPLAYER_FREEIF(argc);
4906 __mmplayer_check_async_state_transition(mmplayer_t *player)
4908 GstState element_state = GST_STATE_VOID_PENDING;
4909 GstState element_pending_state = GST_STATE_VOID_PENDING;
4910 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4911 GstElement *element = NULL;
4912 gboolean async = FALSE;
4914 /* check player handle */
4915 MMPLAYER_RETURN_IF_FAIL(player &&
4917 player->pipeline->mainbin &&
4918 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4921 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4923 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4924 LOGD("don't need to check the pipeline state");
4928 MMPLAYER_PRINT_STATE(player);
4930 /* wait for state transition */
4931 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4932 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4934 if (ret == GST_STATE_CHANGE_FAILURE) {
4935 LOGE(" [%s] state : %s pending : %s",
4936 GST_ELEMENT_NAME(element),
4937 gst_element_state_get_name(element_state),
4938 gst_element_state_get_name(element_pending_state));
4940 /* dump state of all element */
4941 _mmplayer_dump_pipeline_state(player);
4946 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4951 _mmplayer_destroy(MMHandleType handle)
4953 mmplayer_t *player = MM_PLAYER_CAST(handle);
4957 /* check player handle */
4958 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4960 /* destroy can called at anytime */
4961 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4963 /* check async state transition */
4964 __mmplayer_check_async_state_transition(player);
4966 /* release gapless play thread */
4967 if (player->gapless_play_thread) {
4968 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4969 player->gapless_play_thread_exit = TRUE;
4970 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4971 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4973 LOGD("waitting for gapless play thread exit");
4974 g_thread_join(player->gapless_play_thread);
4975 g_mutex_clear(&player->gapless_play_thread_mutex);
4976 g_cond_clear(&player->gapless_play_thread_cond);
4977 LOGD("gapless play thread released");
4980 _mmplayer_release_video_capture(player);
4982 /* de-initialize resource manager */
4983 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4984 player->resource_manager))
4985 LOGE("failed to deinitialize resource manager");
4987 /* release pipeline */
4988 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4989 LOGE("failed to destory pipeline");
4990 return MM_ERROR_PLAYER_INTERNAL;
4993 g_queue_free(player->bus_msg_q);
4995 /* release subtitle info lock and cond */
4996 g_mutex_clear(&player->subtitle_info_mutex);
4997 g_cond_clear(&player->subtitle_info_cond);
4999 __mmplayer_release_dump_list(player->dump_list);
5001 /* release miscellaneous information */
5002 __mmplayer_release_misc(player);
5004 /* release miscellaneous information.
5005 these info needs to be released after pipeline is destroyed. */
5006 __mmplayer_release_misc_post(player);
5008 /* release attributes */
5009 _mmplayer_deconstruct_attribute(handle);
5012 g_mutex_clear(&player->fsink_lock);
5015 g_mutex_clear(&player->update_tag_lock);
5017 /* release video bo lock and cond */
5018 g_mutex_clear(&player->video_bo_mutex);
5019 g_cond_clear(&player->video_bo_cond);
5023 return MM_ERROR_NONE;
5027 _mmplayer_realize(MMHandleType hplayer)
5029 mmplayer_t *player = (mmplayer_t *)hplayer;
5032 MMHandleType attrs = 0;
5033 int ret = MM_ERROR_NONE;
5037 /* check player handle */
5038 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5040 /* check current state */
5041 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5043 attrs = MMPLAYER_GET_ATTRS(player);
5045 LOGE("fail to get attributes.");
5046 return MM_ERROR_PLAYER_INTERNAL;
5048 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5049 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5051 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5052 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5054 if (ret != MM_ERROR_NONE) {
5055 LOGE("failed to parse profile");
5060 if (uri && (strstr(uri, "es_buff://"))) {
5061 if (strstr(uri, "es_buff://push_mode"))
5062 player->es_player_push_mode = TRUE;
5064 player->es_player_push_mode = FALSE;
5067 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5068 LOGW("mms protocol is not supported format.");
5069 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5072 if (MMPLAYER_IS_STREAMING(player))
5073 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5075 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5077 player->smooth_streaming = FALSE;
5078 player->videodec_linked = 0;
5079 player->audiodec_linked = 0;
5080 player->textsink_linked = 0;
5081 player->is_external_subtitle_present = FALSE;
5082 player->is_external_subtitle_added_now = FALSE;
5083 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5084 player->video360_metadata.is_spherical = -1;
5085 player->is_openal_plugin_used = FALSE;
5086 player->demux_pad_index = 0;
5087 player->subtitle_language_list = NULL;
5088 player->is_subtitle_force_drop = FALSE;
5090 _mmplayer_track_initialize(player);
5091 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5093 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5094 gint prebuffer_ms = 0, rebuffer_ms = 0;
5096 player->streamer = _mm_player_streaming_create();
5097 _mm_player_streaming_initialize(player->streamer, TRUE);
5099 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5100 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5102 if (prebuffer_ms > 0) {
5103 prebuffer_ms = MAX(prebuffer_ms, 1000);
5104 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5107 if (rebuffer_ms > 0) {
5108 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5109 rebuffer_ms = MAX(rebuffer_ms, 1000);
5110 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5113 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5114 player->streamer->buffering_req.rebuffer_time);
5117 /* realize pipeline */
5118 ret = __mmplayer_gst_realize(player);
5119 if (ret != MM_ERROR_NONE)
5120 LOGE("fail to realize the player.");
5122 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5130 _mmplayer_unrealize(MMHandleType hplayer)
5132 mmplayer_t *player = (mmplayer_t *)hplayer;
5133 int ret = MM_ERROR_NONE;
5137 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5139 MMPLAYER_CMD_UNLOCK(player);
5140 /* destroy the gst bus msg thread which is created during realize.
5141 this funct have to be called before getting cmd lock. */
5142 _mmplayer_bus_msg_thread_destroy(player);
5143 MMPLAYER_CMD_LOCK(player);
5145 /* check current state */
5146 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5148 /* check async state transition */
5149 __mmplayer_check_async_state_transition(player);
5151 /* unrealize pipeline */
5152 ret = __mmplayer_gst_unrealize(player);
5154 if (!player->interrupted_by_resource) {
5155 int rm_ret = MM_ERROR_NONE;
5156 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5158 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5159 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5160 if (rm_ret != MM_ERROR_NONE)
5161 LOGE("failed to release [%d] resources", res_idx);
5170 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5172 mmplayer_t *player = (mmplayer_t *)hplayer;
5174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5176 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5180 _mmplayer_get_state(MMHandleType hplayer, int *state)
5182 mmplayer_t *player = (mmplayer_t *)hplayer;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5186 *state = MMPLAYER_CURRENT_STATE(player);
5188 return MM_ERROR_NONE;
5192 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5194 GstElement *vol_element = NULL;
5195 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5198 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5199 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5201 /* check pipeline handle */
5202 if (!player->pipeline || !player->pipeline->audiobin) {
5203 LOGD("'%s' will be applied when audiobin is created", prop_name);
5205 /* NOTE : stored value will be used in create_audiobin
5206 * returning MM_ERROR_NONE here makes application to able to
5207 * set audio volume or mute at anytime.
5209 return MM_ERROR_NONE;
5212 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5213 volume_elem_id = MMPLAYER_A_SINK;
5215 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5217 LOGE("failed to get vol element %d", volume_elem_id);
5218 return MM_ERROR_PLAYER_INTERNAL;
5221 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5223 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5224 LOGE("there is no '%s' property", prop_name);
5225 return MM_ERROR_PLAYER_INTERNAL;
5228 if (!strcmp(prop_name, "volume")) {
5229 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5230 } else if (!strcmp(prop_name, "mute")) {
5231 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5233 LOGE("invalid property %s", prop_name);
5234 return MM_ERROR_PLAYER_INTERNAL;
5237 return MM_ERROR_NONE;
5241 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5243 int ret = MM_ERROR_NONE;
5244 mmplayer_t *player = (mmplayer_t *)hplayer;
5247 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5249 LOGD("volume = %f", volume);
5251 /* invalid factor range or not */
5252 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5253 LOGE("Invalid volume value");
5254 return MM_ERROR_INVALID_ARGUMENT;
5257 player->sound.volume = volume;
5259 ret = __mmplayer_gst_set_volume_property(player, "volume");
5266 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5268 mmplayer_t *player = (mmplayer_t *)hplayer;
5272 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5273 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5275 *volume = player->sound.volume;
5277 LOGD("current vol = %f", *volume);
5280 return MM_ERROR_NONE;
5284 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5286 int ret = MM_ERROR_NONE;
5287 mmplayer_t *player = (mmplayer_t *)hplayer;
5290 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5292 LOGD("mute = %d", mute);
5294 player->sound.mute = mute;
5296 ret = __mmplayer_gst_set_volume_property(player, "mute");
5303 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5305 mmplayer_t *player = (mmplayer_t *)hplayer;
5309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5310 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5312 *mute = player->sound.mute;
5314 LOGD("current mute = %d", *mute);
5318 return MM_ERROR_NONE;
5322 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5324 mmplayer_t *player = (mmplayer_t *)hplayer;
5328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5330 player->audio_stream_changed_cb = callback;
5331 player->audio_stream_changed_cb_user_param = user_param;
5332 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5336 return MM_ERROR_NONE;
5340 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5342 mmplayer_t *player = (mmplayer_t *)hplayer;
5346 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5348 player->audio_decoded_cb = callback;
5349 player->audio_decoded_cb_user_param = user_param;
5350 player->audio_extract_opt = opt;
5351 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5355 return MM_ERROR_NONE;
5359 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5361 mmplayer_t *player = (mmplayer_t *)hplayer;
5365 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5367 if (callback && !player->bufmgr)
5368 player->bufmgr = tbm_bufmgr_init(-1);
5370 player->set_mode.video_export = (callback) ? true : false;
5371 player->video_decoded_cb = callback;
5372 player->video_decoded_cb_user_param = user_param;
5374 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5378 return MM_ERROR_NONE;
5382 _mmplayer_start(MMHandleType hplayer)
5384 mmplayer_t *player = (mmplayer_t *)hplayer;
5385 gint ret = MM_ERROR_NONE;
5389 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5391 /* check current state */
5392 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5394 /* start pipeline */
5395 ret = _mmplayer_gst_start(player);
5396 if (ret != MM_ERROR_NONE)
5397 LOGE("failed to start player.");
5399 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5400 LOGD("force playing start even during buffering");
5401 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5409 /* NOTE: post "not supported codec message" to application
5410 * when one codec is not found during AUTOPLUGGING in MSL.
5411 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5412 * And, if any codec is not found, don't send message here.
5413 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5416 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5418 MMMessageParamType msg_param;
5419 memset(&msg_param, 0, sizeof(MMMessageParamType));
5420 gboolean post_msg_direct = FALSE;
5424 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5426 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5427 player->not_supported_codec, player->can_support_codec);
5429 if (player->not_found_demuxer) {
5430 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5431 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5433 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5434 MMPLAYER_FREEIF(msg_param.data);
5436 return MM_ERROR_NONE;
5439 if (player->not_supported_codec) {
5440 if (player->can_support_codec) {
5441 // There is one codec to play
5442 post_msg_direct = TRUE;
5444 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5445 post_msg_direct = TRUE;
5448 if (post_msg_direct) {
5449 MMMessageParamType msg_param;
5450 memset(&msg_param, 0, sizeof(MMMessageParamType));
5452 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5453 LOGW("not found AUDIO codec, posting error code to application.");
5455 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5456 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5457 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5458 LOGW("not found VIDEO codec, posting error code to application.");
5460 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5461 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5464 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5466 MMPLAYER_FREEIF(msg_param.data);
5468 return MM_ERROR_NONE;
5470 // no any supported codec case
5471 LOGW("not found any codec, posting error code to application.");
5473 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5474 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5475 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5477 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5478 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5481 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5483 MMPLAYER_FREEIF(msg_param.data);
5489 return MM_ERROR_NONE;
5493 __mmplayer_check_pipeline(mmplayer_t *player)
5495 GstState element_state = GST_STATE_VOID_PENDING;
5496 GstState element_pending_state = GST_STATE_VOID_PENDING;
5498 int ret = MM_ERROR_NONE;
5500 if (!player->gapless.reconfigure)
5503 LOGW("pipeline is under construction.");
5505 MMPLAYER_PLAYBACK_LOCK(player);
5506 MMPLAYER_PLAYBACK_UNLOCK(player);
5508 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5510 /* wait for state transition */
5511 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5512 if (ret == GST_STATE_CHANGE_FAILURE)
5513 LOGE("failed to change pipeline state within %d sec", timeout);
5516 /* NOTE : it should be able to call 'stop' anytime*/
5518 _mmplayer_stop(MMHandleType hplayer)
5520 mmplayer_t *player = (mmplayer_t *)hplayer;
5521 int ret = MM_ERROR_NONE;
5525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5527 /* check current state */
5528 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5530 /* check pipline building state */
5531 __mmplayer_check_pipeline(player);
5532 __mmplayer_reset_gapless_state(player);
5534 /* NOTE : application should not wait for EOS after calling STOP */
5535 _mmplayer_cancel_eos_timer(player);
5538 player->seek_state = MMPLAYER_SEEK_NONE;
5541 ret = _mmplayer_gst_stop(player);
5543 if (ret != MM_ERROR_NONE)
5544 LOGE("failed to stop player.");
5552 _mmplayer_pause(MMHandleType hplayer)
5554 mmplayer_t *player = (mmplayer_t *)hplayer;
5555 gint64 pos_nsec = 0;
5556 gboolean async = FALSE;
5557 gint ret = MM_ERROR_NONE;
5561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5563 /* check current state */
5564 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5566 /* check pipline building state */
5567 __mmplayer_check_pipeline(player);
5569 switch (MMPLAYER_CURRENT_STATE(player)) {
5570 case MM_PLAYER_STATE_READY:
5572 /* check prepare async or not.
5573 * In the case of streaming playback, it's recommned to avoid blocking wait.
5575 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5576 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5578 /* Changing back sync of rtspsrc to async */
5579 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5580 LOGD("async prepare working mode for rtsp");
5586 case MM_PLAYER_STATE_PLAYING:
5588 /* NOTE : store current point to overcome some bad operation
5589 *(returning zero when getting current position in paused state) of some
5592 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5593 LOGW("getting current position failed in paused");
5595 player->last_position = pos_nsec;
5597 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5598 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5599 This causes problem is position calculation during normal pause resume scenarios also.
5600 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5601 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5602 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5603 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5609 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5610 LOGD("doing async pause in case of ms buff src");
5614 /* pause pipeline */
5615 ret = _mmplayer_gst_pause(player, async);
5617 if (ret != MM_ERROR_NONE)
5618 LOGE("failed to pause player. ret : 0x%x", ret);
5620 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5621 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5622 LOGE("failed to update display_rotation");
5630 /* in case of streaming, pause could take long time.*/
5632 _mmplayer_abort_pause(MMHandleType hplayer)
5634 mmplayer_t *player = (mmplayer_t *)hplayer;
5635 int ret = MM_ERROR_NONE;
5639 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5641 player->pipeline->mainbin,
5642 MM_ERROR_PLAYER_NOT_INITIALIZED);
5644 LOGD("set the pipeline state to READY");
5646 /* set state to READY */
5647 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5648 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5649 if (ret != MM_ERROR_NONE) {
5650 LOGE("fail to change state to READY");
5651 return MM_ERROR_PLAYER_INTERNAL;
5654 LOGD("succeeded in changing state to READY");
5659 _mmplayer_resume(MMHandleType hplayer)
5661 mmplayer_t *player = (mmplayer_t *)hplayer;
5662 int ret = MM_ERROR_NONE;
5663 gboolean async = FALSE;
5667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5669 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5670 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5671 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5675 /* Changing back sync mode rtspsrc to async */
5676 LOGD("async resume for rtsp case");
5680 /* check current state */
5681 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5683 ret = _mmplayer_gst_resume(player, async);
5684 if (ret != MM_ERROR_NONE)
5685 LOGE("failed to resume player.");
5687 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5688 LOGD("force resume even during buffering");
5689 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5698 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5700 mmplayer_t *player = (mmplayer_t *)hplayer;
5701 gint64 pos_nsec = 0;
5702 int ret = MM_ERROR_NONE;
5704 signed long long start = 0, stop = 0;
5705 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5708 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5709 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5711 /* The sound of video is not supported under 0.0 and over 2.0. */
5712 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5713 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5716 _mmplayer_set_mute(hplayer, mute);
5718 if (player->playback_rate == rate)
5719 return MM_ERROR_NONE;
5721 /* If the position is reached at start potion during fast backward, EOS is posted.
5722 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5724 player->playback_rate = rate;
5726 current_state = MMPLAYER_CURRENT_STATE(player);
5728 if (current_state != MM_PLAYER_STATE_PAUSED)
5729 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5731 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5733 if ((current_state == MM_PLAYER_STATE_PAUSED)
5734 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5735 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5736 pos_nsec = player->last_position;
5741 stop = GST_CLOCK_TIME_NONE;
5743 start = GST_CLOCK_TIME_NONE;
5747 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5748 player->playback_rate,
5750 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5751 GST_SEEK_TYPE_SET, start,
5752 GST_SEEK_TYPE_SET, stop)) {
5753 LOGE("failed to set speed playback");
5754 return MM_ERROR_PLAYER_SEEK;
5757 LOGD("succeeded to set speed playback as %0.1f", rate);
5761 return MM_ERROR_NONE;;
5765 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5767 mmplayer_t *player = (mmplayer_t *)hplayer;
5768 int ret = MM_ERROR_NONE;
5772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5774 /* check pipline building state */
5775 __mmplayer_check_pipeline(player);
5777 ret = _mmplayer_gst_set_position(player, position, FALSE);
5785 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5787 mmplayer_t *player = (mmplayer_t *)hplayer;
5788 int ret = MM_ERROR_NONE;
5790 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5791 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5793 if (g_strrstr(player->type, "video/mpegts"))
5794 __mmplayer_update_duration_value(player);
5796 *duration = player->duration;
5801 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5803 mmplayer_t *player = (mmplayer_t *)hplayer;
5804 int ret = MM_ERROR_NONE;
5806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5808 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5814 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5816 mmplayer_t *player = (mmplayer_t *)hplayer;
5817 int ret = MM_ERROR_NONE;
5821 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5823 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5831 __mmplayer_is_midi_type(gchar *str_caps)
5833 if ((g_strrstr(str_caps, "audio/midi")) ||
5834 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5835 (g_strrstr(str_caps, "application/x-smaf")) ||
5836 (g_strrstr(str_caps, "audio/x-imelody")) ||
5837 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5838 (g_strrstr(str_caps, "audio/xmf")) ||
5839 (g_strrstr(str_caps, "audio/mxmf"))) {
5848 __mmplayer_is_only_mp3_type(gchar *str_caps)
5850 if (g_strrstr(str_caps, "application/x-id3") ||
5851 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5857 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5859 GstStructure *caps_structure = NULL;
5860 gint samplerate = 0;
5864 MMPLAYER_RETURN_IF_FAIL(player && caps);
5866 caps_structure = gst_caps_get_structure(caps, 0);
5868 /* set stream information */
5869 gst_structure_get_int(caps_structure, "rate", &samplerate);
5870 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5872 gst_structure_get_int(caps_structure, "channels", &channels);
5873 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5875 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5879 __mmplayer_update_content_type_info(mmplayer_t *player)
5882 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5884 if (__mmplayer_is_midi_type(player->type)) {
5885 player->bypass_audio_effect = TRUE;
5889 if (!player->streamer) {
5890 LOGD("no need to check streaming type");
5894 if (g_strrstr(player->type, "application/x-hls")) {
5895 /* If it can't know exact type when it parses uri because of redirection case,
5896 * it will be fixed by typefinder or when doing autoplugging.
5898 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5899 player->streamer->is_adaptive_streaming = TRUE;
5900 } else if (g_strrstr(player->type, "application/dash+xml")) {
5901 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5902 player->streamer->is_adaptive_streaming = TRUE;
5905 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5906 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5907 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5909 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5910 if (player->streamer->is_adaptive_streaming)
5911 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5913 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5917 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5922 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5923 GstCaps *caps, gpointer data)
5925 mmplayer_t *player = (mmplayer_t *)data;
5930 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5932 /* store type string */
5933 MMPLAYER_FREEIF(player->type);
5934 player->type = gst_caps_to_string(caps);
5936 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5937 player, player->type, probability, gst_caps_get_size(caps));
5939 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5940 (g_strrstr(player->type, "audio/x-raw-int"))) {
5941 LOGE("not support media format");
5943 if (player->msg_posted == FALSE) {
5944 MMMessageParamType msg_param;
5945 memset(&msg_param, 0, sizeof(MMMessageParamType));
5947 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5948 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5950 /* don't post more if one was sent already */
5951 player->msg_posted = TRUE;
5956 __mmplayer_update_content_type_info(player);
5958 pad = gst_element_get_static_pad(tf, "src");
5960 LOGE("fail to get typefind src pad.");
5964 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5965 gboolean async = FALSE;
5966 LOGE("failed to autoplug %s", player->type);
5968 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5970 if (async && player->msg_posted == FALSE)
5971 __mmplayer_handle_missed_plugin(player);
5975 gst_object_unref(GST_OBJECT(pad));
5983 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5985 GstElement *decodebin = NULL;
5989 /* create decodebin */
5990 decodebin = gst_element_factory_make("decodebin", NULL);
5993 LOGE("fail to create decodebin");
5997 /* raw pad handling signal */
5998 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5999 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6001 /* no-more-pad pad handling signal */
6002 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6003 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6006 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6008 /* This signal is emitted when a pad for which there is no further possible
6009 decoding is added to the decodebin.*/
6010 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6011 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6013 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6014 before looking for any elements that can handle that stream.*/
6015 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6016 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6018 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6019 before looking for any elements that can handle that stream.*/
6020 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6021 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6023 /* This signal is emitted once decodebin has finished decoding all the data.*/
6024 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6025 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6027 /* This signal is emitted when a element is added to the bin.*/
6028 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6029 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6036 __mmplayer_gst_make_queue2(mmplayer_t *player)
6038 GstElement *queue2 = NULL;
6039 gint64 dur_bytes = 0L;
6040 mmplayer_gst_element_t *mainbin = NULL;
6041 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6044 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6046 mainbin = player->pipeline->mainbin;
6048 queue2 = gst_element_factory_make("queue2", "queue2");
6050 LOGE("failed to create buffering queue element");
6054 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6055 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6057 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6059 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6060 * skip the pull mode(file or ring buffering) setting. */
6061 if (dur_bytes > 0) {
6062 if (!g_strrstr(player->type, "video/mpegts")) {
6063 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6064 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6070 _mm_player_streaming_set_queue2(player->streamer,
6074 (guint64)dur_bytes); /* no meaning at the moment */
6080 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6082 mmplayer_gst_element_t *mainbin = NULL;
6083 GstElement *decodebin = NULL;
6084 GstElement *queue2 = NULL;
6085 GstPad *sinkpad = NULL;
6086 GstPad *qsrcpad = NULL;
6089 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6091 mainbin = player->pipeline->mainbin;
6093 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6095 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6096 LOGW("need to check: muxed buffer is not null");
6099 queue2 = __mmplayer_gst_make_queue2(player);
6101 LOGE("failed to make queue2");
6105 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6106 LOGE("failed to add buffering queue");
6110 sinkpad = gst_element_get_static_pad(queue2, "sink");
6111 qsrcpad = gst_element_get_static_pad(queue2, "src");
6113 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6114 LOGE("failed to link [%s:%s]-[%s:%s]",
6115 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6119 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6120 LOGE("failed to sync queue2 state with parent");
6124 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6125 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6129 gst_object_unref(GST_OBJECT(sinkpad));
6133 /* create decodebin */
6134 decodebin = _mmplayer_gst_make_decodebin(player);
6136 LOGE("failed to make decodebin");
6140 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6141 LOGE("failed to add decodebin");
6145 /* to force caps on the decodebin element and avoid reparsing stuff by
6146 * typefind. It also avoids a deadlock in the way typefind activates pads in
6147 * the state change */
6148 g_object_set(decodebin, "sink-caps", caps, NULL);
6150 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6152 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6153 LOGE("failed to link [%s:%s]-[%s:%s]",
6154 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6158 gst_object_unref(GST_OBJECT(sinkpad));
6160 gst_object_unref(GST_OBJECT(qsrcpad));
6163 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6164 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6166 /* set decodebin property about buffer in streaming playback. *
6167 * in case of HLS/DASH, it does not need to have big buffer *
6168 * because it is kind of adaptive streaming. */
6169 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6170 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6171 gint high_percent = 0;
6173 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6174 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6176 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6178 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6180 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6181 "high-percent", high_percent,
6182 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6183 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6184 "max-size-buffers", 0, NULL); // disable or automatic
6187 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6188 LOGE("failed to sync decodebin state with parent");
6199 gst_object_unref(GST_OBJECT(sinkpad));
6202 gst_object_unref(GST_OBJECT(qsrcpad));
6205 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6206 * You need to explicitly set elements to the NULL state before
6207 * dropping the final reference, to allow them to clean up.
6209 gst_element_set_state(queue2, GST_STATE_NULL);
6211 /* And, it still has a parent "player".
6212 * You need to let the parent manage the object instead of unreffing the object directly.
6214 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6215 gst_object_unref(queue2);
6220 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6221 * You need to explicitly set elements to the NULL state before
6222 * dropping the final reference, to allow them to clean up.
6224 gst_element_set_state(decodebin, GST_STATE_NULL);
6226 /* And, it still has a parent "player".
6227 * You need to let the parent manage the object instead of unreffing the object directly.
6230 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6231 gst_object_unref(decodebin);
6239 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6244 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6246 LOGD("class : %s, mime : %s", factory_class, mime);
6248 /* add missing plugin */
6249 /* NOTE : msl should check missing plugin for image mime type.
6250 * Some motion jpeg clips can have playable audio track.
6251 * So, msl have to play audio after displaying popup written video format not supported.
6253 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6254 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6255 LOGD("not found demuxer");
6256 player->not_found_demuxer = TRUE;
6257 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6263 if (!g_strrstr(factory_class, "Demuxer")) {
6264 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6265 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6266 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6268 /* check that clip have multi tracks or not */
6269 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6270 LOGD("video plugin is already linked");
6272 LOGW("add VIDEO to missing plugin");
6273 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6274 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6276 } else if (g_str_has_prefix(mime, "audio")) {
6277 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6278 LOGD("audio plugin is already linked");
6280 LOGW("add AUDIO to missing plugin");
6281 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6282 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6290 return MM_ERROR_NONE;
6294 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6296 mmplayer_t *player = (mmplayer_t *)data;
6300 MMPLAYER_RETURN_IF_FAIL(player);
6302 /* remove fakesink. */
6303 if (!_mmplayer_gst_remove_fakesink(player,
6304 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6305 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6306 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6307 * source element are not same. To overcome this situation, this function will called
6308 * several places and several times. Therefore, this is not an error case.
6313 LOGD("[handle: %p] pipeline has completely constructed", player);
6315 if ((player->ini.async_start) &&
6316 (player->msg_posted == FALSE) &&
6317 (player->cmd >= MMPLAYER_COMMAND_START))
6318 __mmplayer_handle_missed_plugin(player);
6320 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6324 __mmplayer_check_profile(void)
6327 static int profile_tv = -1;
6329 if (__builtin_expect(profile_tv != -1, 1))
6332 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6333 switch (*profileName) {
6348 __mmplayer_get_next_uri(mmplayer_t *player)
6350 mmplayer_parse_profile_t profile;
6352 guint num_of_list = 0;
6355 num_of_list = g_list_length(player->uri_info.uri_list);
6356 uri_idx = player->uri_info.uri_idx;
6358 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6359 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6360 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6362 LOGW("next uri does not exist");
6366 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6367 LOGE("failed to parse profile");
6371 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6372 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6373 LOGW("uri type is not supported(%d)", profile.uri_type);
6377 LOGD("success to find next uri %d", uri_idx);
6381 if (uri_idx == num_of_list) {
6382 LOGE("failed to find next uri");
6386 player->uri_info.uri_idx = uri_idx;
6387 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6389 if (mm_attrs_commit_all(player->attrs)) {
6390 LOGE("failed to commit");
6394 SECURE_LOGD("next playback uri: %s", uri);
6399 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6401 #define REPEAT_COUNT_INFINITE -1
6402 #define REPEAT_COUNT_MIN 2
6403 #define ORIGINAL_URI_ONLY 1
6405 MMHandleType attrs = 0;
6409 guint num_of_uri = 0;
6410 int profile_tv = -1;
6414 LOGD("checking for gapless play option");
6416 if (player->pipeline->textbin) {
6417 LOGE("subtitle path is enabled. gapless play is not supported.");
6421 attrs = MMPLAYER_GET_ATTRS(player);
6423 LOGE("fail to get attributes.");
6427 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6429 /* gapless playback is not supported in case of video at TV profile. */
6430 profile_tv = __mmplayer_check_profile();
6431 if (profile_tv && video) {
6432 LOGW("not support video gapless playback");
6436 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6437 LOGE("failed to get play count");
6439 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6440 LOGE("failed to get gapless mode");
6442 /* check repeat count in case of audio */
6444 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6445 LOGW("gapless is disabled");
6449 num_of_uri = g_list_length(player->uri_info.uri_list);
6451 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6453 if (num_of_uri == ORIGINAL_URI_ONLY) {
6454 /* audio looping path */
6455 if (count >= REPEAT_COUNT_MIN) {
6456 /* decrease play count */
6457 /* we succeeded to rewind. update play count and then wait for next EOS */
6459 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6460 /* commit attribute */
6461 if (mm_attrs_commit_all(attrs))
6462 LOGE("failed to commit attribute");
6464 } else if (count != REPEAT_COUNT_INFINITE) {
6465 LOGD("there is no next uri and no repeat");
6468 LOGD("looping cnt %d", count);
6470 /* gapless playback path */
6471 if (!__mmplayer_get_next_uri(player)) {
6472 LOGE("failed to get next uri");
6479 LOGE("unable to play gapless path. EOS will be posted soon");
6484 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6486 mmplayer_selector_t *selector = &player->selector[type];
6487 mmplayer_gst_element_t *sinkbin = NULL;
6488 main_element_id_e selectorId = MMPLAYER_M_NUM;
6489 main_element_id_e sinkId = MMPLAYER_M_NUM;
6490 GstPad *srcpad = NULL;
6491 GstPad *sinkpad = NULL;
6492 gboolean send_notice = FALSE;
6495 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6497 LOGD("type %d", type);
6500 case MM_PLAYER_TRACK_TYPE_AUDIO:
6501 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6502 sinkId = MMPLAYER_A_BIN;
6503 sinkbin = player->pipeline->audiobin;
6505 case MM_PLAYER_TRACK_TYPE_VIDEO:
6506 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6507 sinkId = MMPLAYER_V_BIN;
6508 sinkbin = player->pipeline->videobin;
6511 case MM_PLAYER_TRACK_TYPE_TEXT:
6512 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6513 sinkId = MMPLAYER_T_BIN;
6514 sinkbin = player->pipeline->textbin;
6517 LOGE("requested type is not supportable");
6522 if (player->pipeline->mainbin[selectorId].gst) {
6525 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6527 if (selector->event_probe_id != 0)
6528 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6529 selector->event_probe_id = 0;
6531 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6532 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6534 if (srcpad && sinkpad) {
6535 /* after getting drained signal there is no data flows, so no need to do pad_block */
6536 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6537 gst_pad_unlink(srcpad, sinkpad);
6539 /* send custom event to sink pad to handle it at video sink */
6541 LOGD("send custom event to sinkpad");
6542 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6543 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6544 gst_pad_send_event(sinkpad, event);
6548 gst_object_unref(sinkpad);
6551 gst_object_unref(srcpad);
6554 LOGD("selector release");
6556 /* release and unref requests pad from the selector */
6557 for (n = 0; n < selector->channels->len; n++) {
6558 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6559 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6561 g_ptr_array_set_size(selector->channels, 0);
6563 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6564 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6566 player->pipeline->mainbin[selectorId].gst = NULL;
6574 __mmplayer_deactivate_old_path(mmplayer_t *player)
6577 MMPLAYER_RETURN_IF_FAIL(player);
6579 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6580 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6581 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6582 LOGE("deactivate selector error");
6586 _mmplayer_track_destroy(player);
6587 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6589 if (player->streamer) {
6590 _mm_player_streaming_initialize(player->streamer, FALSE);
6591 _mm_player_streaming_destroy(player->streamer);
6592 player->streamer = NULL;
6595 MMPLAYER_PLAYBACK_LOCK(player);
6596 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6603 if (!player->msg_posted) {
6604 MMMessageParamType msg = {0,};
6607 msg.code = MM_ERROR_PLAYER_INTERNAL;
6608 LOGE("gapless_uri_play> deactivate error");
6610 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6611 player->msg_posted = TRUE;
6617 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6619 int result = MM_ERROR_NONE;
6620 mmplayer_t *player = (mmplayer_t *)hplayer;
6623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6625 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6626 if (mm_attrs_commit_all(player->attrs)) {
6627 LOGE("failed to commit the original uri.");
6628 result = MM_ERROR_PLAYER_INTERNAL;
6630 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6631 LOGE("failed to add the original uri in the uri list.");
6639 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6641 mmplayer_t *player = (mmplayer_t *)hplayer;
6642 guint num_of_list = 0;
6646 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6647 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6649 if (player->pipeline && player->pipeline->textbin) {
6650 LOGE("subtitle path is enabled.");
6651 return MM_ERROR_PLAYER_INVALID_STATE;
6654 num_of_list = g_list_length(player->uri_info.uri_list);
6656 if (is_first_path) {
6657 if (num_of_list == 0) {
6658 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6659 SECURE_LOGD("add original path : %s", uri);
6661 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6662 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6664 SECURE_LOGD("change original path : %s", uri);
6667 MMHandleType attrs = 0;
6668 attrs = MMPLAYER_GET_ATTRS(player);
6670 if (num_of_list == 0) {
6671 char *original_uri = NULL;
6674 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6676 if (!original_uri) {
6677 LOGE("there is no original uri.");
6678 return MM_ERROR_PLAYER_INVALID_STATE;
6681 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6682 player->uri_info.uri_idx = 0;
6684 SECURE_LOGD("add original path at first : %s", original_uri);
6688 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6689 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6693 return MM_ERROR_NONE;
6697 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6699 mmplayer_t *player = (mmplayer_t *)hplayer;
6700 char *next_uri = NULL;
6701 guint num_of_list = 0;
6704 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6706 num_of_list = g_list_length(player->uri_info.uri_list);
6708 if (num_of_list > 0) {
6709 gint uri_idx = player->uri_info.uri_idx;
6711 if (uri_idx < num_of_list-1)
6716 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6717 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6719 *uri = g_strdup(next_uri);
6723 return MM_ERROR_NONE;
6727 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6728 GstCaps *caps, gpointer data)
6730 mmplayer_t *player = (mmplayer_t *)data;
6731 const gchar *klass = NULL;
6732 const gchar *mime = NULL;
6733 gchar *caps_str = NULL;
6735 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6736 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6737 caps_str = gst_caps_to_string(caps);
6739 LOGW("unknown type of caps : %s from %s",
6740 caps_str, GST_ELEMENT_NAME(elem));
6742 MMPLAYER_FREEIF(caps_str);
6744 /* There is no available codec. */
6745 __mmplayer_check_not_supported_codec(player, klass, mime);
6749 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6750 GstCaps *caps, gpointer data)
6752 mmplayer_t *player = (mmplayer_t *)data;
6753 const char *mime = NULL;
6754 gboolean ret = TRUE;
6756 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6757 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6759 if (g_str_has_prefix(mime, "audio")) {
6760 GstStructure *caps_structure = NULL;
6761 gint samplerate = 0;
6763 gchar *caps_str = NULL;
6765 caps_structure = gst_caps_get_structure(caps, 0);
6766 gst_structure_get_int(caps_structure, "rate", &samplerate);
6767 gst_structure_get_int(caps_structure, "channels", &channels);
6769 if ((channels > 0 && samplerate == 0)) {
6770 LOGD("exclude audio...");
6774 caps_str = gst_caps_to_string(caps);
6775 /* set it directly because not sent by TAG */
6776 if (g_strrstr(caps_str, "mobile-xmf"))
6777 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6778 MMPLAYER_FREEIF(caps_str);
6779 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6780 MMMessageParamType msg_param;
6781 memset(&msg_param, 0, sizeof(MMMessageParamType));
6782 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6783 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6784 LOGD("video file is not supported on this device");
6786 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6787 LOGD("already video linked");
6790 LOGD("found new stream");
6797 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6799 gboolean ret = TRUE;
6800 GDBusConnection *conn = NULL;
6802 GVariant *result = NULL;
6803 const gchar *dbus_device_type = NULL;
6804 const gchar *dbus_ret = NULL;
6807 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6809 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6815 result = g_dbus_connection_call_sync(conn,
6816 "org.pulseaudio.Server",
6817 "/org/pulseaudio/StreamManager",
6818 "org.pulseaudio.StreamManager",
6819 "GetCurrentMediaRoutingPath",
6820 g_variant_new("(s)", "out"),
6821 G_VARIANT_TYPE("(ss)"),
6822 G_DBUS_CALL_FLAGS_NONE,
6826 if (!result || err) {
6827 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6833 /* device type is listed in stream-map.json at mmfw-sysconf */
6834 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6836 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6837 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6842 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6843 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6844 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6845 LOGD("audio offload is supportable");
6851 LOGD("audio offload is not supportable");
6855 g_variant_unref(result);
6856 g_object_unref(conn);
6861 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6863 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6864 gint64 position = 0;
6866 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6867 player->pipeline && player->pipeline->mainbin);
6869 MMPLAYER_CMD_LOCK(player);
6870 current_state = MMPLAYER_CURRENT_STATE(player);
6872 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6873 LOGW("getting current position failed in paused");
6875 _mmplayer_unrealize((MMHandleType)player);
6876 _mmplayer_realize((MMHandleType)player);
6878 _mmplayer_set_position((MMHandleType)player, position);
6880 /* async not to be blocked in streaming case */
6881 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6882 if (mm_attrs_commit_all(player->attrs))
6883 LOGE("failed to commit");
6885 _mmplayer_pause((MMHandleType)player);
6887 if (current_state == MM_PLAYER_STATE_PLAYING)
6888 _mmplayer_start((MMHandleType)player);
6889 MMPLAYER_CMD_UNLOCK(player);
6891 LOGD("rebuilding audio pipeline is completed.");
6894 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6896 mmplayer_t *player = (mmplayer_t *)user_data;
6897 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6898 gboolean is_supportable = FALSE;
6900 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6901 LOGW("failed to get device type");
6903 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6905 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6906 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6907 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6908 LOGD("ignore this dev connected info");
6912 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6913 if (player->build_audio_offload == is_supportable) {
6914 LOGD("keep current pipeline without re-building");
6918 /* rebuild pipeline */
6919 LOGD("re-build pipeline - offload: %d", is_supportable);
6920 player->build_audio_offload = FALSE;
6921 __mmplayer_rebuild_audio_pipeline(player);
6927 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6929 unsigned int id = 0;
6931 if (player->audio_device_cb_id != 0) {
6932 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6936 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6937 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6938 LOGD("added device connected cb (%u)", id);
6939 player->audio_device_cb_id = id;
6941 LOGW("failed to add device connected cb");
6949 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6951 gboolean ret = FALSE;
6952 GstElementFactory *factory = NULL;
6955 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6957 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6958 if (!__mmplayer_is_only_mp3_type(player->type))
6961 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6962 LOGD("there is no audio offload sink");
6966 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6967 LOGW("there is no audio device type to support offload");
6971 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6973 LOGW("there is no installed audio offload sink element");
6976 gst_object_unref(factory);
6978 if (__mmplayer_acquire_hw_resource(player,
6979 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6980 LOGE("failed to acquire audio offload decoder resource");
6984 if (!__mmplayer_add_audio_device_connected_cb(player))
6987 if (!__mmplayer_is_audio_offload_device_type(player))
6990 LOGD("audio offload can be built");
6995 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7001 static GstAutoplugSelectResult
7002 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7004 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7006 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7007 int audio_offload = 0;
7009 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7010 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7012 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7013 LOGD("expose audio path to build offload output path");
7014 player->build_audio_offload = TRUE;
7015 /* update codec info */
7016 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7017 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7018 player->audiodec_linked = 1;
7020 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7024 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7026 LOGD("audio codec type: %d", codec_type);
7027 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7028 /* sw codec will be skipped */
7029 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7030 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7031 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7032 ret = GST_AUTOPLUG_SELECT_SKIP;
7036 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7037 /* hw codec will be skipped */
7038 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7039 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7040 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7041 ret = GST_AUTOPLUG_SELECT_SKIP;
7046 /* set stream information */
7047 if (!player->audiodec_linked)
7048 __mmplayer_set_audio_attrs(player, caps);
7050 /* update codec info */
7051 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7052 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7053 player->audiodec_linked = 1;
7055 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7057 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7059 LOGD("video codec type: %d", codec_type);
7060 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7061 /* sw codec is skipped */
7062 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7063 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7064 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7065 ret = GST_AUTOPLUG_SELECT_SKIP;
7069 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7070 /* hw codec is skipped */
7071 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7072 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7073 ret = GST_AUTOPLUG_SELECT_SKIP;
7078 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7079 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7081 /* mark video decoder for acquire */
7082 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7083 LOGW("video decoder resource is already acquired, skip it.");
7084 ret = GST_AUTOPLUG_SELECT_SKIP;
7088 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7089 LOGE("failed to acquire video decoder resource");
7090 ret = GST_AUTOPLUG_SELECT_SKIP;
7093 player->interrupted_by_resource = FALSE;
7096 /* update codec info */
7097 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7098 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7099 player->videodec_linked = 1;
7107 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7108 GstCaps *caps, GstElementFactory *factory, gpointer data)
7110 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7111 mmplayer_t *player = (mmplayer_t *)data;
7113 gchar *factory_name = NULL;
7114 gchar *caps_str = NULL;
7115 const gchar *klass = NULL;
7118 factory_name = GST_OBJECT_NAME(factory);
7119 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7120 caps_str = gst_caps_to_string(caps);
7122 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7124 /* store type string */
7125 if (player->type == NULL) {
7126 player->type = gst_caps_to_string(caps);
7127 __mmplayer_update_content_type_info(player);
7130 /* filtering exclude keyword */
7131 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7132 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7133 LOGW("skipping [%s] by exculde keyword [%s]",
7134 factory_name, player->ini.exclude_element_keyword[idx]);
7136 result = GST_AUTOPLUG_SELECT_SKIP;
7141 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7142 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7143 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7144 factory_name, player->ini.unsupported_codec_keyword[idx]);
7145 result = GST_AUTOPLUG_SELECT_SKIP;
7150 /* exclude webm format */
7151 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7152 * because webm format is not supportable.
7153 * If webm is disabled in "autoplug-continue", there is no state change
7154 * failure or error because the decodebin will expose the pad directly.
7155 * It make MSL invoke _prepare_async_callback.
7156 * So, we need to disable webm format in "autoplug-select" */
7157 if (caps_str && strstr(caps_str, "webm")) {
7158 LOGW("webm is not supported");
7159 result = GST_AUTOPLUG_SELECT_SKIP;
7163 /* check factory class for filtering */
7164 /* NOTE : msl don't need to use image plugins.
7165 * So, those plugins should be skipped for error handling.
7167 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7168 LOGD("skipping [%s] by not required", factory_name);
7169 result = GST_AUTOPLUG_SELECT_SKIP;
7173 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7174 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7175 // TO CHECK : subtitle if needed, add subparse exception.
7176 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7177 result = GST_AUTOPLUG_SELECT_SKIP;
7181 if (g_strrstr(factory_name, "mpegpsdemux")) {
7182 LOGD("skipping PS container - not support");
7183 result = GST_AUTOPLUG_SELECT_SKIP;
7187 if (g_strrstr(factory_name, "mssdemux"))
7188 player->smooth_streaming = TRUE;
7190 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7191 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7194 GstStructure *str = NULL;
7195 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7197 /* don't make video because of not required */
7198 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7199 (!player->set_mode.video_export)) {
7200 LOGD("no need video decoding, expose pad");
7201 result = GST_AUTOPLUG_SELECT_EXPOSE;
7205 /* get w/h for omx state-tune */
7206 /* FIXME: deprecated? */
7207 str = gst_caps_get_structure(caps, 0);
7208 gst_structure_get_int(str, "width", &width);
7211 if (player->v_stream_caps) {
7212 gst_caps_unref(player->v_stream_caps);
7213 player->v_stream_caps = NULL;
7216 player->v_stream_caps = gst_caps_copy(caps);
7217 LOGD("take caps for video state tune");
7218 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7222 if (g_strrstr(klass, "Codec/Decoder")) {
7223 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7224 if (result != GST_AUTOPLUG_SELECT_TRY) {
7225 LOGW("skip add decoder");
7231 MMPLAYER_FREEIF(caps_str);
7237 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7240 //mmplayer_t *player = (mmplayer_t *)data;
7241 GstCaps *caps = NULL;
7243 LOGD("[Decodebin2] pad-removed signal");
7245 caps = gst_pad_query_caps(new_pad, NULL);
7247 LOGW("query caps is NULL");
7251 gchar *caps_str = NULL;
7252 caps_str = gst_caps_to_string(caps);
7254 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7256 MMPLAYER_FREEIF(caps_str);
7257 gst_caps_unref(caps);
7261 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7263 mmplayer_t *player = (mmplayer_t *)data;
7264 GstIterator *iter = NULL;
7265 GValue item = { 0, };
7267 gboolean done = FALSE;
7268 gboolean is_all_drained = TRUE;
7271 MMPLAYER_RETURN_IF_FAIL(player);
7273 LOGD("__mmplayer_gst_decode_drained");
7275 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7276 LOGW("Fail to get cmd lock");
7280 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7281 !__mmplayer_verify_gapless_play_path(player)) {
7282 LOGD("decoding is finished.");
7283 __mmplayer_reset_gapless_state(player);
7284 MMPLAYER_CMD_UNLOCK(player);
7288 player->gapless.reconfigure = TRUE;
7290 /* check decodebin src pads whether they received EOS or not */
7291 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7294 switch (gst_iterator_next(iter, &item)) {
7295 case GST_ITERATOR_OK:
7296 pad = g_value_get_object(&item);
7297 if (pad && !GST_PAD_IS_EOS(pad)) {
7298 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7299 is_all_drained = FALSE;
7302 g_value_reset(&item);
7304 case GST_ITERATOR_RESYNC:
7305 gst_iterator_resync(iter);
7307 case GST_ITERATOR_ERROR:
7308 case GST_ITERATOR_DONE:
7313 g_value_unset(&item);
7314 gst_iterator_free(iter);
7316 if (!is_all_drained) {
7317 LOGD("Wait util the all pads get EOS.");
7318 MMPLAYER_CMD_UNLOCK(player);
7323 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7324 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7326 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7327 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7328 __mmplayer_deactivate_old_path(player);
7329 MMPLAYER_CMD_UNLOCK(player);
7335 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7337 mmplayer_t *player = (mmplayer_t *)data;
7338 const gchar *klass = NULL;
7339 gchar *factory_name = NULL;
7341 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7342 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7344 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7346 if (__mmplayer_add_dump_buffer_probe(player, element))
7347 LOGD("add buffer probe");
7349 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7350 gchar *selected = NULL;
7351 selected = g_strdup(GST_ELEMENT_NAME(element));
7352 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7355 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7356 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7357 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7359 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7360 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7362 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7363 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7364 "max-video-width", player->adaptive_info.limit.width,
7365 "max-video-height", player->adaptive_info.limit.height, NULL);
7367 } else if (g_strrstr(klass, "Demuxer")) {
7368 //LOGD("plugged element is demuxer. take it");
7369 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7370 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7373 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7374 int surface_type = 0;
7376 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7379 // to support trust-zone only
7380 if (g_strrstr(factory_name, "asfdemux")) {
7381 LOGD("set file-location %s", player->profile.uri);
7382 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7383 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7384 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7385 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7386 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7387 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7388 (__mmplayer_is_only_mp3_type(player->type))) {
7389 LOGD("[mpegaudioparse] set streaming pull mode.");
7390 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7392 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7393 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7396 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7397 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7398 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7400 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7401 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7403 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7404 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7405 (MMPLAYER_IS_DASH_STREAMING(player))) {
7406 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7407 _mm_player_streaming_set_multiqueue(player->streamer, element);
7408 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7417 __mmplayer_release_misc(mmplayer_t *player)
7420 bool cur_mode = player->set_mode.rich_audio;
7423 MMPLAYER_RETURN_IF_FAIL(player);
7425 player->video_decoded_cb = NULL;
7426 player->video_decoded_cb_user_param = NULL;
7427 player->video_stream_prerolled = false;
7429 player->audio_decoded_cb = NULL;
7430 player->audio_decoded_cb_user_param = NULL;
7431 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7433 player->audio_stream_changed_cb = NULL;
7434 player->audio_stream_changed_cb_user_param = NULL;
7436 player->sent_bos = FALSE;
7437 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7439 player->seek_state = MMPLAYER_SEEK_NONE;
7441 player->total_bitrate = 0;
7442 player->total_maximum_bitrate = 0;
7444 player->not_found_demuxer = 0;
7446 player->last_position = 0;
7447 player->duration = 0;
7448 player->http_content_size = 0;
7449 player->not_supported_codec = MISSING_PLUGIN_NONE;
7450 player->can_support_codec = FOUND_PLUGIN_NONE;
7451 player->pending_seek.is_pending = false;
7452 player->pending_seek.pos = 0;
7453 player->msg_posted = FALSE;
7454 player->has_many_types = FALSE;
7455 player->is_subtitle_force_drop = FALSE;
7456 player->play_subtitle = FALSE;
7457 player->adjust_subtitle_pos = 0;
7458 player->has_closed_caption = FALSE;
7459 player->set_mode.video_export = false;
7460 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7461 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7463 player->set_mode.rich_audio = cur_mode;
7465 if (player->audio_device_cb_id > 0 &&
7466 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7467 LOGW("failed to remove audio device_connected_callback");
7468 player->audio_device_cb_id = 0;
7470 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7471 player->bitrate[i] = 0;
7472 player->maximum_bitrate[i] = 0;
7475 /* free memory related to audio effect */
7476 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7478 if (player->adaptive_info.var_list) {
7479 g_list_free_full(player->adaptive_info.var_list, g_free);
7480 player->adaptive_info.var_list = NULL;
7483 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7484 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7485 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7487 /* Reset video360 settings to their defaults in case if the pipeline is to be
7490 player->video360_metadata.is_spherical = -1;
7491 player->is_openal_plugin_used = FALSE;
7493 player->is_content_spherical = FALSE;
7494 player->is_video360_enabled = TRUE;
7495 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7496 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7497 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7498 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7499 player->video360_zoom = 1.0f;
7500 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7501 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7503 player->sound.rg_enable = false;
7505 __mmplayer_initialize_video_roi(player);
7510 __mmplayer_release_misc_post(mmplayer_t *player)
7512 char *original_uri = NULL;
7515 /* player->pipeline is already released before. */
7517 MMPLAYER_RETURN_IF_FAIL(player);
7519 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7521 /* clean found audio decoders */
7522 if (player->audio_decoders) {
7523 GList *a_dec = player->audio_decoders;
7524 for (; a_dec; a_dec = g_list_next(a_dec)) {
7525 gchar *name = a_dec->data;
7526 MMPLAYER_FREEIF(name);
7528 g_list_free(player->audio_decoders);
7529 player->audio_decoders = NULL;
7532 /* clean the uri list except original uri */
7533 if (player->uri_info.uri_list) {
7534 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7536 if (player->attrs) {
7537 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7538 LOGD("restore original uri = %s", original_uri);
7540 if (mm_attrs_commit_all(player->attrs))
7541 LOGE("failed to commit the original uri.");
7544 GList *uri_list = player->uri_info.uri_list;
7545 for (; uri_list; uri_list = g_list_next(uri_list)) {
7546 gchar *uri = uri_list->data;
7547 MMPLAYER_FREEIF(uri);
7549 g_list_free(player->uri_info.uri_list);
7550 player->uri_info.uri_list = NULL;
7553 /* clear the audio stream buffer list */
7554 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7556 /* clear the video stream bo list */
7557 __mmplayer_video_stream_destroy_bo_list(player);
7558 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7560 if (player->profile.input_mem.buf) {
7561 free(player->profile.input_mem.buf);
7562 player->profile.input_mem.buf = NULL;
7564 player->profile.input_mem.len = 0;
7565 player->profile.input_mem.offset = 0;
7567 player->uri_info.uri_idx = 0;
7572 __mmplayer_check_subtitle(mmplayer_t *player)
7574 MMHandleType attrs = 0;
7575 char *subtitle_uri = NULL;
7579 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7581 /* get subtitle attribute */
7582 attrs = MMPLAYER_GET_ATTRS(player);
7586 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7587 if (!subtitle_uri || !strlen(subtitle_uri))
7590 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7591 player->is_external_subtitle_present = TRUE;
7599 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7601 MMPLAYER_RETURN_IF_FAIL(player);
7603 if (player->eos_timer) {
7604 LOGD("cancel eos timer");
7605 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7606 player->eos_timer = 0;
7613 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7617 MMPLAYER_RETURN_IF_FAIL(player);
7618 MMPLAYER_RETURN_IF_FAIL(sink);
7620 player->sink_elements = g_list_append(player->sink_elements, sink);
7626 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7630 MMPLAYER_RETURN_IF_FAIL(player);
7631 MMPLAYER_RETURN_IF_FAIL(sink);
7633 player->sink_elements = g_list_remove(player->sink_elements, sink);
7639 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7640 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7642 mmplayer_signal_item_t *item = NULL;
7645 MMPLAYER_RETURN_IF_FAIL(player);
7647 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7648 LOGE("invalid signal type [%d]", type);
7652 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7654 LOGE("cannot connect signal [%s]", signal);
7659 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7660 player->signals[type] = g_list_append(player->signals[type], item);
7666 /* NOTE : be careful with calling this api. please refer to below glib comment
7667 * glib comment : Note that there is a bug in GObject that makes this function much
7668 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7669 * will no longer be called, but, the signal handler is not currently disconnected.
7670 * If the instance is itself being freed at the same time than this doesn't matter,
7671 * since the signal will automatically be removed, but if instance persists,
7672 * then the signal handler will leak. You should not remove the signal yourself
7673 * because in a future versions of GObject, the handler will automatically be
7676 * It's possible to work around this problem in a way that will continue to work
7677 * with future versions of GObject by checking that the signal handler is still
7678 * connected before disconnected it:
7680 * if (g_signal_handler_is_connected(instance, id))
7681 * g_signal_handler_disconnect(instance, id);
7684 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7686 GList *sig_list = NULL;
7687 mmplayer_signal_item_t *item = NULL;
7691 MMPLAYER_RETURN_IF_FAIL(player);
7693 LOGD("release signals type : %d", type);
7695 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7696 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7697 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7698 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7699 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7700 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7704 sig_list = player->signals[type];
7706 for (; sig_list; sig_list = sig_list->next) {
7707 item = sig_list->data;
7709 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7710 if (g_signal_handler_is_connected(item->obj, item->sig))
7711 g_signal_handler_disconnect(item->obj, item->sig);
7714 MMPLAYER_FREEIF(item);
7717 g_list_free(player->signals[type]);
7718 player->signals[type] = NULL;
7726 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7728 mmplayer_t *player = 0;
7729 int prev_display_surface_type = 0;
7730 void *prev_display_overlay = NULL;
7734 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7735 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7737 player = MM_PLAYER_CAST(handle);
7739 /* check video sinkbin is created */
7740 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7741 LOGE("Videosink is already created");
7742 return MM_ERROR_NONE;
7745 LOGD("videosink element is not yet ready");
7747 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7748 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7750 return MM_ERROR_INVALID_ARGUMENT;
7753 /* load previous attributes */
7754 if (player->attrs) {
7755 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7756 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7757 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7758 if (prev_display_surface_type == surface_type) {
7759 LOGD("incoming display surface type is same as previous one, do nothing..");
7761 return MM_ERROR_NONE;
7764 LOGE("failed to load attributes");
7766 return MM_ERROR_PLAYER_INTERNAL;
7769 /* videobin is not created yet, so we just set attributes related to display surface */
7770 LOGD("store display attribute for given surface type(%d)", surface_type);
7771 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7772 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7773 if (mm_attrs_commit_all(player->attrs)) {
7774 LOGE("failed to commit attribute");
7776 return MM_ERROR_PLAYER_INTERNAL;
7780 return MM_ERROR_NONE;
7783 /* Note : if silent is true, then subtitle would not be displayed. :*/
7785 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7787 mmplayer_t *player = (mmplayer_t *)hplayer;
7791 /* check player handle */
7792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7794 player->set_mode.subtitle_off = silent;
7796 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7800 return MM_ERROR_NONE;
7804 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7806 mmplayer_gst_element_t *mainbin = NULL;
7807 mmplayer_gst_element_t *textbin = NULL;
7808 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7809 GstState current_state = GST_STATE_VOID_PENDING;
7810 GstState element_state = GST_STATE_VOID_PENDING;
7811 GstState element_pending_state = GST_STATE_VOID_PENDING;
7813 GstEvent *event = NULL;
7814 int result = MM_ERROR_NONE;
7816 GstClock *curr_clock = NULL;
7817 GstClockTime base_time, start_time, curr_time;
7822 /* check player handle */
7823 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7825 player->pipeline->mainbin &&
7826 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7828 mainbin = player->pipeline->mainbin;
7829 textbin = player->pipeline->textbin;
7831 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7833 // sync clock with current pipeline
7834 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7835 curr_time = gst_clock_get_time(curr_clock);
7837 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7838 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7840 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7841 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7843 if (current_state > GST_STATE_READY) {
7844 // sync state with current pipeline
7845 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7846 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7847 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7849 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7850 if (GST_STATE_CHANGE_FAILURE == ret) {
7851 LOGE("fail to state change.");
7852 result = MM_ERROR_PLAYER_INTERNAL;
7856 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7857 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7860 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7861 gst_object_unref(curr_clock);
7864 // seek to current position
7865 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7866 result = MM_ERROR_PLAYER_INVALID_STATE;
7867 LOGE("gst_element_query_position failed, invalid state");
7871 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7872 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);
7874 _mmplayer_gst_send_event_to_sink(player, event);
7876 result = MM_ERROR_PLAYER_INTERNAL;
7877 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7881 /* sync state with current pipeline */
7882 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7883 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7884 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7886 return MM_ERROR_NONE;
7889 /* release text pipeline resource */
7890 player->textsink_linked = 0;
7892 /* release signal */
7893 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7895 /* release textbin with it's childs */
7896 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7897 MMPLAYER_FREEIF(player->pipeline->textbin);
7898 player->pipeline->textbin = NULL;
7900 /* release subtitle elem */
7901 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7902 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7908 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7910 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7911 GstState current_state = GST_STATE_VOID_PENDING;
7913 MMHandleType attrs = 0;
7914 mmplayer_gst_element_t *mainbin = NULL;
7915 mmplayer_gst_element_t *textbin = NULL;
7917 gchar *subtitle_uri = NULL;
7918 int result = MM_ERROR_NONE;
7919 const gchar *charset = NULL;
7923 /* check player handle */
7924 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7926 player->pipeline->mainbin &&
7927 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7928 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7930 mainbin = player->pipeline->mainbin;
7931 textbin = player->pipeline->textbin;
7933 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7934 if (current_state < GST_STATE_READY) {
7935 result = MM_ERROR_PLAYER_INVALID_STATE;
7936 LOGE("Pipeline is not in proper state");
7940 attrs = MMPLAYER_GET_ATTRS(player);
7942 LOGE("cannot get content attribute");
7943 result = MM_ERROR_PLAYER_INTERNAL;
7947 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7948 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7949 LOGE("subtitle uri is not proper filepath");
7950 result = MM_ERROR_PLAYER_INVALID_URI;
7954 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7955 LOGE("failed to get storage info of subtitle path");
7956 result = MM_ERROR_PLAYER_INVALID_URI;
7960 LOGD("old subtitle file path is [%s]", subtitle_uri);
7961 LOGD("new subtitle file path is [%s]", filepath);
7963 if (!strcmp(filepath, subtitle_uri)) {
7964 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7967 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7968 if (mm_attrs_commit_all(player->attrs)) {
7969 LOGE("failed to commit.");
7974 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7975 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7976 player->subtitle_language_list = NULL;
7977 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7979 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7980 if (ret != GST_STATE_CHANGE_SUCCESS) {
7981 LOGE("failed to change state of textbin to READY");
7982 result = MM_ERROR_PLAYER_INTERNAL;
7986 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7987 if (ret != GST_STATE_CHANGE_SUCCESS) {
7988 LOGE("failed to change state of subparse to READY");
7989 result = MM_ERROR_PLAYER_INTERNAL;
7993 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7994 if (ret != GST_STATE_CHANGE_SUCCESS) {
7995 LOGE("failed to change state of filesrc to READY");
7996 result = MM_ERROR_PLAYER_INTERNAL;
8000 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8002 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8004 charset = _mmplayer_get_charset(filepath);
8006 LOGD("detected charset is %s", charset);
8007 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8010 result = _mmplayer_sync_subtitle_pipeline(player);
8017 /* API to switch between external subtitles */
8019 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8021 int result = MM_ERROR_NONE;
8022 mmplayer_t *player = (mmplayer_t *)hplayer;
8027 /* check player handle */
8028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8030 /* filepath can be null in idle state */
8032 /* check file path */
8033 if ((path = strstr(filepath, "file://")))
8034 result = _mmplayer_exist_file_path(path + 7);
8036 result = _mmplayer_exist_file_path(filepath);
8038 if (result != MM_ERROR_NONE) {
8039 LOGE("invalid subtitle path 0x%X", result);
8040 return result; /* file not found or permission denied */
8044 if (!player->pipeline) {
8046 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8047 if (mm_attrs_commit_all(player->attrs)) {
8048 LOGE("failed to commit"); /* subtitle path will not be created */
8049 return MM_ERROR_PLAYER_INTERNAL;
8052 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8053 /* check filepath */
8054 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8056 if (!__mmplayer_check_subtitle(player)) {
8057 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8058 if (mm_attrs_commit_all(player->attrs)) {
8059 LOGE("failed to commit");
8060 return MM_ERROR_PLAYER_INTERNAL;
8063 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8064 LOGE("fail to create text pipeline");
8065 return MM_ERROR_PLAYER_INTERNAL;
8068 result = _mmplayer_sync_subtitle_pipeline(player);
8070 result = __mmplayer_change_external_subtitle_language(player, filepath);
8073 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8074 player->is_external_subtitle_added_now = TRUE;
8076 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8077 if (!player->subtitle_language_list) {
8078 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8079 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8080 LOGW("subtitle language list is not updated yet");
8082 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8090 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8092 int result = MM_ERROR_NONE;
8093 gchar *change_pad_name = NULL;
8094 GstPad *sinkpad = NULL;
8095 mmplayer_gst_element_t *mainbin = NULL;
8096 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8097 GstCaps *caps = NULL;
8098 gint total_track_num = 0;
8102 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8103 MM_ERROR_PLAYER_NOT_INITIALIZED);
8105 LOGD("Change Track(%d) to %d", type, index);
8107 mainbin = player->pipeline->mainbin;
8109 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8110 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8111 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8112 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8114 /* Changing Video Track is not supported. */
8115 LOGE("Track Type Error");
8119 if (mainbin[elem_idx].gst == NULL) {
8120 result = MM_ERROR_PLAYER_NO_OP;
8121 LOGD("Req track doesn't exist");
8125 total_track_num = player->selector[type].total_track_num;
8126 if (total_track_num <= 0) {
8127 result = MM_ERROR_PLAYER_NO_OP;
8128 LOGD("Language list is not available");
8132 if ((index < 0) || (index >= total_track_num)) {
8133 result = MM_ERROR_INVALID_ARGUMENT;
8134 LOGD("Not a proper index : %d", index);
8138 /*To get the new pad from the selector*/
8139 change_pad_name = g_strdup_printf("sink_%u", index);
8140 if (change_pad_name == NULL) {
8141 result = MM_ERROR_PLAYER_INTERNAL;
8142 LOGD("Pad does not exists");
8146 LOGD("new active pad name: %s", change_pad_name);
8148 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8149 if (sinkpad == NULL) {
8150 LOGD("sinkpad is NULL");
8151 result = MM_ERROR_PLAYER_INTERNAL;
8155 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8156 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8158 caps = gst_pad_get_current_caps(sinkpad);
8159 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8162 gst_object_unref(sinkpad);
8164 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8165 __mmplayer_set_audio_attrs(player, caps);
8168 MMPLAYER_FREEIF(change_pad_name);
8173 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8175 int result = MM_ERROR_NONE;
8176 mmplayer_t *player = NULL;
8177 mmplayer_gst_element_t *mainbin = NULL;
8179 gint current_active_index = 0;
8181 GstState current_state = GST_STATE_VOID_PENDING;
8182 GstEvent *event = NULL;
8187 player = (mmplayer_t *)hplayer;
8188 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8190 if (!player->pipeline) {
8191 LOGE("Track %d pre setting -> %d", type, index);
8193 player->selector[type].active_pad_index = index;
8197 mainbin = player->pipeline->mainbin;
8199 current_active_index = player->selector[type].active_pad_index;
8201 /*If index is same as running index no need to change the pad*/
8202 if (current_active_index == index)
8205 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8206 result = MM_ERROR_PLAYER_INVALID_STATE;
8210 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8211 if (current_state < GST_STATE_PAUSED) {
8212 result = MM_ERROR_PLAYER_INVALID_STATE;
8213 LOGW("Pipeline not in porper state");
8217 result = __mmplayer_change_selector_pad(player, type, index);
8218 if (result != MM_ERROR_NONE) {
8219 LOGE("change selector pad error");
8223 player->selector[type].active_pad_index = index;
8225 if (current_state == GST_STATE_PLAYING) {
8226 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8227 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8228 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8230 _mmplayer_gst_send_event_to_sink(player, event);
8232 result = MM_ERROR_PLAYER_INTERNAL;
8242 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8244 mmplayer_t *player = (mmplayer_t *)hplayer;
8248 /* check player handle */
8249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8251 *silent = player->set_mode.subtitle_off;
8253 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8257 return MM_ERROR_NONE;
8261 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8263 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8264 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8266 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8267 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8271 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8272 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8273 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8274 mmplayer_dump_t *dump_s;
8275 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8276 if (dump_s == NULL) {
8277 LOGE("malloc fail");
8281 dump_s->dump_element_file = NULL;
8282 dump_s->dump_pad = NULL;
8283 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8285 if (dump_s->dump_pad) {
8286 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8287 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]);
8288 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8289 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);
8290 /* add list for removed buffer probe and close FILE */
8291 player->dump_list = g_list_append(player->dump_list, dump_s);
8292 LOGD("%s sink pad added buffer probe for dump", factory_name);
8295 MMPLAYER_FREEIF(dump_s);
8296 LOGE("failed to get %s sink pad added", factory_name);
8303 static GstPadProbeReturn
8304 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8306 FILE *dump_data = (FILE *)u_data;
8308 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8309 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8311 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8313 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8315 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8317 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8319 gst_buffer_unmap(buffer, &probe_info);
8321 return GST_PAD_PROBE_OK;
8325 __mmplayer_release_dump_list(GList *dump_list)
8327 GList *d_list = dump_list;
8332 for (; d_list; d_list = g_list_next(d_list)) {
8333 mmplayer_dump_t *dump_s = d_list->data;
8334 if (dump_s->dump_pad) {
8335 if (dump_s->probe_handle_id)
8336 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8337 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8339 if (dump_s->dump_element_file) {
8340 fclose(dump_s->dump_element_file);
8341 dump_s->dump_element_file = NULL;
8343 MMPLAYER_FREEIF(dump_s);
8345 g_list_free(dump_list);
8350 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8352 mmplayer_t *player = (mmplayer_t *)hplayer;
8356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8357 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8359 *exist = (bool)player->has_closed_caption;
8363 return MM_ERROR_NONE;
8367 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8371 // LOGD("unref internal gst buffer %p", buffer);
8372 gst_buffer_unref((GstBuffer *)buffer);
8379 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8381 mmplayer_t *player = (mmplayer_t *)hplayer;
8385 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8386 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8388 if (MMPLAYER_IS_STREAMING(player))
8389 *timeout = (int)player->ini.live_state_change_timeout;
8391 *timeout = (int)player->ini.localplayback_state_change_timeout;
8393 LOGD("timeout = %d", *timeout);
8396 return MM_ERROR_NONE;
8400 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8404 MMPLAYER_RETURN_IF_FAIL(player);
8406 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8408 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8409 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8410 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8411 player->storage_info[i].id = -1;
8412 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8414 if (path_type != MMPLAYER_PATH_MAX)
8423 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8425 int ret = MM_ERROR_NONE;
8426 mmplayer_t *player = (mmplayer_t *)hplayer;
8427 MMMessageParamType msg_param = {0, };
8430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8432 LOGW("state changed storage %d:%d", id, state);
8434 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8435 return MM_ERROR_NONE;
8437 /* FIXME: text path should be handled seperately. */
8438 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8439 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8440 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8441 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8442 LOGW("external storage is removed");
8444 if (player->msg_posted == FALSE) {
8445 memset(&msg_param, 0, sizeof(MMMessageParamType));
8446 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8447 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8448 player->msg_posted = TRUE;
8451 /* unrealize the player */
8452 ret = _mmplayer_unrealize(hplayer);
8453 if (ret != MM_ERROR_NONE)
8454 LOGE("failed to unrealize");
8462 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8464 int ret = MM_ERROR_NONE;
8465 mmplayer_t *player = (mmplayer_t *)hplayer;
8466 int idx = 0, total = 0;
8467 gchar *result = NULL, *tmp = NULL;
8470 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8471 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8473 total = *num = g_list_length(player->adaptive_info.var_list);
8475 LOGW("There is no stream variant info.");
8479 result = g_strdup("");
8480 for (idx = 0 ; idx < total ; idx++) {
8481 stream_variant_t *v_data = NULL;
8482 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8485 gchar data[64] = {0};
8486 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8488 tmp = g_strconcat(result, data, NULL);
8492 LOGW("There is no variant data in %d", idx);
8497 *var_info = (char *)result;
8499 LOGD("variant info %d:%s", *num, *var_info);
8505 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8507 int ret = MM_ERROR_NONE;
8508 mmplayer_t *player = (mmplayer_t *)hplayer;
8511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8513 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8515 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8516 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8517 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8519 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8520 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8521 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8522 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8524 /* FIXME: seek to current position for applying new variant limitation */
8533 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8535 int ret = MM_ERROR_NONE;
8536 mmplayer_t *player = (mmplayer_t *)hplayer;
8539 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8540 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8542 *bandwidth = player->adaptive_info.limit.bandwidth;
8543 *width = player->adaptive_info.limit.width;
8544 *height = player->adaptive_info.limit.height;
8546 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8553 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8555 int ret = MM_ERROR_NONE;
8556 mmplayer_t *player = (mmplayer_t *)hplayer;
8559 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8560 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8561 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8563 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8565 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8566 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8567 else /* live case */
8568 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8570 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8577 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8579 #define IDX_FIRST_SW_CODEC 0
8580 mmplayer_t *player = (mmplayer_t *)hplayer;
8581 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8582 MMHandleType attrs = 0;
8585 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8587 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8588 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8589 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8591 switch (stream_type) {
8592 case MM_PLAYER_STREAM_TYPE_AUDIO:
8593 /* to support audio codec selection, codec info have to be added in ini file as below.
8594 audio codec element hw = xxxx
8595 audio codec element sw = avdec */
8596 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8597 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8598 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8599 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8600 LOGE("There is no audio codec info for codec_type %d", codec_type);
8601 return MM_ERROR_PLAYER_NO_OP;
8604 case MM_PLAYER_STREAM_TYPE_VIDEO:
8605 /* to support video codec selection, codec info have to be added in ini file as below.
8606 video codec element hw = omx
8607 video codec element sw = avdec */
8608 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8609 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8610 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8611 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8612 LOGE("There is no video codec info for codec_type %d", codec_type);
8613 return MM_ERROR_PLAYER_NO_OP;
8617 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8618 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8622 LOGD("update %s codec_type to %d", attr_name, codec_type);
8624 attrs = MMPLAYER_GET_ATTRS(player);
8625 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8627 if (mm_attrs_commit_all(player->attrs)) {
8628 LOGE("failed to commit codec_type attributes");
8629 return MM_ERROR_PLAYER_INTERNAL;
8633 return MM_ERROR_NONE;
8637 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8639 mmplayer_t *player = (mmplayer_t *)hplayer;
8640 GstElement *rg_vol_element = NULL;
8644 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8646 player->sound.rg_enable = enabled;
8648 /* just hold rgvolume enable value if pipeline is not ready */
8649 if (!player->pipeline || !player->pipeline->audiobin) {
8650 LOGD("pipeline is not ready. holding rgvolume enable value");
8651 return MM_ERROR_NONE;
8654 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8656 if (!rg_vol_element) {
8657 LOGD("rgvolume element is not created");
8658 return MM_ERROR_PLAYER_INTERNAL;
8662 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8664 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8668 return MM_ERROR_NONE;
8672 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8674 mmplayer_t *player = (mmplayer_t *)hplayer;
8675 GstElement *rg_vol_element = NULL;
8676 gboolean enable = FALSE;
8680 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8681 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8683 /* just hold enable_rg value if pipeline is not ready */
8684 if (!player->pipeline || !player->pipeline->audiobin) {
8685 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8686 *enabled = player->sound.rg_enable;
8687 return MM_ERROR_NONE;
8690 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8692 if (!rg_vol_element) {
8693 LOGD("rgvolume element is not created");
8694 return MM_ERROR_PLAYER_INTERNAL;
8697 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8698 *enabled = (bool)enable;
8702 return MM_ERROR_NONE;
8706 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8708 mmplayer_t *player = (mmplayer_t *)hplayer;
8709 MMHandleType attrs = 0;
8710 void *handle = NULL;
8711 int ret = MM_ERROR_NONE;
8715 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8717 attrs = MMPLAYER_GET_ATTRS(player);
8718 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8720 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8722 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8723 return MM_ERROR_PLAYER_INTERNAL;
8726 player->video_roi.scale_x = scale_x;
8727 player->video_roi.scale_y = scale_y;
8728 player->video_roi.scale_width = scale_width;
8729 player->video_roi.scale_height = scale_height;
8731 /* check video sinkbin is created */
8732 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8733 return MM_ERROR_NONE;
8735 if (!gst_video_overlay_set_video_roi_area(
8736 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8737 scale_x, scale_y, scale_width, scale_height))
8738 ret = MM_ERROR_PLAYER_INTERNAL;
8740 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8741 scale_x, scale_y, scale_width, scale_height);
8749 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8751 mmplayer_t *player = (mmplayer_t *)hplayer;
8752 int ret = MM_ERROR_NONE;
8756 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8757 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8759 *scale_x = player->video_roi.scale_x;
8760 *scale_y = player->video_roi.scale_y;
8761 *scale_width = player->video_roi.scale_width;
8762 *scale_height = player->video_roi.scale_height;
8764 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8765 *scale_x, *scale_y, *scale_width, *scale_height);
8771 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8773 mmplayer_t* player = (mmplayer_t*)hplayer;
8777 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8779 player->client_pid = pid;
8781 LOGD("client pid[%d] %p", pid, player);
8785 return MM_ERROR_NONE;
8789 __mmplayer_update_duration_value(mmplayer_t *player)
8791 gboolean ret = FALSE;
8792 gint64 dur_nsec = 0;
8793 LOGD("try to update duration");
8795 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8796 player->duration = dur_nsec;
8797 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8801 if (player->duration < 0) {
8802 LOGW("duration is Non-Initialized !!!");
8803 player->duration = 0;
8806 /* update streaming service type */
8807 player->streaming_type = _mmplayer_get_stream_service_type(player);
8809 /* check duration is OK */
8810 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8811 /* FIXIT : find another way to get duration here. */
8812 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8818 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8820 /* update audio params
8821 NOTE : We need original audio params and it can be only obtained from src pad of audio
8822 decoder. Below code only valid when we are not using 'resampler' just before
8823 'audioconverter'. */
8824 GstCaps *caps_a = NULL;
8826 gint samplerate = 0, channels = 0;
8827 GstStructure *p = NULL;
8828 GstElement *aconv = NULL;
8830 LOGD("try to update audio attrs");
8832 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8834 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8835 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8836 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8837 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8839 LOGE("there is no audio converter");
8843 pad = gst_element_get_static_pad(aconv, "sink");
8846 LOGW("failed to get pad from audio converter");
8850 caps_a = gst_pad_get_current_caps(pad);
8852 LOGW("not ready to get audio caps");
8853 gst_object_unref(pad);
8857 p = gst_caps_get_structure(caps_a, 0);
8859 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8861 gst_structure_get_int(p, "rate", &samplerate);
8862 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8864 gst_structure_get_int(p, "channels", &channels);
8865 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8867 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8869 gst_caps_unref(caps_a);
8870 gst_object_unref(pad);
8876 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8878 LOGD("try to update video attrs");
8880 GstCaps *caps_v = NULL;
8884 GstStructure *p = NULL;
8886 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8887 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8889 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8891 LOGD("no videosink sink pad");
8895 caps_v = gst_pad_get_current_caps(pad);
8896 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8897 if (!caps_v && player->v_stream_caps) {
8898 caps_v = player->v_stream_caps;
8899 gst_caps_ref(caps_v);
8903 LOGD("no negitiated caps from videosink");
8904 gst_object_unref(pad);
8908 p = gst_caps_get_structure(caps_v, 0);
8909 gst_structure_get_int(p, "width", &width);
8910 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8912 gst_structure_get_int(p, "height", &height);
8913 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8915 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8917 SECURE_LOGD("width : %d height : %d", width, height);
8919 gst_caps_unref(caps_v);
8920 gst_object_unref(pad);
8923 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8924 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8931 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8933 gboolean ret = FALSE;
8934 guint64 data_size = 0;
8938 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8939 if (!player->duration)
8942 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8943 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8944 if (stat(path, &sb) == 0)
8945 data_size = (guint64)sb.st_size;
8947 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8948 data_size = player->http_content_size;
8951 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8954 guint64 bitrate = 0;
8955 guint64 msec_dur = 0;
8957 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8959 bitrate = data_size * 8 * 1000 / msec_dur;
8960 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8961 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8965 LOGD("player duration is less than 0");
8969 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8970 if (player->total_bitrate) {
8971 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8980 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8982 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8983 data->uri_type = uri_type;
8987 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8989 int ret = MM_ERROR_PLAYER_INVALID_URI;
8991 char *buffer = NULL;
8992 char *seperator = strchr(path, ',');
8993 char ext[100] = {0,}, size[100] = {0,};
8996 if ((buffer = strstr(path, "ext="))) {
8997 buffer += strlen("ext=");
8999 if (strlen(buffer)) {
9000 strncpy(ext, buffer, 99);
9002 if ((seperator = strchr(ext, ','))
9003 || (seperator = strchr(ext, ' '))
9004 || (seperator = strchr(ext, '\0'))) {
9005 seperator[0] = '\0';
9010 if ((buffer = strstr(path, "size="))) {
9011 buffer += strlen("size=");
9013 if (strlen(buffer) > 0) {
9014 strncpy(size, buffer, 99);
9016 if ((seperator = strchr(size, ','))
9017 || (seperator = strchr(size, ' '))
9018 || (seperator = strchr(size, '\0'))) {
9019 seperator[0] = '\0';
9022 mem_size = atoi(size);
9027 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9029 if (mem_size && param) {
9030 if (data->input_mem.buf)
9031 free(data->input_mem.buf);
9032 data->input_mem.buf = malloc(mem_size);
9034 if (data->input_mem.buf) {
9035 memcpy(data->input_mem.buf, param, mem_size);
9036 data->input_mem.len = mem_size;
9037 ret = MM_ERROR_NONE;
9039 LOGE("failed to alloc mem %d", mem_size);
9040 ret = MM_ERROR_PLAYER_INTERNAL;
9043 data->input_mem.offset = 0;
9044 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9051 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9053 gchar *location = NULL;
9056 int ret = MM_ERROR_NONE;
9058 if ((path = strstr(uri, "file://"))) {
9059 location = g_filename_from_uri(uri, NULL, &err);
9060 if (!location || (err != NULL)) {
9061 LOGE("Invalid URI '%s' for filesrc: %s", path,
9062 (err != NULL) ? err->message : "unknown error");
9066 MMPLAYER_FREEIF(location);
9068 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9069 return MM_ERROR_PLAYER_INVALID_URI;
9071 LOGD("path from uri: %s", location);
9074 path = (location != NULL) ? (location) : ((char *)uri);
9077 ret = _mmplayer_exist_file_path(path);
9079 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9080 if (ret == MM_ERROR_NONE) {
9081 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9082 if (_mmplayer_is_sdp_file(path)) {
9083 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9084 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9086 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9088 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9089 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9091 LOGE("invalid uri, could not play..");
9092 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9095 MMPLAYER_FREEIF(location);
9100 static mmplayer_video_decoded_data_info_t *
9101 __mmplayer_create_stream_from_pad(GstPad *pad)
9103 GstCaps *caps = NULL;
9104 GstStructure *structure = NULL;
9105 unsigned int fourcc = 0;
9106 const gchar *string_format = NULL;
9107 mmplayer_video_decoded_data_info_t *stream = NULL;
9109 MMPixelFormatType format;
9112 caps = gst_pad_get_current_caps(pad);
9114 LOGE("Caps is NULL.");
9118 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9119 structure = gst_caps_get_structure(caps, 0);
9120 gst_structure_get_int(structure, "width", &width);
9121 gst_structure_get_int(structure, "height", &height);
9122 string_format = gst_structure_get_string(structure, "format");
9125 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9126 format = _mmplayer_get_pixtype(fourcc);
9127 gst_video_info_from_caps(&info, caps);
9128 gst_caps_unref(caps);
9131 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9132 LOGE("Wrong condition!!");
9136 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9138 LOGE("failed to alloc mem for video data");
9142 stream->width = width;
9143 stream->height = height;
9144 stream->format = format;
9145 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9151 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9153 unsigned int pitch = 0;
9154 unsigned int size = 0;
9156 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9159 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9160 bo = gst_tizen_memory_get_bos(mem, index);
9162 stream->bo[index] = tbm_bo_ref(bo);
9164 LOGE("failed to get bo for index %d", index);
9167 for (index = 0; index < stream->plane_num; index++) {
9168 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9169 stream->stride[index] = pitch;
9171 stream->elevation[index] = size / pitch;
9173 stream->elevation[index] = stream->height;
9178 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9180 if (stream->format == MM_PIXEL_FORMAT_I420) {
9181 int ret = TBM_SURFACE_ERROR_NONE;
9182 tbm_surface_h surface;
9183 tbm_surface_info_s info;
9185 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9187 ret = tbm_surface_get_info(surface, &info);
9188 if (ret != TBM_SURFACE_ERROR_NONE) {
9189 tbm_surface_destroy(surface);
9193 tbm_surface_destroy(surface);
9194 stream->stride[0] = info.planes[0].stride;
9195 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9196 stream->stride[1] = info.planes[1].stride;
9197 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9198 stream->stride[2] = info.planes[2].stride;
9199 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9200 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9201 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9202 stream->stride[0] = stream->width * 4;
9203 stream->elevation[0] = stream->height;
9204 stream->bo_size = stream->stride[0] * stream->height;
9206 LOGE("Not support format %d", stream->format);
9214 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9216 tbm_bo_handle thandle;
9218 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9219 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9220 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9224 unsigned char *src = NULL;
9225 unsigned char *dest = NULL;
9226 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9228 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9230 LOGE("fail to gst_memory_map");
9234 if (!mapinfo.data) {
9235 LOGE("data pointer is wrong");
9239 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9240 if (!stream->bo[0]) {
9241 LOGE("Fail to tbm_bo_alloc!!");
9245 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9247 LOGE("thandle pointer is wrong");
9251 if (stream->format == MM_PIXEL_FORMAT_I420) {
9252 src_stride[0] = GST_ROUND_UP_4(stream->width);
9253 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9254 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9255 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9258 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9259 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9261 for (i = 0; i < 3; i++) {
9262 src = mapinfo.data + src_offset[i];
9263 dest = thandle.ptr + dest_offset[i];
9268 for (j = 0; j < stream->height >> k; j++) {
9269 memcpy(dest, src, stream->width>>k);
9270 src += src_stride[i];
9271 dest += stream->stride[i];
9274 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9275 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9277 LOGE("Not support format %d", stream->format);
9281 tbm_bo_unmap(stream->bo[0]);
9282 gst_memory_unmap(mem, &mapinfo);
9288 tbm_bo_unmap(stream->bo[0]);
9291 gst_memory_unmap(mem, &mapinfo);
9297 __mmplayer_set_pause_state(mmplayer_t *player)
9299 if (player->sent_bos)
9302 /* rtsp case, get content attrs by GstMessage */
9303 if (MMPLAYER_IS_RTSP_STREAMING(player))
9306 /* it's first time to update all content attrs. */
9307 _mmplayer_update_content_attrs(player, ATTR_ALL);
9311 __mmplayer_set_playing_state(mmplayer_t *player)
9313 gchar *audio_codec = NULL;
9315 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9316 /* initialize because auto resume is done well. */
9317 player->resumed_by_rewind = FALSE;
9318 player->playback_rate = 1.0;
9321 if (player->sent_bos)
9324 /* try to get content metadata */
9326 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9327 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9328 * legacy mmfw-player api
9330 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9332 if ((player->cmd == MMPLAYER_COMMAND_START)
9333 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9334 __mmplayer_handle_missed_plugin(player);
9337 /* check audio codec field is set or not
9338 * we can get it from typefinder or codec's caps.
9340 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9342 /* The codec format can't be sent for audio only case like amr, mid etc.
9343 * Because, parser don't make related TAG.
9344 * So, if it's not set yet, fill it with found data.
9347 if (g_strrstr(player->type, "audio/midi"))
9348 audio_codec = "MIDI";
9349 else if (g_strrstr(player->type, "audio/x-amr"))
9350 audio_codec = "AMR";
9351 else if (g_strrstr(player->type, "audio/mpeg")
9352 && !g_strrstr(player->type, "mpegversion=(int)1"))
9353 audio_codec = "AAC";
9355 audio_codec = "unknown";
9357 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9359 if (mm_attrs_commit_all(player->attrs))
9360 LOGE("failed to update attributes");
9362 LOGD("set audio codec type with caps");